Skip to content

Commit 8ff5f88

Browse files
authored
Fix five issues found running the agent examples (#495)
1 parent 46bffcc commit 8ff5f88

10 files changed

Lines changed: 130 additions & 95 deletions

‎examples/agentic_workflows/mcp_weather_agent.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def create_mcp_agent_workflow(executor: WorkflowExecutor, mcp_server: str) -> Co
9090
plan_task = LlmChatComplete(
9191
task_ref_name="plan_action",
9292
llm_provider="anthropic",
93-
model="claude-sonnet-4-20250514",
93+
model="claude-sonnet-5",
9494
messages=[
9595
ChatMessage(
9696
role="system",

‎examples/agents/56_rag_agent.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"text": (
6666
"Agent Configuration. Agents are defined with a name, model, instructions, "
6767
"and tools. The model field uses the format 'provider/model_name', e.g. "
68-
"'openai/gpt-4o' or 'anthropic/claude-sonnet-4-20250514'. Instructions can be "
68+
"'openai/gpt-4o' or 'anthropic/claude-sonnet-5'. Instructions can be "
6969
"a string or a PromptTemplate referencing a stored prompt. Tools can be "
7070
"@tool-decorated Python functions, http_tool for REST APIs, mcp_tool for "
7171
"MCP servers, or agent_tool to wrap another agent as a callable tool. "

‎examples/agents/59_coding_agent.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
qa_tester = Agent(
2828
name="qa_tester",
29-
model="anthropic/claude-sonnet-4-20250514",
29+
model="anthropic/claude-sonnet-4-6",
3030
instructions=(
3131
"You are a meticulous QA engineer. Review the code written by the "
3232
"coder for correctness, edge cases, and bugs. Write and execute test "
@@ -45,7 +45,7 @@
4545

4646
coder = Agent(
4747
name="coder",
48-
model="anthropic/claude-sonnet-4-20250514",
48+
model="anthropic/claude-sonnet-4-6",
4949
instructions=(
5050
"You are an expert Python developer. Write clean, well-structured "
5151
"Python code to solve the given problem. Always execute your code to "

‎examples/agents/60_github_coding_agent.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def create_pull_request(title: str, body: str, issue_number: int = 0) -> str:
249249

250250
github_agent = Agent(
251251
name="github_agent",
252-
model="anthropic/claude-sonnet-4-20250514",
252+
model="anthropic/claude-sonnet-4-6",
253253
instructions=(
254254
"You are a GitHub operations specialist. You handle all git and "
255255
"GitHub CLI interactions.\n\n"
@@ -282,7 +282,7 @@ def create_pull_request(title: str, body: str, issue_number: int = 0) -> str:
282282

283283
coder = Agent(
284284
name="coder",
285-
model="anthropic/claude-sonnet-4-20250514",
285+
model="anthropic/claude-sonnet-4-6",
286286
instructions=(
287287
"You are an expert developer. Write clean, well-structured code.\n\n"
288288
"WHEN YOU RECEIVE A TASK:\n"
@@ -311,7 +311,7 @@ def create_pull_request(title: str, body: str, issue_number: int = 0) -> str:
311311

312312
qa_tester = Agent(
313313
name="qa_tester",
314-
model="anthropic/claude-sonnet-4-20250514",
314+
model="anthropic/claude-sonnet-4-6",
315315
instructions=(
316316
"You are a meticulous QA engineer. Review the code written by the "
317317
"coder for correctness, edge cases, and bugs.\n\n"
@@ -340,7 +340,7 @@ def create_pull_request(title: str, body: str, issue_number: int = 0) -> str:
340340

341341
coding_team = Agent(
342342
name="coding_team",
343-
model="anthropic/claude-sonnet-4-20250514",
343+
model="anthropic/claude-sonnet-4-6",
344344
instructions=(
345345
"You are a coding team coordinator. Delegate the incoming request "
346346
"to github_agent to get started — it will pick an issue and set "

‎examples/agents/60a_github_coding_agent_simple.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
github_agent = Agent(
4343
name="github_agent",
44-
model="anthropic/claude-sonnet-4-20250514",
44+
model="anthropic/claude-sonnet-4-6",
4545
instructions=(
4646
"You are a GitHub operations specialist. You handle all git and "
4747
"GitHub CLI interactions.\n\n"
@@ -77,7 +77,7 @@
7777

7878
coder = Agent(
7979
name="coder",
80-
model="anthropic/claude-sonnet-4-20250514",
80+
model="anthropic/claude-sonnet-4-6",
8181
instructions=(
8282
"You are an expert developer. You write clean, well-structured code.\n\n"
8383
f"The repo is cloned at {WORK_DIR}.\n\n"
@@ -109,7 +109,7 @@
109109

110110
qa_tester = Agent(
111111
name="qa_tester",
112-
model="anthropic/claude-sonnet-4-20250514",
112+
model="anthropic/claude-sonnet-4-6",
113113
instructions=(
114114
"You are a meticulous QA engineer. Review the code written by the "
115115
"coder for correctness, edge cases, and bugs.\n\n"
@@ -134,7 +134,7 @@
134134

135135
coding_team = Agent(
136136
name="coding_team",
137-
model="anthropic/claude-sonnet-4-20250514",
137+
model="anthropic/claude-sonnet-4-6",
138138
instructions=(
139139
"You are a coding team coordinator. Delegate the incoming request "
140140
"to github_agent to get started — it will pick an issue and set "

‎examples/agents/74_cli_error_output.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
with AgentRuntime() as rt:
3737
result = rt.run(agent, prompt)
3838
result.print_result()
39-
output = result.output or ""
39+
output = str(result.output)
4040

4141
# Verify the agent saw the error output
4242
assert "No such file or directory" in output or "nonexistent" in output, (

‎examples/agents/adk/35_rag_agent.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"text": (
7777
"Agent Configuration. Agents are defined with a name, model, instructions, "
7878
"and tools. The model field uses the format 'provider/model_name', e.g. "
79-
"'openai/gpt-4o' or 'anthropic/claude-sonnet-4-20250514'. Instructions can be "
79+
"'openai/gpt-4o' or 'anthropic/claude-sonnet-5'. Instructions can be "
8080
"a string or a PromptTemplate referencing a stored prompt. Tools can be "
8181
"@tool-decorated Python functions, http_tool for REST APIs, mcp_tool for "
8282
"MCP servers, or agent_tool to wrap another agent as a callable tool. "

‎examples/agents/langgraph/46_crash_and_resume.py‎

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -104,80 +104,80 @@ def generate_report(analysis: str) -> str:
104104
)
105105

106106

107-
# -- Phase 1: Deploy, start, serve briefly, then crash --------------------
108-
109-
print("=" * 60)
110-
print("Phase 1: Deploy + start, then simulate crash")
111-
print("=" * 60)
112-
113-
with AgentRuntime() as runtime:
114-
# Deploy the workflow definition (in production, do this once in CI/CD)
115-
runtime.deploy(graph)
116-
print("Agent deployed to server.")
117-
118-
# Start an execution by name — the agent is already deployed on the server,
119-
# so we only need to send the name and prompt (not the full graph object).
120-
handle = runtime.start(
121-
"sales_analyst",
122-
"Fetch the Q4 2025 sales data, run a full trend analysis on it, "
123-
"then generate an executive summary report. "
124-
"Call each tool in sequence — do not skip any step.",
125-
)
126-
print(f"Execution started: {handle.execution_id}")
127-
128-
# Save execution_id so we can check status later
129-
with open(SESSION_FILE, "w") as f:
130-
f.write(handle.execution_id)
131-
132-
# Serve workers just long enough for the first tool to start
133-
print("\nServing workers briefly...")
134-
runtime.serve(graph, blocking=False)
135-
time.sleep(8)
136-
137-
print("\nRuntime closed — workers are dead, workflow persists on server.")
138-
print()
139-
140-
with open(SESSION_FILE) as f:
141-
saved_execution_id = f.read().strip()
142-
143-
# -- Pause: let the user see the stalled execution in the UI --------------
144-
145-
ui_link = f"{UI_BASE}/execution/{saved_execution_id}"
146-
print("-" * 60)
147-
print("Open the Conductor UI to see the execution in RUNNING state:")
148-
print(f" {ui_link}")
149-
print()
150-
print("The workflow is alive on the server but stalled — no workers are")
151-
print("polling to pick up the next task. The completed steps are")
152-
print("preserved; only the remaining steps need to run.")
153-
print("-" * 60)
154-
input("\nPress Enter to resume (restart workers)...")
155-
print()
156-
157-
158-
# -- Phase 2: Restart serve — workers pick up stalled tasks ----------------
159-
160-
print("=" * 60)
161-
print("Phase 2: Restart serve() — workers reconnect automatically")
162-
print("=" * 60)
163-
164-
with AgentRuntime() as runtime:
165-
# serve() re-registers the same workers. The server dispatches
166-
# stalled tasks to them — no resume() call needed.
167-
print("\nServing workers (non-blocking for demo)...")
168-
runtime.serve(graph, blocking=False)
169-
170-
# Poll until the execution completes
171-
print(f"Polling execution: {saved_execution_id}")
172-
status = runtime.get_status(saved_execution_id)
173-
while not status.is_complete:
174-
time.sleep(2)
107+
if __name__ == "__main__":
108+
# -- Phase 1: Deploy, start, serve briefly, then crash --------------------
109+
110+
print("=" * 60)
111+
print("Phase 1: Deploy + start, then simulate crash")
112+
print("=" * 60)
113+
114+
with AgentRuntime() as runtime:
115+
# Deploy the workflow definition (in production, do this once in CI/CD)
116+
runtime.deploy(graph)
117+
print("Agent deployed to server.")
118+
119+
# Start an execution by name — the agent is already deployed on the server,
120+
# so we only need to send the name and prompt (not the full graph object).
121+
handle = runtime.start(
122+
"sales_analyst",
123+
"Fetch the Q4 2025 sales data, run a full trend analysis on it, "
124+
"then generate an executive summary report. "
125+
"Call each tool in sequence — do not skip any step.",
126+
)
127+
print(f"Execution started: {handle.execution_id}")
128+
129+
# Save execution_id so we can check status later
130+
with open(SESSION_FILE, "w") as f:
131+
f.write(handle.execution_id)
132+
133+
# Serve workers just long enough for the first tool to start
134+
print("\nServing workers briefly...")
135+
runtime.serve(graph, blocking=False)
136+
time.sleep(8)
137+
138+
print("\nRuntime closed — workers are dead, workflow persists on server.")
139+
print()
140+
141+
with open(SESSION_FILE) as f:
142+
saved_execution_id = f.read().strip()
143+
144+
# -- Pause: let the user see the stalled execution in the UI --------------
145+
146+
ui_link = f"{UI_BASE}/execution/{saved_execution_id}"
147+
print("-" * 60)
148+
print("Open the Conductor UI to see the execution in RUNNING state:")
149+
print(f" {ui_link}")
150+
print()
151+
print("The workflow is alive on the server but stalled — no workers are")
152+
print("polling to pick up the next task. The completed steps are")
153+
print("preserved; only the remaining steps need to run.")
154+
print("-" * 60)
155+
input("\nPress Enter to resume (restart workers)...")
156+
print()
157+
158+
# -- Phase 2: Restart serve — workers pick up stalled tasks ----------------
159+
160+
print("=" * 60)
161+
print("Phase 2: Restart serve() — workers reconnect automatically")
162+
print("=" * 60)
163+
164+
with AgentRuntime() as runtime:
165+
# serve() re-registers the same workers. The server dispatches
166+
# stalled tasks to them — no resume() call needed.
167+
print("\nServing workers (non-blocking for demo)...")
168+
runtime.serve(graph, blocking=False)
169+
170+
# Poll until the execution completes
171+
print(f"Polling execution: {saved_execution_id}")
175172
status = runtime.get_status(saved_execution_id)
176-
print(f" status: {status.status}")
173+
while not status.is_complete:
174+
time.sleep(2)
175+
status = runtime.get_status(saved_execution_id)
176+
print(f" status: {status.status}")
177177

178-
print(f"\nStatus: {status.status}")
179-
print(f"Output: {status.output}")
180-
print("\nCheck the completed execution in the UI:")
181-
print(f" {ui_link}")
178+
print(f"\nStatus: {status.status}")
179+
print(f"Output: {status.output}")
180+
print("\nCheck the completed execution in the UI:")
181+
print(f" {ui_link}")
182182

183-
print("\nDone — same workflow, seamless resume after simulated crash.")
183+
print("\nDone — same workflow, seamless resume after simulated crash.")

‎examples/agents/settings.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
Set ``CONDUCTOR_AGENT_LLM_MODEL`` as an environment variable to override the
44
default model used by all examples::
55
6-
export CONDUCTOR_AGENT_LLM_MODEL=anthropic/claude-sonnet-4-20250514
6+
export CONDUCTOR_AGENT_LLM_MODEL=anthropic/claude-sonnet-4-6
77
export CONDUCTOR_AGENT_LLM_MODEL=google_gemini/gemini-2.0-flash
88
9-
If unset, defaults to ``anthropic/claude-sonnet-4-6``.
9+
If unset, defaults to ``openai/gpt-4o``.
1010
1111
``CONDUCTOR_AGENT_SECONDARY_LLM_MODEL`` provides a second model for multi-model examples
1212
(e.g., cheap triage vs capable specialist). Defaults to ``openai/gpt-4o``.

‎scripts/run_examples.sh‎

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,55 @@
1515
set -euo pipefail
1616

1717
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
18-
EXAMPLES_DIR="$(cd "$SCRIPT_DIR/../examples" && pwd)"
18+
EXAMPLES_DIR="$(cd "$SCRIPT_DIR/../examples/agents" && pwd)"
1919
TIMEOUT="${EXAMPLE_TIMEOUT:-300}"
2020

2121
# Cross-platform python: honour PYTHON env var, then try python3, then python.
2222
PYTHON="${PYTHON:-$(command -v python3 2>/dev/null || command -v python 2>/dev/null || echo python3)}"
2323

24+
# Cross-platform timeout: GNU coreutils provides `timeout`; macOS ships it as
25+
# `gtimeout`, and only when coreutils is installed. Without either, run the
26+
# examples unbounded rather than failing every one of them.
27+
TIMEOUT_BIN="$(command -v timeout 2>/dev/null || command -v gtimeout 2>/dev/null || true)"
28+
if [[ -z "$TIMEOUT_BIN" ]]; then
29+
echo "Warning: neither 'timeout' nor 'gtimeout' found; examples will run" >&2
30+
echo " without a time limit. On macOS: brew install coreutils" >&2
31+
fi
32+
2433
# Cross-platform temp dir: honour TMPDIR (set on macOS/Linux), fall back to /tmp.
2534
TMP_BASE="${TMPDIR:-${TEMP:-/tmp}}"
2635

2736
# Examples that require external services not typically available in a
28-
# standard test environment.
37+
# standard test environment. Run them with --all once the services and
38+
# credentials they need are in place.
2939
SKIP_BY_DEFAULT=(
3040
"04_http_and_mcp_tools" # needs MCP server running
3141
"04_mcp_weather" # needs MCP server running
3242
"24_code_execution" # needs Docker
3343
"25_semantic_memory" # needs vector store / extra deps
3444
"26_opentelemetry_tracing" # needs OTel collector
3545
"28_gpt_assistant_agent" # needs OpenAI Assistants API key
46+
47+
# Act on real third-party accounts: these clone, branch, push, open pull
48+
# requests or post messages, so a default run must not reach them.
49+
"16c_credentials_cli_tools" # needs AWS credentials; can open PRs
50+
"16d_credentials_gh_cli" # needs an authenticated gh CLI
51+
"60_github_coding_agent" # pushes branches, opens PRs
52+
"60a_github_coding_agent_simple" # clones and pushes to a real repo
53+
"61_github_coding_agent_chained" # needs GITHUB_TOKEN; pushes branches
54+
"61a_github_coding_agent_claude_code" # needs GITHUB_TOKEN; pushes branches
55+
"91_slack_autofix_agent" # pushes, opens PRs, posts to Slack
56+
57+
# Block on stdin with no canned response in HITL_STDIN below, so they would
58+
# sit until the per-example timeout.
59+
"09d_human_tool"
60+
"18_manual_selection"
61+
"32_human_guardrail"
62+
"62_coding_agent_openai"
63+
"78_approval_workflow"
64+
"81_chat_repl"
65+
"82_coding_agent"
66+
"82b_coding_agent_tui"
3667
)
3768

3869
# HITL examples that call input() — we pipe automated responses via stdin.
@@ -117,7 +148,11 @@ echo " Running ${#EXAMPLES[@]} examples"
117148
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
118149
echo " Skipping ${#SKIPPED[@]}: ${SKIPPED[*]}"
119150
fi
120-
echo " Timeout: ${TIMEOUT}s per example"
151+
if [[ -n "$TIMEOUT_BIN" ]]; then
152+
echo " Timeout: ${TIMEOUT}s per example"
153+
else
154+
echo " Timeout: none (no timeout binary found)"
155+
fi
121156
echo "=========================================="
122157
echo ""
123158

@@ -141,9 +176,9 @@ for example in "${EXAMPLES[@]}"; do
141176
if [[ -n "$STDIN_RESPONSE" ]]; then
142177
# Use `yes` to provide unlimited identical responses — handles
143178
# cases where the LLM calls an approval tool multiple times.
144-
RUN_CMD="yes '$STDIN_RESPONSE' | timeout $TIMEOUT $PYTHON $example"
179+
RUN_CMD="yes '$STDIN_RESPONSE' | ${TIMEOUT_BIN:+$TIMEOUT_BIN $TIMEOUT }$PYTHON $example"
145180
else
146-
RUN_CMD="timeout $TIMEOUT $PYTHON $example"
181+
RUN_CMD="${TIMEOUT_BIN:+$TIMEOUT_BIN $TIMEOUT }$PYTHON $example"
147182
fi
148183

149184
if eval "$RUN_CMD" > "$LOG_FILE" 2>&1; then

0 commit comments

Comments
 (0)