Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/agentic_workflows/mcp_weather_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def create_mcp_agent_workflow(executor: WorkflowExecutor, mcp_server: str) -> Co
plan_task = LlmChatComplete(
task_ref_name="plan_action",
llm_provider="anthropic",
model="claude-sonnet-4-20250514",
model="claude-sonnet-5",
messages=[
ChatMessage(
role="system",
Expand Down
2 changes: 1 addition & 1 deletion examples/agents/56_rag_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"text": (
"Agent Configuration. Agents are defined with a name, model, instructions, "
"and tools. The model field uses the format 'provider/model_name', e.g. "
"'openai/gpt-4o' or 'anthropic/claude-sonnet-4-20250514'. Instructions can be "
"'openai/gpt-4o' or 'anthropic/claude-sonnet-5'. Instructions can be "
"a string or a PromptTemplate referencing a stored prompt. Tools can be "
"@tool-decorated Python functions, http_tool for REST APIs, mcp_tool for "
"MCP servers, or agent_tool to wrap another agent as a callable tool. "
Expand Down
4 changes: 2 additions & 2 deletions examples/agents/59_coding_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

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

coder = Agent(
name="coder",
model="anthropic/claude-sonnet-4-20250514",
model="anthropic/claude-sonnet-4-6",
instructions=(
"You are an expert Python developer. Write clean, well-structured "
"Python code to solve the given problem. Always execute your code to "
Expand Down
8 changes: 4 additions & 4 deletions examples/agents/60_github_coding_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ def create_pull_request(title: str, body: str, issue_number: int = 0) -> str:

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

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

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

coding_team = Agent(
name="coding_team",
model="anthropic/claude-sonnet-4-20250514",
model="anthropic/claude-sonnet-4-6",
instructions=(
"You are a coding team coordinator. Delegate the incoming request "
"to github_agent to get started — it will pick an issue and set "
Expand Down
8 changes: 4 additions & 4 deletions examples/agents/60a_github_coding_agent_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

github_agent = Agent(
name="github_agent",
model="anthropic/claude-sonnet-4-20250514",
model="anthropic/claude-sonnet-4-6",
instructions=(
"You are a GitHub operations specialist. You handle all git and "
"GitHub CLI interactions.\n\n"
Expand Down Expand Up @@ -77,7 +77,7 @@

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

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

coding_team = Agent(
name="coding_team",
model="anthropic/claude-sonnet-4-20250514",
model="anthropic/claude-sonnet-4-6",
instructions=(
"You are a coding team coordinator. Delegate the incoming request "
"to github_agent to get started — it will pick an issue and set "
Expand Down
2 changes: 1 addition & 1 deletion examples/agents/74_cli_error_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
with AgentRuntime() as rt:
result = rt.run(agent, prompt)
result.print_result()
output = result.output or ""
output = str(result.output)

# Verify the agent saw the error output
assert "No such file or directory" in output or "nonexistent" in output, (
Expand Down
2 changes: 1 addition & 1 deletion examples/agents/adk/35_rag_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"text": (
"Agent Configuration. Agents are defined with a name, model, instructions, "
"and tools. The model field uses the format 'provider/model_name', e.g. "
"'openai/gpt-4o' or 'anthropic/claude-sonnet-4-20250514'. Instructions can be "
"'openai/gpt-4o' or 'anthropic/claude-sonnet-5'. Instructions can be "
"a string or a PromptTemplate referencing a stored prompt. Tools can be "
"@tool-decorated Python functions, http_tool for REST APIs, mcp_tool for "
"MCP servers, or agent_tool to wrap another agent as a callable tool. "
Expand Down
148 changes: 74 additions & 74 deletions examples/agents/langgraph/46_crash_and_resume.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,80 +104,80 @@ def generate_report(analysis: str) -> str:
)


# -- Phase 1: Deploy, start, serve briefly, then crash --------------------

print("=" * 60)
print("Phase 1: Deploy + start, then simulate crash")
print("=" * 60)

with AgentRuntime() as runtime:
# Deploy the workflow definition (in production, do this once in CI/CD)
runtime.deploy(graph)
print("Agent deployed to server.")

# Start an execution by name — the agent is already deployed on the server,
# so we only need to send the name and prompt (not the full graph object).
handle = runtime.start(
"sales_analyst",
"Fetch the Q4 2025 sales data, run a full trend analysis on it, "
"then generate an executive summary report. "
"Call each tool in sequence — do not skip any step.",
)
print(f"Execution started: {handle.execution_id}")

# Save execution_id so we can check status later
with open(SESSION_FILE, "w") as f:
f.write(handle.execution_id)

# Serve workers just long enough for the first tool to start
print("\nServing workers briefly...")
runtime.serve(graph, blocking=False)
time.sleep(8)

print("\nRuntime closed — workers are dead, workflow persists on server.")
print()

with open(SESSION_FILE) as f:
saved_execution_id = f.read().strip()

# -- Pause: let the user see the stalled execution in the UI --------------

ui_link = f"{UI_BASE}/execution/{saved_execution_id}"
print("-" * 60)
print("Open the Conductor UI to see the execution in RUNNING state:")
print(f" {ui_link}")
print()
print("The workflow is alive on the server but stalled — no workers are")
print("polling to pick up the next task. The completed steps are")
print("preserved; only the remaining steps need to run.")
print("-" * 60)
input("\nPress Enter to resume (restart workers)...")
print()


# -- Phase 2: Restart serve — workers pick up stalled tasks ----------------

print("=" * 60)
print("Phase 2: Restart serve() — workers reconnect automatically")
print("=" * 60)

with AgentRuntime() as runtime:
# serve() re-registers the same workers. The server dispatches
# stalled tasks to them — no resume() call needed.
print("\nServing workers (non-blocking for demo)...")
runtime.serve(graph, blocking=False)

# Poll until the execution completes
print(f"Polling execution: {saved_execution_id}")
status = runtime.get_status(saved_execution_id)
while not status.is_complete:
time.sleep(2)
if __name__ == "__main__":
# -- Phase 1: Deploy, start, serve briefly, then crash --------------------

print("=" * 60)
print("Phase 1: Deploy + start, then simulate crash")
print("=" * 60)

with AgentRuntime() as runtime:
# Deploy the workflow definition (in production, do this once in CI/CD)
runtime.deploy(graph)
print("Agent deployed to server.")

# Start an execution by name — the agent is already deployed on the server,
# so we only need to send the name and prompt (not the full graph object).
handle = runtime.start(
"sales_analyst",
"Fetch the Q4 2025 sales data, run a full trend analysis on it, "
"then generate an executive summary report. "
"Call each tool in sequence — do not skip any step.",
)
print(f"Execution started: {handle.execution_id}")

# Save execution_id so we can check status later
with open(SESSION_FILE, "w") as f:
f.write(handle.execution_id)

# Serve workers just long enough for the first tool to start
print("\nServing workers briefly...")
runtime.serve(graph, blocking=False)
time.sleep(8)

print("\nRuntime closed — workers are dead, workflow persists on server.")
print()

with open(SESSION_FILE) as f:
saved_execution_id = f.read().strip()

# -- Pause: let the user see the stalled execution in the UI --------------

ui_link = f"{UI_BASE}/execution/{saved_execution_id}"
print("-" * 60)
print("Open the Conductor UI to see the execution in RUNNING state:")
print(f" {ui_link}")
print()
print("The workflow is alive on the server but stalled — no workers are")
print("polling to pick up the next task. The completed steps are")
print("preserved; only the remaining steps need to run.")
print("-" * 60)
input("\nPress Enter to resume (restart workers)...")
print()

# -- Phase 2: Restart serve — workers pick up stalled tasks ----------------

print("=" * 60)
print("Phase 2: Restart serve() — workers reconnect automatically")
print("=" * 60)

with AgentRuntime() as runtime:
# serve() re-registers the same workers. The server dispatches
# stalled tasks to them — no resume() call needed.
print("\nServing workers (non-blocking for demo)...")
runtime.serve(graph, blocking=False)

# Poll until the execution completes
print(f"Polling execution: {saved_execution_id}")
status = runtime.get_status(saved_execution_id)
print(f" status: {status.status}")
while not status.is_complete:
time.sleep(2)
status = runtime.get_status(saved_execution_id)
print(f" status: {status.status}")

print(f"\nStatus: {status.status}")
print(f"Output: {status.output}")
print("\nCheck the completed execution in the UI:")
print(f" {ui_link}")
print(f"\nStatus: {status.status}")
print(f"Output: {status.output}")
print("\nCheck the completed execution in the UI:")
print(f" {ui_link}")

print("\nDone — same workflow, seamless resume after simulated crash.")
print("\nDone — same workflow, seamless resume after simulated crash.")
4 changes: 2 additions & 2 deletions examples/agents/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
Set ``CONDUCTOR_AGENT_LLM_MODEL`` as an environment variable to override the
default model used by all examples::

export CONDUCTOR_AGENT_LLM_MODEL=anthropic/claude-sonnet-4-20250514
export CONDUCTOR_AGENT_LLM_MODEL=anthropic/claude-sonnet-4-6
export CONDUCTOR_AGENT_LLM_MODEL=google_gemini/gemini-2.0-flash

If unset, defaults to ``anthropic/claude-sonnet-4-6``.
If unset, defaults to ``openai/gpt-4o``.

``CONDUCTOR_AGENT_SECONDARY_LLM_MODEL`` provides a second model for multi-model examples
(e.g., cheap triage vs capable specialist). Defaults to ``openai/gpt-4o``.
Expand Down
45 changes: 40 additions & 5 deletions scripts/run_examples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,55 @@
set -euo pipefail

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

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

# Cross-platform timeout: GNU coreutils provides `timeout`; macOS ships it as
# `gtimeout`, and only when coreutils is installed. Without either, run the
# examples unbounded rather than failing every one of them.
TIMEOUT_BIN="$(command -v timeout 2>/dev/null || command -v gtimeout 2>/dev/null || true)"
if [[ -z "$TIMEOUT_BIN" ]]; then
echo "Warning: neither 'timeout' nor 'gtimeout' found; examples will run" >&2
echo " without a time limit. On macOS: brew install coreutils" >&2
fi

# Cross-platform temp dir: honour TMPDIR (set on macOS/Linux), fall back to /tmp.
TMP_BASE="${TMPDIR:-${TEMP:-/tmp}}"

# Examples that require external services not typically available in a
# standard test environment.
# standard test environment. Run them with --all once the services and
# credentials they need are in place.
SKIP_BY_DEFAULT=(
"04_http_and_mcp_tools" # needs MCP server running
"04_mcp_weather" # needs MCP server running
"24_code_execution" # needs Docker
"25_semantic_memory" # needs vector store / extra deps
"26_opentelemetry_tracing" # needs OTel collector
"28_gpt_assistant_agent" # needs OpenAI Assistants API key

# Act on real third-party accounts: these clone, branch, push, open pull
# requests or post messages, so a default run must not reach them.
"16c_credentials_cli_tools" # needs AWS credentials; can open PRs
"16d_credentials_gh_cli" # needs an authenticated gh CLI
"60_github_coding_agent" # pushes branches, opens PRs
"60a_github_coding_agent_simple" # clones and pushes to a real repo
"61_github_coding_agent_chained" # needs GITHUB_TOKEN; pushes branches
"61a_github_coding_agent_claude_code" # needs GITHUB_TOKEN; pushes branches
"91_slack_autofix_agent" # pushes, opens PRs, posts to Slack

# Block on stdin with no canned response in HITL_STDIN below, so they would
# sit until the per-example timeout.
"09d_human_tool"
"18_manual_selection"
"32_human_guardrail"
"62_coding_agent_openai"
"78_approval_workflow"
"81_chat_repl"
"82_coding_agent"
"82b_coding_agent_tui"
)

# HITL examples that call input() — we pipe automated responses via stdin.
Expand Down Expand Up @@ -117,7 +148,11 @@ echo " Running ${#EXAMPLES[@]} examples"
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
echo " Skipping ${#SKIPPED[@]}: ${SKIPPED[*]}"
fi
echo " Timeout: ${TIMEOUT}s per example"
if [[ -n "$TIMEOUT_BIN" ]]; then
echo " Timeout: ${TIMEOUT}s per example"
else
echo " Timeout: none (no timeout binary found)"
fi
echo "=========================================="
echo ""

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

if eval "$RUN_CMD" > "$LOG_FILE" 2>&1; then
Expand Down
Loading