From 171e181bf1ecb55e8d7241288a8f8c71ce25c7ad Mon Sep 17 00:00:00 2001 From: Nir Singher Date: Wed, 5 Aug 2026 16:47:29 +0300 Subject: [PATCH] fix(examples): pin band-sdk to a published PyPI release instead of git HEAD Every example's PEP 723 metadata resolved band-sdk via a [tool.uv.sources] git override pointing at main, so uv run always built the SDK fresh from whatever was on main at that moment -- including unreleased or actively-breaking code -- rather than a stable, reproducible release. This surfaced while validating the Claude/Codex Docker planner/reviewer stack. Repoints every example (and the AGENTS.md/CLAUDE.md template) at the published PyPI band-sdk, pinned >=1.2.0,<2.0.0, and drops the git source override. Also hardens the coding_agents create_agents.py/test_communication.py scripts (shared .env loading, ledger-persistence timing, a guard against the stale bind-mount directory Docker auto-creates) uncovered along the way. Fixes INT-1178 --- AGENTS.md | 49 +++- examples/20-questions-arena/guesser_agent.py | 5 +- examples/20-questions-arena/start_game.py | 5 +- examples/20-questions-arena/thinker_agent.py | 5 +- examples/a2a_bridge/01_basic_agent.py | 5 +- examples/a2a_bridge/02_with_auth.py | 5 +- examples/a2a_gateway/01_basic_gateway.py | 5 +- examples/a2a_gateway/02_with_demo_agent.py | 5 +- examples/acp/clients/bridge_architecture.py | 5 +- examples/acp/clients/copilot.py | 5 +- examples/acp/clients/cursor.py | 5 +- examples/acp/clients/generic.py | 5 +- examples/acp/clients/rich_streaming.py | 5 +- .../acp/copilot_docker/colocated/client.py | 5 +- examples/acp/copilot_docker/compose/client.py | 5 +- examples/acp/copilot_sandbox/client.py | 5 +- examples/acp/servers/basic.py | 5 +- examples/acp/servers/jetbrains.py | 5 +- examples/acp/servers/push_notifications.py | 5 +- examples/acp/servers/routing.py | 5 +- examples/agentcore/agentcore_llm_server.py | 5 +- examples/agentcore/verify_deployment.py | 5 +- examples/agno/01_basic_agent.py | 5 +- examples/agno/02_tool_reporting.py | 5 +- examples/agno/03_tom_agent.py | 5 +- examples/agno/04_jerry_agent.py | 5 +- examples/agno/05_memory_secretary.py | 5 +- examples/agno/06_agno_db_history.py | 5 +- examples/anthropic/01_basic_agent.py | 5 +- examples/anthropic/02_custom_instructions.py | 5 +- examples/anthropic/03_tom_agent.py | 5 +- examples/anthropic/04_jerry_agent.py | 5 +- examples/anthropic/05_contact_management.py | 5 +- examples/claude_sdk/01_basic_agent.py | 5 +- examples/claude_sdk/02_extended_thinking.py | 5 +- examples/claude_sdk/03_tom_agent.py | 5 +- examples/claude_sdk/04_jerry_agent.py | 5 +- examples/claude_sdk_docker/runner.py | 5 +- examples/codex/01_basic_agent.py | 5 +- examples/codex/02_tom_agent.py | 5 +- examples/codex/03_jerry_agent.py | 5 +- examples/coding_agents/README.md | 69 ++++-- examples/coding_agents/create_agents.py | 212 ++++++++++++++---- examples/coding_agents/test_communication.py | 59 ++--- examples/copilot_sdk/01_basic_agent.py | 5 +- examples/copilot_sdk/02_byok_anthropic.py | 5 +- examples/copilot_sdk/03_tom_agent.py | 5 +- examples/copilot_sdk/04_jerry_agent.py | 5 +- .../05_contact_and_memory_agent.py | 5 +- examples/copilot_sdk/06_ask_user.py | 5 +- examples/crewai/01_basic_agent.py | 5 +- examples/crewai/02_role_based_agent.py | 5 +- examples/crewai/03_coordinator_agent.py | 5 +- examples/crewai/04_research_crew.py | 5 +- examples/crewai/05_tom_agent.py | 5 +- examples/crewai/06_jerry_agent.py | 5 +- .../crewai/07_contact_and_memory_agent.py | 5 +- examples/crewai/08_flow_router.py | 5 +- examples/crewai/09_flow_custom_tools.py | 5 +- examples/crewai/10_memory_tool_usage.py | 5 +- examples/docker_demo/conductor.py | 5 +- examples/docker_demo/provision.py | 5 +- examples/gemini/01_basic_agent.py | 5 +- examples/google_adk/01_basic_agent.py | 5 +- examples/google_adk/02_custom_instructions.py | 5 +- examples/google_adk/03_custom_tools.py | 5 +- examples/langgraph/01_simple_agent.py | 5 +- examples/langgraph/02_custom_tools.py | 5 +- examples/langgraph/03_custom_personality.py | 5 +- examples/langgraph/04_calculator_as_tool.py | 5 +- examples/langgraph/05_rag_as_tool.py | 5 +- .../langgraph/06_delegate_to_sql_agent.py | 5 +- examples/langgraph/07_tom_agent.py | 5 +- examples/langgraph/08_jerry_agent.py | 5 +- .../langgraph/09_research_ops_orchestrator.py | 5 +- examples/langgraph/10_memory_tool_usage.py | 5 +- examples/langgraph/11_no_llm_graph.py | 5 +- examples/letta/01_basic_agent.py | 5 +- examples/mixed/01_strategy_coordinator.py | 5 +- examples/mixed/02_draft_writer.py | 5 +- examples/mixed/03_fact_checker_a2a.py | 5 +- examples/mixed/04_risk_reviewer_a2a.py | 5 +- examples/mixed/05_a2a_bridge.py | 5 +- examples/opencode/01_basic_agent.py | 5 +- examples/opencode/02_workspace_agent.py | 5 +- examples/opencode/03_custom_tools_agent.py | 5 +- examples/opencode/04_memory_secretary.py | 5 +- examples/opencode/05_tom_agent.py | 5 +- examples/opencode/06_jerry_agent.py | 5 +- examples/opentelemetry/pydantic_ai_agent.py | 5 +- examples/parlant/01_basic_agent.py | 5 +- examples/parlant/02_with_guidelines.py | 5 +- examples/parlant/03_support_agent.py | 5 +- examples/parlant/04_tom_agent.py | 5 +- examples/parlant/05_jerry_agent.py | 5 +- examples/pydantic_ai/01_basic_agent.py | 5 +- .../pydantic_ai/02_custom_instructions.py | 5 +- examples/pydantic_ai/03_tom_agent.py | 5 +- examples/pydantic_ai/04_jerry_agent.py | 5 +- examples/run_agent.py | 5 +- examples/slack/01_basic_bot.py | 5 +- examples/strands/01_basic_agent.py | 5 +- examples/strands/02_custom_tools.py | 5 +- examples/strands/03_custom_instructions.py | 5 +- examples/strands/04_native_tools.py | 5 +- examples/strands/05_bedrock_model.py | 5 +- examples/strands/06_tom_agent.py | 5 +- examples/strands/07_jerry_agent.py | 5 +- 108 files changed, 400 insertions(+), 509 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e3d028ea7..290d9cac7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -601,15 +601,17 @@ uv run ruff check . && uv run ruff format . ### PEP 723 Script Metadata (Required for `uv run` support) -Every example file must include PEP 723 inline script metadata at the top for standalone execution with `uv run`: +Every example file must include PEP 723 inline script metadata at the top for +standalone execution with `uv run` — this includes **every** standalone script +in an example directory (registration/provisioning helpers, test harnesses, +one-off utilities), not just the primary agent entrypoint. Bare `python foo.py` +assumes the SDK is already installed; document `uv run foo.py` in the README so +the script runs against a fetched-on-the-fly SDK. Metadata: ```python # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[]>=1.2.0,<2.0.0"] # /// """ Brief description of what this example does. @@ -621,16 +623,53 @@ Run with: Replace `` with the appropriate framework extra (e.g., `langgraph`, `anthropic`, `crewai`, `claude-sdk`, `pydantic-ai`, `parlant`). +**Depend on the published PyPI `band-sdk`, pinned `>=1.2.0,<2.0.0`** — not a +`[tool.uv.sources]` git override. `uv run` then fetches a released wheel instead +of building the default branch HEAD (reproducible, no git needed). The **only** +exception: an example whose extra is not yet published on PyPI (a brand-new +adapter) may keep a git source until the next release exposes the extra — leave +a one-line comment saying so, and flip it to the pinned PyPI form once released. + ### Other Requirements - Use `load_agent_config("agent_name")` for credentials, NOT direct `os.environ.get()` + and NOT a hand-rolled YAML loader. `band.config.load_agent_config()` already + validates a missing file / empty values / required fields and understands both + the keyed (`planner:`/`reviewer:`) and flat single-agent formats — reuse it. - Always load and validate `BAND_WS_URL` and `BAND_REST_URL` with `ValueError` +- **A helper script must read the same config source as the stack it supports.** + If the runtime (e.g. Docker Compose) reads `.env` for `BAND_REST_URL`, the + companion scripts must `load_dotenv()` the same `.env` — otherwise they + silently target a *different* platform (the default `app.band.ai`) than the + containers, and register/probe agents the stack can't see. - Use `raise ValueError(...)` for missing required config, NOT `logger.error()` + `sys.exit()` - Use single sys.path line: `sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))` - Never hardcode UUIDs in docstrings - reference `agent_config.yaml` instead - All `async def main()` functions must have `-> None` return type hint - Always include `from __future__ import annotations` as first import +### Provisioning / setup scripts (create-agents, register-*, bootstrap) + +Scripts that create remote resources (agents, rooms) or generate credential +files have failure modes plain examples don't. Follow these: + +- **Persist created resource ids immediately, append-only.** Write each id to a + cleanup ledger the moment the resource exists — before the next create or any + file write can fail. Writing all ids once at the end orphans everything already + created if a later step throws; overwriting the ledger on a re-run loses the + *previous* run's ids. Both leak paid/limited resources. +- **Refuse to clobber existing credentials without an explicit `FORCE`.** A + re-run that silently overwrites `agent_config.yaml` orphans the agents it + referenced. Fail with a message pointing at the cleanup ledger. +- **Guard file writes against the stale bind-mount directory.** Docker + auto-creates a *missing* bind-mount source as an empty **directory**. Check + `path.is_dir()` / `path.exists()`, NOT `path.is_file()` (which is `False` for a + directory and lets the work run, then crashes at `write_text` with + `IsADirectoryError`). Do this check **before** any irreversible step (e.g. + registering agents), so you never create resources you then can't record. +- **Keep `main()` thin.** Extract persistence (config/ledger writes) and the + user-facing summary into small named helpers — easier to read and to test. + ## Documentation Testing (markdown snippets) Tracked `.md` files (except `examples/`) run in CI as tests via `pytest-markdown-docs` diff --git a/examples/20-questions-arena/guesser_agent.py b/examples/20-questions-arena/guesser_agent.py index 83e4c044d..7963765f6 100644 --- a/examples/20-questions-arena/guesser_agent.py +++ b/examples/20-questions-arena/guesser_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Guesser agent for the 20 Questions Arena game. diff --git a/examples/20-questions-arena/start_game.py b/examples/20-questions-arena/start_game.py index 8df48294f..cf5c4c1c5 100644 --- a/examples/20-questions-arena/start_game.py +++ b/examples/20-questions-arena/start_game.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """Start a 20 Questions Arena game as a user by creating a room, adding all agents, and sending a message. diff --git a/examples/20-questions-arena/thinker_agent.py b/examples/20-questions-arena/thinker_agent.py index 1d7db23b1..529cef7ac 100644 --- a/examples/20-questions-arena/thinker_agent.py +++ b/examples/20-questions-arena/thinker_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Thinker agent for the 20 Questions Arena game. diff --git a/examples/a2a_bridge/01_basic_agent.py b/examples/a2a_bridge/01_basic_agent.py index d920add35..8a3651dc6 100644 --- a/examples/a2a_bridge/01_basic_agent.py +++ b/examples/a2a_bridge/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[a2a]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[a2a]>=1.2.0,<2.0.0"] # /// """ Basic A2A adapter example. diff --git a/examples/a2a_bridge/02_with_auth.py b/examples/a2a_bridge/02_with_auth.py index 0ebc7d9f6..f3764fc41 100644 --- a/examples/a2a_bridge/02_with_auth.py +++ b/examples/a2a_bridge/02_with_auth.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[a2a]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[a2a]>=1.2.0,<2.0.0"] # /// """ A2A adapter with authentication example. diff --git a/examples/a2a_gateway/01_basic_gateway.py b/examples/a2a_gateway/01_basic_gateway.py index f32637576..fd6f2242e 100644 --- a/examples/a2a_gateway/01_basic_gateway.py +++ b/examples/a2a_gateway/01_basic_gateway.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[a2a_gateway]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[a2a_gateway]>=1.2.0,<2.0.0"] # /// """ Basic A2A Gateway adapter example. diff --git a/examples/a2a_gateway/02_with_demo_agent.py b/examples/a2a_gateway/02_with_demo_agent.py index 2e9caeec6..82ddc2656 100644 --- a/examples/a2a_gateway/02_with_demo_agent.py +++ b/examples/a2a_gateway/02_with_demo_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[a2a_gateway_demo]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[a2a_gateway_demo]>=1.2.0,<2.0.0"] # /// """ Run A2A Gateway with Demo Orchestrator Agent. diff --git a/examples/acp/clients/bridge_architecture.py b/examples/acp/clients/bridge_architecture.py index e5648981b..470b1afff 100644 --- a/examples/acp/clients/bridge_architecture.py +++ b/examples/acp/clients/bridge_architecture.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ ACP Bridge Architecture example. diff --git a/examples/acp/clients/copilot.py b/examples/acp/clients/copilot.py index a097a3dc3..659ed2429 100644 --- a/examples/acp/clients/copilot.py +++ b/examples/acp/clients/copilot.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ GitHub Copilot CLI ACP Client - Use GitHub Copilot from Band. diff --git a/examples/acp/clients/cursor.py b/examples/acp/clients/cursor.py index 97d6a4f68..dc3b37b02 100644 --- a/examples/acp/clients/cursor.py +++ b/examples/acp/clients/cursor.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ Cursor ACP Client - Use Cursor's AI agent from Band. diff --git a/examples/acp/clients/generic.py b/examples/acp/clients/generic.py index e339b6105..9a4fb893e 100644 --- a/examples/acp/clients/generic.py +++ b/examples/acp/clients/generic.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ ACP Client example - Use a remote ACP agent from Band. diff --git a/examples/acp/clients/rich_streaming.py b/examples/acp/clients/rich_streaming.py index 35b730bdc..2a62bef51 100644 --- a/examples/acp/clients/rich_streaming.py +++ b/examples/acp/clients/rich_streaming.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ ACP Client with rich streaming - Thoughts, tool calls, and plans. diff --git a/examples/acp/copilot_docker/colocated/client.py b/examples/acp/copilot_docker/colocated/client.py index 571c5b61a..29e865c53 100644 --- a/examples/acp/copilot_docker/colocated/client.py +++ b/examples/acp/copilot_docker/colocated/client.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ Host-side Band SDK client for the colocated Copilot Docker example. diff --git a/examples/acp/copilot_docker/compose/client.py b/examples/acp/copilot_docker/compose/client.py index 0131f43b2..40e1806ac 100644 --- a/examples/acp/copilot_docker/compose/client.py +++ b/examples/acp/copilot_docker/compose/client.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git"} +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ Host-side Band SDK client for the Copilot Docker Compose example. diff --git a/examples/acp/copilot_sandbox/client.py b/examples/acp/copilot_sandbox/client.py index 73546515f..d141e125f 100644 --- a/examples/acp/copilot_sandbox/client.py +++ b/examples/acp/copilot_sandbox/client.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ GitHub Copilot in a Docker sandbox (sbx), driven by Band over stdio. diff --git a/examples/acp/servers/basic.py b/examples/acp/servers/basic.py index 9632e3b14..2184d9500 100644 --- a/examples/acp/servers/basic.py +++ b/examples/acp/servers/basic.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ Basic ACP Server example - Band as an ACP agent. diff --git a/examples/acp/servers/jetbrains.py b/examples/acp/servers/jetbrains.py index a27a3af88..a79761aa3 100644 --- a/examples/acp/servers/jetbrains.py +++ b/examples/acp/servers/jetbrains.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ JetBrains ACP Server - Use Band as an ACP agent in JetBrains IDEs. diff --git a/examples/acp/servers/push_notifications.py b/examples/acp/servers/push_notifications.py index 4b0efd5e6..6c58c096a 100644 --- a/examples/acp/servers/push_notifications.py +++ b/examples/acp/servers/push_notifications.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ ACP Server with push notifications - Real-time activity from Band peers. diff --git a/examples/acp/servers/routing.py b/examples/acp/servers/routing.py index f8ed46e56..b66dd8a5c 100644 --- a/examples/acp/servers/routing.py +++ b/examples/acp/servers/routing.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[acp]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[acp]>=1.2.0,<2.0.0"] # /// """ ACP Server with routing - Target specific peers via slash commands or modes. diff --git a/examples/agentcore/agentcore_llm_server.py b/examples/agentcore/agentcore_llm_server.py index 3c9d22a35..b67420adc 100644 --- a/examples/agentcore/agentcore_llm_server.py +++ b/examples/agentcore/agentcore_llm_server.py @@ -1,13 +1,10 @@ # /// script # requires-python = ">=3.11" # dependencies = [ -# "band-sdk[anthropic]", +# "band-sdk[anthropic]>=1.2.0,<2.0.0", # "fastapi>=0.110", # "uvicorn>=0.29", # ] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } # /// """AgentCore container that runs the Band SDK per invocation. diff --git a/examples/agentcore/verify_deployment.py b/examples/agentcore/verify_deployment.py index 96007c103..c633aed23 100644 --- a/examples/agentcore/verify_deployment.py +++ b/examples/agentcore/verify_deployment.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk>=1.2.0,<2.0.0"] # /// """Post-deployment smoke check for the AgentCore demo in this folder. diff --git a/examples/agno/01_basic_agent.py b/examples/agno/01_basic_agent.py index df2ce61dd..a13107cd4 100644 --- a/examples/agno/01_basic_agent.py +++ b/examples/agno/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[agno]", "anthropic>=0.75.0"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[agno]>=1.2.0,<2.0.0", "anthropic>=0.75.0"] # /// """ Basic Agno agent example. diff --git a/examples/agno/02_tool_reporting.py b/examples/agno/02_tool_reporting.py index de7d5be61..8304b2ed0 100644 --- a/examples/agno/02_tool_reporting.py +++ b/examples/agno/02_tool_reporting.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[agno]", "anthropic>=0.75.0"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[agno]>=1.2.0,<2.0.0", "anthropic>=0.75.0"] # /// """ Agno agent with tool-execution reporting. diff --git a/examples/agno/03_tom_agent.py b/examples/agno/03_tom_agent.py index 476363bbf..45c173427 100644 --- a/examples/agno/03_tom_agent.py +++ b/examples/agno/03_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[agno]", "anthropic>=0.75.0"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[agno]>=1.2.0,<2.0.0", "anthropic>=0.75.0"] # /// """ Tom the cat agent — tries to catch Jerry! diff --git a/examples/agno/04_jerry_agent.py b/examples/agno/04_jerry_agent.py index 5dd31476e..5b7fbc805 100644 --- a/examples/agno/04_jerry_agent.py +++ b/examples/agno/04_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[agno]", "anthropic>=0.75.0"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[agno]>=1.2.0,<2.0.0", "anthropic>=0.75.0"] # /// """ Jerry the mouse agent — outsmarts Tom! diff --git a/examples/agno/05_memory_secretary.py b/examples/agno/05_memory_secretary.py index a9bf104de..484eff582 100644 --- a/examples/agno/05_memory_secretary.py +++ b/examples/agno/05_memory_secretary.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[agno]", "anthropic>=0.75.0"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[agno]>=1.2.0,<2.0.0", "anthropic>=0.75.0"] # /// """ Agno agent with Band memory tools enabled. diff --git a/examples/agno/06_agno_db_history.py b/examples/agno/06_agno_db_history.py index 17770e23e..7e4d373fb 100644 --- a/examples/agno/06_agno_db_history.py +++ b/examples/agno/06_agno_db_history.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[agno]", "anthropic>=0.75.0"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[agno]>=1.2.0,<2.0.0", "anthropic>=0.75.0"] # /// """ Agno-owned conversation history with a database. diff --git a/examples/anthropic/01_basic_agent.py b/examples/anthropic/01_basic_agent.py index 65358cdf6..632b388e8 100644 --- a/examples/anthropic/01_basic_agent.py +++ b/examples/anthropic/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[anthropic]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[anthropic]>=1.2.0,<2.0.0"] # /// """ Basic Anthropic SDK agent example. diff --git a/examples/anthropic/02_custom_instructions.py b/examples/anthropic/02_custom_instructions.py index bc93468e0..e8db675f5 100644 --- a/examples/anthropic/02_custom_instructions.py +++ b/examples/anthropic/02_custom_instructions.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[anthropic]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[anthropic]>=1.2.0,<2.0.0"] # /// """ Agent with custom system prompt instructions. diff --git a/examples/anthropic/03_tom_agent.py b/examples/anthropic/03_tom_agent.py index dec84ff23..0789bbf4e 100644 --- a/examples/anthropic/03_tom_agent.py +++ b/examples/anthropic/03_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[anthropic]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[anthropic]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent - tries to catch Jerry! diff --git a/examples/anthropic/04_jerry_agent.py b/examples/anthropic/04_jerry_agent.py index 2c2edc30d..e278e1c1c 100644 --- a/examples/anthropic/04_jerry_agent.py +++ b/examples/anthropic/04_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[anthropic]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[anthropic]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent - clever and cheese-loving! diff --git a/examples/anthropic/05_contact_management.py b/examples/anthropic/05_contact_management.py index 2ab5208c1..94512a550 100644 --- a/examples/anthropic/05_contact_management.py +++ b/examples/anthropic/05_contact_management.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[anthropic]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[anthropic]>=1.2.0,<2.0.0"] # /// """ Contact management example using the Anthropic adapter. diff --git a/examples/claude_sdk/01_basic_agent.py b/examples/claude_sdk/01_basic_agent.py index 86fa6c614..0b0a46d85 100644 --- a/examples/claude_sdk/01_basic_agent.py +++ b/examples/claude_sdk/01_basic_agent.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[claude_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[claude_sdk]>=1.2.0,<2.0.0"] # /// """ Basic Claude SDK Agent Example. diff --git a/examples/claude_sdk/02_extended_thinking.py b/examples/claude_sdk/02_extended_thinking.py index c2d04bb82..3b79b4c34 100644 --- a/examples/claude_sdk/02_extended_thinking.py +++ b/examples/claude_sdk/02_extended_thinking.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[claude_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[claude_sdk]>=1.2.0,<2.0.0"] # /// """ Extended Thinking Claude SDK Agent Example. diff --git a/examples/claude_sdk/03_tom_agent.py b/examples/claude_sdk/03_tom_agent.py index 2d563126f..58c57d7c3 100644 --- a/examples/claude_sdk/03_tom_agent.py +++ b/examples/claude_sdk/03_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[claude_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[claude_sdk]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent using Claude SDK. diff --git a/examples/claude_sdk/04_jerry_agent.py b/examples/claude_sdk/04_jerry_agent.py index e0162d163..699220922 100644 --- a/examples/claude_sdk/04_jerry_agent.py +++ b/examples/claude_sdk/04_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[claude_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[claude_sdk]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent using Claude SDK. diff --git a/examples/claude_sdk_docker/runner.py b/examples/claude_sdk_docker/runner.py index 0c1dc012a..6ec631784 100644 --- a/examples/claude_sdk_docker/runner.py +++ b/examples/claude_sdk_docker/runner.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[claude_sdk]", "pyyaml"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[claude_sdk]>=1.2.0,<2.0.0", "pyyaml"] # /// """ YAML-based agent runner for Band Claude SDK. diff --git a/examples/codex/01_basic_agent.py b/examples/codex/01_basic_agent.py index 321475a4e..63d55ab34 100644 --- a/examples/codex/01_basic_agent.py +++ b/examples/codex/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[codex,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[codex,logging]>=1.2.0,<2.0.0"] # /// """ Basic Codex adapter agent example. diff --git a/examples/codex/02_tom_agent.py b/examples/codex/02_tom_agent.py index 7ec177c23..02c655f99 100644 --- a/examples/codex/02_tom_agent.py +++ b/examples/codex/02_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[codex,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[codex,logging]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent - tries to catch Jerry! diff --git a/examples/codex/03_jerry_agent.py b/examples/codex/03_jerry_agent.py index d47345ded..de67364b9 100644 --- a/examples/codex/03_jerry_agent.py +++ b/examples/codex/03_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[codex,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[codex,logging]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent - clever and cheese-loving! diff --git a/examples/coding_agents/README.md b/examples/coding_agents/README.md index a4c7d69ce..06a26c879 100644 --- a/examples/coding_agents/README.md +++ b/examples/coding_agents/README.md @@ -20,10 +20,15 @@ Shared workspace volumes: ## Repo Initialization -On startup, each container reads `repo` config from `agent_config.yaml`: -1. Clone repo to `repo.path` if missing -2. Skip clone when repo already exists -3. Optionally generate context files when `repo.index: true` +The `repo` block in `agent_config.yaml` is **optional**. With no `repo` block +(the default written by `create_agents.py`), the agents boot, connect to Band, +and coordinate over chat — no repository is cloned and no GitHub/SSH access is +needed. This is the fastest way to see the two agents talk. + +When you add a `repo` block, each container on startup: +1. Clones the repo to `repo.path` if missing +2. Skips the clone when the repo already exists +3. Optionally generates context files when `repo.index: true` Generated files: - `/workspace/context/structure.md` @@ -62,28 +67,35 @@ When using HTTPS URLs, configure git credentials on host (`credential helper`, P ## Prerequisites - Docker and Docker Compose v2 -- Anthropic API key for planner -- OpenAI API key for reviewer -- Band agent credentials (`agent_id` + `api_key`) +- Anthropic API key for the planner +- OpenAI API key for the reviewer +- A Band **user** API key (`band_u_...`) to register the two agents ## Setup -1. Configure environment: +1. Add your LLM API keys: ```bash cp .env.example .env +# edit .env: set ANTHROPIC_API_KEY and OPENAI_API_KEY ``` -2. Configure agents and repo: +2. Register the agents and generate `agent_config.yaml`: ```bash -cp agent_config.yaml.example agent_config.yaml +BAND_API_KEY=band_u_... uv run create_agents.py ``` -Fill in: -- `planner.agent_id`, `planner.api_key` -- `reviewer.agent_id`, `reviewer.api_key` -- `planner.repo` and `reviewer.repo` (same URL/path/branch) +`create_agents.py` carries PEP 723 metadata, so `uv run` fetches the SDK on the +fly — no separate `pip install` needed. It loads this directory's `.env`, so it +registers the agents on the **same** `BAND_REST_URL` Compose connects to (set it +once in `.env`). + +This registers a Planner and a Reviewer and writes the combined +`agent_config.yaml` that compose reads. No repo is wired by default (chat-only). +To point the agents at a shared repo, set `REPO_URL` (and optionally +`REPO_BRANCH`, `REPO_INDEX`) when running the script — see +`agent_config.yaml.example` for the block it produces. 3. Build and run: @@ -100,6 +112,12 @@ docker compose logs -f planner docker compose logs -f reviewer ``` +5. (Optional) Send a test message that makes the planner ping the reviewer: + +```bash +uv run test_communication.py +``` + ## Configuration ### `.env` @@ -118,14 +136,17 @@ docker compose logs -f reviewer ### `agent_config.yaml` -Use `repo` under both planner and reviewer: +Generated by `create_agents.py` — you don't normally edit it by hand. It's a +single combined file keyed by agent. The `repo` block is optional; omit it (the +default) for a chat-only stack. To add a repo later, drop an identical `repo` +block under **both** agents: ```yaml planner: agent_id: "..." api_key: "..." role: planner - repo: + repo: # optional url: "git@github.com:org/repo.git" path: "/workspace/repo" branch: "main" @@ -134,7 +155,8 @@ planner: reviewer: agent_id: "..." api_key: "..." - repo: + role: reviewer + repo: # keep identical to planner.repo url: "git@github.com:org/repo.git" path: "/workspace/repo" branch: "main" @@ -143,7 +165,18 @@ reviewer: ## Troubleshooting -- `Config file not found`: create `agent_config.yaml` from the example. +- **`Config file is empty` / `IsADirectoryError` on `agent_config.yaml`**: a + stale empty `agent_config.yaml` **directory** exists (Docker auto-creates the + bind-mount source when the file is missing). Run `docker compose down`, then + `rm -rf agent_config.yaml && python create_agents.py` to regenerate the file + before `docker compose up`. +- `Config file not found`: run `create_agents.py` to generate `agent_config.yaml`. +- **`httpx.ConnectError: [Errno -2] Name or service not known` (crash loop)**: + `BAND_REST_URL`/`BAND_WS_URL` in `.env` point at an unreachable/misspelled + host. `create_agents.py` reads the same `.env`, so it registers the agents on + whatever `BAND_REST_URL` you set there (default `https://app.band.ai`) — fix + the value in `.env`, re-run `uv run create_agents.py` if the platform changed, + then `docker compose up -d --force-recreate`. - `Invalid repo configuration`: verify `repo.url` and absolute `repo.path`. - `Host not found in known_hosts`: add host key (`ssh-keyscan -H >> ~/.ssh/known_hosts`). - `Authentication failed` on clone: verify SSH keys or HTTPS token/credential helper. diff --git a/examples/coding_agents/create_agents.py b/examples/coding_agents/create_agents.py index 014556c14..2e3d62553 100644 --- a/examples/coding_agents/create_agents.py +++ b/examples/coding_agents/create_agents.py @@ -1,11 +1,32 @@ #!/usr/bin/env python3 -"""Create test agents for E2E testing. - -Registers planner and reviewer agents via User API -and writes their credentials to YAML config files. +# /// script +# requires-python = ">=3.11" +# dependencies = ["band-sdk>=1.2.0,<2.0.0"] +# /// +"""Register the planner + reviewer agents and write agent_config.yaml. + +Registers both agents via the Band User API and writes a single combined +``agent_config.yaml`` (keyed ``planner:``/``reviewer:``) — exactly the file +docker-compose.yml consumes. This replaces the old two-step "copy the example, +then paste credentials" flow, which left an empty ``agent_config.yaml`` +directory behind (Docker auto-creates the bind-mount source) and crashed both +containers. + +Platform selection: the script loads this directory's ``.env`` (the same file +Compose reads), so ``BAND_REST_URL`` there is the single source of truth for +which platform the agents are registered against. Set it once in ``.env``. Usage: - BAND_API_KEY=band_u_... python create_agents.py + BAND_API_KEY=band_u_... uv run create_agents.py + +Optional repo (agents clone + work on a shared git repo). Omit for a +chat-only stack that needs no GitHub/SSH: + REPO_URL=git@github.com:org/repo.git \ + REPO_BRANCH=main REPO_INDEX=true \ + BAND_API_KEY=band_u_... uv run create_agents.py + +Re-running registers NEW agents. To avoid orphaning the ones already in +agent_config.yaml, the script refuses to overwrite it unless FORCE=1. """ from __future__ import annotations @@ -13,8 +34,11 @@ import asyncio import logging import os +from pathlib import Path +from typing import Any import yaml +from dotenv import load_dotenv from band import LoggingStyle, LogSettings @@ -26,76 +50,178 @@ logger = logging.getLogger(__name__) AGENTS = [ - {"name": "Planner", "role": "planner", "file": "planner.yaml"}, - {"name": "Reviewer", "role": "reviewer", "file": "reviewer.yaml"}, + {"name": "Planner", "role": "planner", "key": "planner"}, + {"name": "Reviewer", "role": "reviewer", "key": "reviewer"}, ] +SCRIPT_DIR = Path(__file__).resolve().parent +ENV_PATH = SCRIPT_DIR / ".env" +CONFIG_PATH = SCRIPT_DIR / "agent_config.yaml" +CLEANUP_PATH = SCRIPT_DIR / ".agent_ids.txt" + +CONFIG_HEADER = """\ +# Combined agent credentials for the coding_agents Docker Compose stack. +# Generated by create_agents.py. NEVER commit real credentials. +# +# Keys must match the runner AGENT_KEY: +# planner -> AGENT_KEY=planner (compose service "planner") +# reviewer -> REVIEWER_AGENT_KEY=reviewer (compose service "reviewer") +# +# No `repo:` block => the agents boot and coordinate over chat without cloning +# anything (no GitHub/SSH needed). Set REPO_URL when running this script, or add +# an identical `repo:` block under each agent by hand — see +# agent_config.yaml.example for the template. +""" + + +def env_flag(name: str, *, default: bool = False) -> bool: + """Read a truthy env flag (``1``/``true``/``yes``), or *default* if unset.""" + raw = os.environ.get(name) + if raw is None: + return default + return raw.strip().lower() in ("1", "true", "yes") + + +def build_repo_block() -> dict[str, Any] | None: + """Build an optional repo block from REPO_* env vars, or None if unset.""" + url = os.environ.get("REPO_URL", "").strip() + if not url: + return None + + repo: dict[str, Any] = { + "url": url, + "path": os.environ.get("REPO_PATH", "/workspace/repo").strip(), + } + branch = os.environ.get("REPO_BRANCH", "").strip() + if branch: + repo["branch"] = branch + repo["index"] = env_flag("REPO_INDEX", default=True) + return repo + + +def config_write_blocked_reason() -> str | None: + """Explain why ``agent_config.yaml`` can't be safely written, else ``None``. + + Called BEFORE any agent is registered, so we never create agents we then + can't record. ``is_file()`` is deliberately avoided: it returns ``False`` + for a stale ``agent_config.yaml`` *directory* (Docker auto-creates the + bind-mount source as one when the file is missing — the exact state this + stack recovers from), which would let registration run and only crash later + at ``write_text``. + """ + if CONFIG_PATH.is_dir(): + return ( + f"{CONFIG_PATH.name} is a directory. Docker auto-creates the bind-mount " + "source as an empty directory when the file is missing — the exact state " + "this stack must recover from. Run `docker compose down`, then " + f"`rm -rf {CONFIG_PATH.name}` and re-run this script." + ) + if CONFIG_PATH.exists() and not env_flag("FORCE"): + return ( + f"{CONFIG_PATH.name} already exists. Re-running registers NEW Band agents " + "and would orphan the ones referenced there. Delete it (and clean up the " + f"agents listed in {CLEANUP_PATH.name}), or set FORCE=1 to overwrite." + ) + return None + + +def append_cleanup_id(agent_id: str) -> None: + """Append a freshly registered agent id to the cleanup ledger immediately. + + Written per-agent (append, not overwrite) so a failure part-way through + registration — or a FORCE re-run — never orphans an already-created agent: + every id ever registered stays recorded for teardown. + """ + with open(CLEANUP_PATH, "a", encoding="utf-8") as f: + f.write(f"{agent_id}\n") + + +def write_config(config: dict[str, Any]) -> None: + """Write the combined, keyed ``agent_config.yaml`` that Compose consumes.""" + body = yaml.dump(config, default_flow_style=False, sort_keys=False) + CONFIG_PATH.write_text(f"{CONFIG_HEADER}\n{body}", encoding="utf-8") + logger.info("\nWrote combined config: %s", CONFIG_PATH.name) + + +def log_summary( + created: list[dict[str, str]], + repo_block: dict[str, Any] | None, + base_url: str, +) -> None: + """Print the registration summary and the next-step setup instructions.""" + logger.info("Agent IDs recorded in %s for cleanup", CLEANUP_PATH.name) + logger.info("\n=== Summary ===") + for a in created: + logger.info("%s: id=%s, role=%s", a["name"], a["id"], a["role"]) + logger.info( + "\nRepo: %s", repo_block["url"] if repo_block else "none (chat-only, no clone)" + ) + logger.info("Registered against: %s", base_url) + logger.info( + "IMPORTANT: BAND_REST_URL in .env (%s) is the platform these agents live on; " + "the containers must use the same one to find them.", + base_url, + ) + logger.info("\nNext: docker compose build && docker compose up -d") + async def main() -> None: + # Load this directory's .env first, so BAND_REST_URL matches the platform + # Compose connects to (Compose reads the same .env via env_file). + load_dotenv(ENV_PATH) + api_key = os.environ.get("BAND_API_KEY") if not api_key: raise ValueError("BAND_API_KEY environment variable is required") + blocked = config_write_blocked_reason() + if blocked: + raise ValueError(blocked) + base_url = os.environ.get("BAND_REST_URL", "https://app.band.ai") - from band_rest import AsyncRestClient + from band.client.rest import AsyncRestClient, DEFAULT_REQUEST_OPTIONS from band_rest.types import AgentRegisterRequest client = AsyncRestClient(api_key=api_key, base_url=base_url) - created = [] - script_dir = os.path.dirname(os.path.abspath(__file__)) + repo_block = build_repo_block() + config: dict[str, Any] = {} + created: list[dict[str, str]] = [] for agent_def in AGENTS: logger.info("Creating agent: %s ...", agent_def["name"]) response = await client.human_api_agents.register_my_agent( agent=AgentRegisterRequest( name=agent_def["name"], - description=f"E2E test agent - {agent_def['role']} role", - ) + description=f"coding_agents example - {agent_def['role']} role", + ), + request_options=DEFAULT_REQUEST_OPTIONS, ) agent = response.data.agent credentials = response.data.credentials - + # Persist the id before anything else can fail (a later agent's + # registration, or the config write): a partial run stays cleanable. + append_cleanup_id(agent.id) logger.info(" Created: %s (ID: %s)", agent.name, agent.id) - # Omit `model` so the runner falls back to None and the npm `claude` - # binary picks its own default. Override per agent by adding - # `"model": "opus"` (or any alias / pinned ID) below. - config = { + # Omit `model` so each runner falls back to its own default (the npm + # `claude` binary / codex pick their default). Add a `model:` key here + # to pin one. + section: dict[str, Any] = { "agent_id": agent.id, "api_key": credentials.api_key, "role": agent_def["role"], } + if repo_block is not None: + section["repo"] = dict(repo_block) - config_path = os.path.join(script_dir, agent_def["file"]) - with open(config_path, "w") as f: - yaml.dump(config, f, default_flow_style=False) - logger.info(" Config written to: %s", agent_def["file"]) - - created.append( - { - "name": agent.name, - "id": agent.id, - "api_key": credentials.api_key, - "role": agent_def["role"], - "file": agent_def["file"], - } - ) - - logger.info("\n=== Summary ===") - for a in created: - logger.info( - "%s: id=%s, role=%s, config=%s", a["name"], a["id"], a["role"], a["file"] - ) + config[agent_def["key"]] = section + created.append({"name": agent.name, "id": agent.id, "role": agent_def["role"]}) - # Write agent IDs to a cleanup file for later deletion - cleanup_path = os.path.join(script_dir, ".agent_ids.txt") - with open(cleanup_path, "w") as f: - for a in created: - f.write(f"{a['id']}\n") - logger.info("\nAgent IDs saved to .agent_ids.txt for cleanup") + write_config(config) + log_summary(created, repo_block, base_url) if __name__ == "__main__": diff --git a/examples/coding_agents/test_communication.py b/examples/coding_agents/test_communication.py index 6588ec71f..c5ceb129e 100644 --- a/examples/coding_agents/test_communication.py +++ b/examples/coding_agents/test_communication.py @@ -1,11 +1,19 @@ #!/usr/bin/env python3 +# /// script +# requires-python = ">=3.11" +# dependencies = ["band-sdk>=1.2.0,<2.0.0"] +# /// """Test inter-agent communication between planner and reviewer. -Creates a chat room, adds all 3 agents, sends a test message, -and verifies delivery by checking container logs. +Creates a chat room, adds the reviewer, sends a test message mentioning it, +and lists the room messages so you can confirm delivery. + +Reads credentials from the combined agent_config.yaml written by +create_agents.py, and this directory's .env (the same file Compose reads) for +BAND_REST_URL — so this script targets the same platform as the running stack. Usage: - python test_communication.py + uv run test_communication.py """ from __future__ import annotations @@ -13,10 +21,9 @@ import asyncio import logging import os -import sys from pathlib import Path -import yaml +from dotenv import load_dotenv from band import LoggingStyle, LogSettings @@ -27,19 +34,13 @@ ) logger = logging.getLogger(__name__) -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../..")) - -SCRIPT_DIR = Path(__file__).parent - - -def load_agent_config(filename: str) -> dict: - """Load agent config from YAML file.""" - path = SCRIPT_DIR / filename - with open(path) as f: - return yaml.safe_load(f) +SCRIPT_DIR = Path(__file__).resolve().parent +ENV_PATH = SCRIPT_DIR / ".env" +CONFIG_PATH = SCRIPT_DIR / "agent_config.yaml" async def main() -> None: + from band.config import load_agent_config from band_rest import AsyncRestClient from band_rest.types import ( ChatMessageRequest, @@ -48,14 +49,19 @@ async def main() -> None: ParticipantRequest, ) - # Load agent configs - planner = load_agent_config("planner.yaml") - reviewer = load_agent_config("reviewer.yaml") + # Match the platform Compose connects to (Compose reads the same .env). + load_dotenv(ENV_PATH) + + # Load agent credentials from the combined file create_agents.py writes. + # load_agent_config validates the file exists and the required fields are + # present, and understands the keyed (planner:/reviewer:) format. + _, planner_key = load_agent_config("planner", config_path=CONFIG_PATH) + reviewer_id, _ = load_agent_config("reviewer", config_path=CONFIG_PATH) base_url = os.environ.get("BAND_REST_URL", "https://app.band.ai") # Use planner as the "orchestrator" to create the room - client = AsyncRestClient(api_key=planner["api_key"], base_url=base_url) + client = AsyncRestClient(api_key=planner_key, base_url=base_url) # Step 1: Create a chat room logger.info("Creating chat room...") @@ -67,13 +73,12 @@ async def main() -> None: logger.info(" Room created: %s", room_id) # Step 2: Add reviewer as participant - for name, agent_config in [("Reviewer", reviewer)]: - logger.info("Adding %s to room...", name) - await client.agent_api_participants.add_agent_chat_participant( - chat_id=room_id, - participant=ParticipantRequest(participant_id=agent_config["agent_id"]), - ) - logger.info(" %s added", name) + logger.info("Adding Reviewer to room...") + await client.agent_api_participants.add_agent_chat_participant( + chat_id=room_id, + participant=ParticipantRequest(participant_id=reviewer_id), + ) + logger.info(" Reviewer added") # Give agents time to join the room via WebSocket logger.info("Waiting for agents to join room...") @@ -83,7 +88,7 @@ async def main() -> None: logger.info("Sending test message...") mentions = [ ChatMessageRequestMentionsItem( - id=reviewer["agent_id"], + id=reviewer_id, name="Reviewer", ), ] diff --git a/examples/copilot_sdk/01_basic_agent.py b/examples/copilot_sdk/01_basic_agent.py index 0f4726123..58b0dd05b 100644 --- a/examples/copilot_sdk/01_basic_agent.py +++ b/examples/copilot_sdk/01_basic_agent.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[copilot_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[copilot_sdk]>=1.5.0,<2.0.0"] # /// """ Basic GitHub Copilot SDK Agent Example. diff --git a/examples/copilot_sdk/02_byok_anthropic.py b/examples/copilot_sdk/02_byok_anthropic.py index 3a0bdc501..6589ff42a 100644 --- a/examples/copilot_sdk/02_byok_anthropic.py +++ b/examples/copilot_sdk/02_byok_anthropic.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[copilot_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[copilot_sdk]>=1.5.0,<2.0.0"] # /// """ Copilot SDK Agent with BYOK (bring your own key) — Anthropic provider. diff --git a/examples/copilot_sdk/03_tom_agent.py b/examples/copilot_sdk/03_tom_agent.py index bfa019eb2..3a9f5e03b 100644 --- a/examples/copilot_sdk/03_tom_agent.py +++ b/examples/copilot_sdk/03_tom_agent.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[copilot_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[copilot_sdk]>=1.5.0,<2.0.0"] # /// """ Tom the cat agent - tries to catch Jerry! diff --git a/examples/copilot_sdk/04_jerry_agent.py b/examples/copilot_sdk/04_jerry_agent.py index be5056a89..2a86dcc1f 100644 --- a/examples/copilot_sdk/04_jerry_agent.py +++ b/examples/copilot_sdk/04_jerry_agent.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[copilot_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[copilot_sdk]>=1.5.0,<2.0.0"] # /// """ Jerry the mouse agent - outsmarts Tom! diff --git a/examples/copilot_sdk/05_contact_and_memory_agent.py b/examples/copilot_sdk/05_contact_and_memory_agent.py index 24f1fd62d..2c5761719 100644 --- a/examples/copilot_sdk/05_contact_and_memory_agent.py +++ b/examples/copilot_sdk/05_contact_and_memory_agent.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[copilot_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[copilot_sdk]>=1.5.0,<2.0.0"] # /// """ Copilot SDK agent with contact and memory tools enabled. diff --git a/examples/copilot_sdk/06_ask_user.py b/examples/copilot_sdk/06_ask_user.py index 57f42285f..eaade3a72 100644 --- a/examples/copilot_sdk/06_ask_user.py +++ b/examples/copilot_sdk/06_ask_user.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[copilot_sdk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[copilot_sdk]>=1.5.0,<2.0.0"] # /// """ Human-in-the-loop via Copilot's ``ask_user`` tool, answered in the room. diff --git a/examples/crewai/01_basic_agent.py b/examples/crewai/01_basic_agent.py index ceef230d0..6409461e4 100644 --- a/examples/crewai/01_basic_agent.py +++ b/examples/crewai/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ Basic CrewAI agent example. diff --git a/examples/crewai/02_role_based_agent.py b/examples/crewai/02_role_based_agent.py index 027c459ad..9ddbc4e98 100644 --- a/examples/crewai/02_role_based_agent.py +++ b/examples/crewai/02_role_based_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ CrewAI agent with role, goal, and backstory. diff --git a/examples/crewai/03_coordinator_agent.py b/examples/crewai/03_coordinator_agent.py index 28469da70..57ea2ce15 100644 --- a/examples/crewai/03_coordinator_agent.py +++ b/examples/crewai/03_coordinator_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ CrewAI coordinator agent for multi-agent orchestration. diff --git a/examples/crewai/04_research_crew.py b/examples/crewai/04_research_crew.py index 57a723e2a..be26773dc 100644 --- a/examples/crewai/04_research_crew.py +++ b/examples/crewai/04_research_crew.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ Complete CrewAI-style crew with multiple specialized agents. diff --git a/examples/crewai/05_tom_agent.py b/examples/crewai/05_tom_agent.py index 2c07d8cf2..e5b4b17f5 100644 --- a/examples/crewai/05_tom_agent.py +++ b/examples/crewai/05_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent using CrewAI. diff --git a/examples/crewai/06_jerry_agent.py b/examples/crewai/06_jerry_agent.py index 67577beeb..e1abe5098 100644 --- a/examples/crewai/06_jerry_agent.py +++ b/examples/crewai/06_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent using CrewAI. diff --git a/examples/crewai/07_contact_and_memory_agent.py b/examples/crewai/07_contact_and_memory_agent.py index 687b676c0..c9bb4422c 100644 --- a/examples/crewai/07_contact_and_memory_agent.py +++ b/examples/crewai/07_contact_and_memory_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ CrewAI agent with contact and memory tools enabled. diff --git a/examples/crewai/08_flow_router.py b/examples/crewai/08_flow_router.py index 3dc070576..aaa3ca90a 100644 --- a/examples/crewai/08_flow_router.py +++ b/examples/crewai/08_flow_router.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """CrewAI Flow router example. diff --git a/examples/crewai/09_flow_custom_tools.py b/examples/crewai/09_flow_custom_tools.py index 377f7e8ec..aa83e6622 100644 --- a/examples/crewai/09_flow_custom_tools.py +++ b/examples/crewai/09_flow_custom_tools.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """CrewAI Flow custom tools example. diff --git a/examples/crewai/10_memory_tool_usage.py b/examples/crewai/10_memory_tool_usage.py index f50d8bbac..e43554ebe 100644 --- a/examples/crewai/10_memory_tool_usage.py +++ b/examples/crewai/10_memory_tool_usage.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ CrewAI agent with memory tools enabled. diff --git a/examples/docker_demo/conductor.py b/examples/docker_demo/conductor.py index ed061e7e0..e3b931b41 100644 --- a/examples/docker_demo/conductor.py +++ b/examples/docker_demo/conductor.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk>=1.2.0,<2.0.0"] # /// """Host-side conductor + circuit breaker for the three-agent Docker demo. diff --git a/examples/docker_demo/provision.py b/examples/docker_demo/provision.py index 060eefd49..045a5a584 100644 --- a/examples/docker_demo/provision.py +++ b/examples/docker_demo/provision.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk>=1.2.0,<2.0.0"] # /// """Provision (and tear down) the three demo agents on the Band platform. diff --git a/examples/gemini/01_basic_agent.py b/examples/gemini/01_basic_agent.py index 4c0cc3699..039fa0516 100644 --- a/examples/gemini/01_basic_agent.py +++ b/examples/gemini/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[gemini]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[gemini]>=1.2.0,<2.0.0"] # /// """ Basic Gemini agent example. diff --git a/examples/google_adk/01_basic_agent.py b/examples/google_adk/01_basic_agent.py index 594bff1cb..fece140dc 100644 --- a/examples/google_adk/01_basic_agent.py +++ b/examples/google_adk/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[google_adk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[google_adk]>=1.2.0,<2.0.0"] # /// """ Basic Google ADK agent example. diff --git a/examples/google_adk/02_custom_instructions.py b/examples/google_adk/02_custom_instructions.py index 50833507a..ce2a438ad 100644 --- a/examples/google_adk/02_custom_instructions.py +++ b/examples/google_adk/02_custom_instructions.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[google_adk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[google_adk]>=1.2.0,<2.0.0"] # /// """ Google ADK agent with custom instructions and model selection. diff --git a/examples/google_adk/03_custom_tools.py b/examples/google_adk/03_custom_tools.py index bb681bb8d..e07cbd572 100644 --- a/examples/google_adk/03_custom_tools.py +++ b/examples/google_adk/03_custom_tools.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[google_adk]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[google_adk]>=1.2.0,<2.0.0"] # /// """ Google ADK agent with custom tools. diff --git a/examples/langgraph/01_simple_agent.py b/examples/langgraph/01_simple_agent.py index 49e1b35b6..a964a9745 100644 --- a/examples/langgraph/01_simple_agent.py +++ b/examples/langgraph/01_simple_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Simple LangGraph agent example using the composition API. diff --git a/examples/langgraph/02_custom_tools.py b/examples/langgraph/02_custom_tools.py index 0810c2b6e..4cb77c008 100644 --- a/examples/langgraph/02_custom_tools.py +++ b/examples/langgraph/02_custom_tools.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Example showing how to add custom tools to a Band agent. diff --git a/examples/langgraph/03_custom_personality.py b/examples/langgraph/03_custom_personality.py index 0517cb629..9400280a1 100644 --- a/examples/langgraph/03_custom_personality.py +++ b/examples/langgraph/03_custom_personality.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Example showing how to customize agent personality with custom instructions. diff --git a/examples/langgraph/04_calculator_as_tool.py b/examples/langgraph/04_calculator_as_tool.py index 5dd5ba2e6..82a176cd8 100644 --- a/examples/langgraph/04_calculator_as_tool.py +++ b/examples/langgraph/04_calculator_as_tool.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Example: Using graph_as_tool to wrap a standalone graph as a tool. diff --git a/examples/langgraph/05_rag_as_tool.py b/examples/langgraph/05_rag_as_tool.py index 74617b2d8..4bc908ed8 100644 --- a/examples/langgraph/05_rag_as_tool.py +++ b/examples/langgraph/05_rag_as_tool.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Example: Using the standalone Agentic RAG graph with Band platform. diff --git a/examples/langgraph/06_delegate_to_sql_agent.py b/examples/langgraph/06_delegate_to_sql_agent.py index e75557c0b..830a198eb 100644 --- a/examples/langgraph/06_delegate_to_sql_agent.py +++ b/examples/langgraph/06_delegate_to_sql_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Example: Hierarchical agents with graph_as_tool. diff --git a/examples/langgraph/07_tom_agent.py b/examples/langgraph/07_tom_agent.py index ad8b6f228..76143f2c0 100644 --- a/examples/langgraph/07_tom_agent.py +++ b/examples/langgraph/07_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent using LangGraph. diff --git a/examples/langgraph/08_jerry_agent.py b/examples/langgraph/08_jerry_agent.py index 2dd1db1db..21dd4ee64 100644 --- a/examples/langgraph/08_jerry_agent.py +++ b/examples/langgraph/08_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent using LangGraph. diff --git a/examples/langgraph/09_research_ops_orchestrator.py b/examples/langgraph/09_research_ops_orchestrator.py index 8508eb2fd..aa2951f2b 100644 --- a/examples/langgraph/09_research_ops_orchestrator.py +++ b/examples/langgraph/09_research_ops_orchestrator.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ Custom LangGraph orchestrator with platform tools and subgraph delegation. diff --git a/examples/langgraph/10_memory_tool_usage.py b/examples/langgraph/10_memory_tool_usage.py index 0dcc980b8..02bff47ce 100644 --- a/examples/langgraph/10_memory_tool_usage.py +++ b/examples/langgraph/10_memory_tool_usage.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ LangGraph agent with memory tools enabled. diff --git a/examples/langgraph/11_no_llm_graph.py b/examples/langgraph/11_no_llm_graph.py index 4d917c78e..ca321501e 100644 --- a/examples/langgraph/11_no_llm_graph.py +++ b/examples/langgraph/11_no_llm_graph.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[langgraph]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/thenvoi/thenvoi-sdk-python.git" } +# dependencies = ["band-sdk[langgraph]>=1.2.0,<2.0.0"] # /// """ LangGraph agent with no LLM inside — a deterministic ping/pong graph. diff --git a/examples/letta/01_basic_agent.py b/examples/letta/01_basic_agent.py index b9979ba04..4c83e26cd 100644 --- a/examples/letta/01_basic_agent.py +++ b/examples/letta/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[letta]", "pydantic-settings", "python-dotenv"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[letta]>=1.2.0,<2.0.0", "pydantic-settings", "python-dotenv"] # /// """ Basic Letta agent example. diff --git a/examples/mixed/01_strategy_coordinator.py b/examples/mixed/01_strategy_coordinator.py index acbf2e6cf..0c3b93567 100644 --- a/examples/mixed/01_strategy_coordinator.py +++ b/examples/mixed/01_strategy_coordinator.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ Mixed-example CrewAI coordinator. diff --git a/examples/mixed/02_draft_writer.py b/examples/mixed/02_draft_writer.py index 5fce20005..07827d8c6 100644 --- a/examples/mixed/02_draft_writer.py +++ b/examples/mixed/02_draft_writer.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[crewai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[crewai]>=1.2.0,<2.0.0"] # /// """ Mixed-example CrewAI writer. diff --git a/examples/mixed/03_fact_checker_a2a.py b/examples/mixed/03_fact_checker_a2a.py index 98f3118a2..21a9ff396 100644 --- a/examples/mixed/03_fact_checker_a2a.py +++ b/examples/mixed/03_fact_checker_a2a.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[a2a_gateway]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[a2a_gateway]>=1.2.0,<2.0.0"] # /// """ Remote A2A fact checker for the mixed example. diff --git a/examples/mixed/04_risk_reviewer_a2a.py b/examples/mixed/04_risk_reviewer_a2a.py index 29b8a922b..fc3ea545d 100644 --- a/examples/mixed/04_risk_reviewer_a2a.py +++ b/examples/mixed/04_risk_reviewer_a2a.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[a2a_gateway]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[a2a_gateway]>=1.2.0,<2.0.0"] # /// """ Remote A2A risk reviewer for the mixed example. diff --git a/examples/mixed/05_a2a_bridge.py b/examples/mixed/05_a2a_bridge.py index de31880fc..8d3180e04 100644 --- a/examples/mixed/05_a2a_bridge.py +++ b/examples/mixed/05_a2a_bridge.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[a2a]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[a2a]>=1.2.0,<2.0.0"] # /// """ Mixed-example bridge launcher. diff --git a/examples/opencode/01_basic_agent.py b/examples/opencode/01_basic_agent.py index fa6335eda..c84d868d2 100644 --- a/examples/opencode/01_basic_agent.py +++ b/examples/opencode/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[opencode]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[opencode]>=1.2.0,<2.0.0"] # /// """ Basic OpenCode adapter agent example. diff --git a/examples/opencode/02_workspace_agent.py b/examples/opencode/02_workspace_agent.py index d43a4e263..01543061f 100644 --- a/examples/opencode/02_workspace_agent.py +++ b/examples/opencode/02_workspace_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[opencode]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[opencode]>=1.2.0,<2.0.0"] # /// """OpenCode coding agent scoped to one local workspace. diff --git a/examples/opencode/03_custom_tools_agent.py b/examples/opencode/03_custom_tools_agent.py index b24ff8904..3e16f6f04 100644 --- a/examples/opencode/03_custom_tools_agent.py +++ b/examples/opencode/03_custom_tools_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[opencode]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[opencode]>=1.2.0,<2.0.0"] # /// """OpenCode agent with application-defined tools. diff --git a/examples/opencode/04_memory_secretary.py b/examples/opencode/04_memory_secretary.py index 55d57d6c2..615bc3fab 100644 --- a/examples/opencode/04_memory_secretary.py +++ b/examples/opencode/04_memory_secretary.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[opencode]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[opencode]>=1.2.0,<2.0.0"] # /// """OpenCode agent with durable Band memory. diff --git a/examples/opencode/05_tom_agent.py b/examples/opencode/05_tom_agent.py index 1cd1b8408..841a8ac72 100644 --- a/examples/opencode/05_tom_agent.py +++ b/examples/opencode/05_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[opencode]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[opencode]>=1.2.0,<2.0.0"] # /// """Tom the cat, powered by OpenCode. diff --git a/examples/opencode/06_jerry_agent.py b/examples/opencode/06_jerry_agent.py index b70be031d..6ace4098a 100644 --- a/examples/opencode/06_jerry_agent.py +++ b/examples/opencode/06_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[opencode]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[opencode]>=1.2.0,<2.0.0"] # /// """Jerry the mouse, powered by OpenCode. diff --git a/examples/opentelemetry/pydantic_ai_agent.py b/examples/opentelemetry/pydantic_ai_agent.py index 634f871c1..27157f049 100644 --- a/examples/opentelemetry/pydantic_ai_agent.py +++ b/examples/opentelemetry/pydantic_ai_agent.py @@ -1,13 +1,10 @@ # /// script # requires-python = ">=3.11" # dependencies = [ -# "band-sdk[pydantic-ai,logging]", +# "band-sdk[pydantic-ai,logging]>=1.2.0,<2.0.0", # "opentelemetry-sdk>=1.44.0", # "opentelemetry-instrumentation-logging>=0.65b0", # ] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } # /// """ Band agent with host-owned OpenTelemetry: correlated logs and framework spans. diff --git a/examples/parlant/01_basic_agent.py b/examples/parlant/01_basic_agent.py index b538f72b9..03f200eed 100644 --- a/examples/parlant/01_basic_agent.py +++ b/examples/parlant/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[parlant,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[parlant,logging]>=1.2.0,<2.0.0"] # /// """ Basic Parlant agent example using the official Parlant SDK. diff --git a/examples/parlant/02_with_guidelines.py b/examples/parlant/02_with_guidelines.py index e76ff1aba..8082c9bd3 100644 --- a/examples/parlant/02_with_guidelines.py +++ b/examples/parlant/02_with_guidelines.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[parlant,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[parlant,logging]>=1.2.0,<2.0.0"] # /// """ Parlant agent with behavioral guidelines using the official Parlant SDK. diff --git a/examples/parlant/03_support_agent.py b/examples/parlant/03_support_agent.py index 4e320044f..eabc6f6ef 100644 --- a/examples/parlant/03_support_agent.py +++ b/examples/parlant/03_support_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[parlant,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[parlant,logging]>=1.2.0,<2.0.0"] # /// """ Customer support agent using Parlant SDK with guidelines. diff --git a/examples/parlant/04_tom_agent.py b/examples/parlant/04_tom_agent.py index 9f571fb95..e956f5118 100644 --- a/examples/parlant/04_tom_agent.py +++ b/examples/parlant/04_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[parlant,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[parlant,logging]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent using Parlant. diff --git a/examples/parlant/05_jerry_agent.py b/examples/parlant/05_jerry_agent.py index bc280db69..86640b071 100644 --- a/examples/parlant/05_jerry_agent.py +++ b/examples/parlant/05_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[parlant,logging]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[parlant,logging]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent using Parlant. diff --git a/examples/pydantic_ai/01_basic_agent.py b/examples/pydantic_ai/01_basic_agent.py index 7f05d5669..fcb9009f1 100644 --- a/examples/pydantic_ai/01_basic_agent.py +++ b/examples/pydantic_ai/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[pydantic-ai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[pydantic-ai]>=1.2.0,<2.0.0"] # /// """ Basic Pydantic AI agent example. diff --git a/examples/pydantic_ai/02_custom_instructions.py b/examples/pydantic_ai/02_custom_instructions.py index 806a8065c..af446602d 100644 --- a/examples/pydantic_ai/02_custom_instructions.py +++ b/examples/pydantic_ai/02_custom_instructions.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[pydantic-ai,anthropic]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[pydantic-ai,anthropic]>=1.2.0,<2.0.0"] # /// """ Agent with custom system prompt instructions. diff --git a/examples/pydantic_ai/03_tom_agent.py b/examples/pydantic_ai/03_tom_agent.py index 2688e67c0..9ccddb226 100644 --- a/examples/pydantic_ai/03_tom_agent.py +++ b/examples/pydantic_ai/03_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[pydantic-ai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[pydantic-ai]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent using Pydantic AI. diff --git a/examples/pydantic_ai/04_jerry_agent.py b/examples/pydantic_ai/04_jerry_agent.py index 8940ac748..cc5740fc9 100644 --- a/examples/pydantic_ai/04_jerry_agent.py +++ b/examples/pydantic_ai/04_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[pydantic-ai]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[pydantic-ai]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent using Pydantic AI. diff --git a/examples/run_agent.py b/examples/run_agent.py index b0efd73e8..65252f3a5 100644 --- a/examples/run_agent.py +++ b/examples/run_agent.py @@ -2,12 +2,9 @@ # /// script # requires-python = ">=3.11" # dependencies = [ -# "band-sdk[langgraph,anthropic,pydantic-ai,claude_sdk,parlant,crewai,a2a,codex]", +# "band-sdk[langgraph,anthropic,pydantic-ai,claude_sdk,parlant,crewai,a2a,codex]>=1.2.0,<2.0.0", # "python-dotenv>=1.1.1", # ] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } # /// """ Run Band SDK agents using the composition pattern. diff --git a/examples/slack/01_basic_bot.py b/examples/slack/01_basic_bot.py index 4439c07da..1b88e9464 100644 --- a/examples/slack/01_basic_bot.py +++ b/examples/slack/01_basic_bot.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[slack,anthropic]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[slack,anthropic]>=1.2.0,<2.0.0"] # /// """ Basic Slack bot: wrap an Anthropic brain with the SlackAdapter and diff --git a/examples/strands/01_basic_agent.py b/examples/strands/01_basic_agent.py index 1ac99e614..eeac066ef 100644 --- a/examples/strands/01_basic_agent.py +++ b/examples/strands/01_basic_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[strands]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[strands]>=1.2.0,<2.0.0"] # /// """ Basic Strands Agents example. diff --git a/examples/strands/02_custom_tools.py b/examples/strands/02_custom_tools.py index 9e1f299a3..78f16dea1 100644 --- a/examples/strands/02_custom_tools.py +++ b/examples/strands/02_custom_tools.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[strands]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[strands]>=1.2.0,<2.0.0"] # /// """ Strands agent with custom tools and capabilities. diff --git a/examples/strands/03_custom_instructions.py b/examples/strands/03_custom_instructions.py index 330b2a42b..b8213b01e 100644 --- a/examples/strands/03_custom_instructions.py +++ b/examples/strands/03_custom_instructions.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[strands]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[strands]>=1.2.0,<2.0.0"] # /// """ Strands agent with a fully custom system prompt. diff --git a/examples/strands/04_native_tools.py b/examples/strands/04_native_tools.py index e69308e46..cf0b7bbd4 100644 --- a/examples/strands/04_native_tools.py +++ b/examples/strands/04_native_tools.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[strands]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[strands]>=1.2.0,<2.0.0"] # /// """ Strands agent with framework-native tools. diff --git a/examples/strands/05_bedrock_model.py b/examples/strands/05_bedrock_model.py index f2b996525..101f3ff62 100644 --- a/examples/strands/05_bedrock_model.py +++ b/examples/strands/05_bedrock_model.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[strands]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[strands]>=1.2.0,<2.0.0"] # /// """ Strands agent on Amazon Bedrock. diff --git a/examples/strands/06_tom_agent.py b/examples/strands/06_tom_agent.py index b8c30361b..8d14bf665 100644 --- a/examples/strands/06_tom_agent.py +++ b/examples/strands/06_tom_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[strands]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[strands]>=1.2.0,<2.0.0"] # /// """ Tom the cat agent - tries to catch Jerry! diff --git a/examples/strands/07_jerry_agent.py b/examples/strands/07_jerry_agent.py index fba919519..ed24c054c 100644 --- a/examples/strands/07_jerry_agent.py +++ b/examples/strands/07_jerry_agent.py @@ -1,9 +1,6 @@ # /// script # requires-python = ">=3.11" -# dependencies = ["band-sdk[strands]"] -# -# [tool.uv.sources] -# band-sdk = { git = "https://github.com/band-ai/band-sdk-python.git" } +# dependencies = ["band-sdk[strands]>=1.2.0,<2.0.0"] # /// """ Jerry the mouse agent - outsmarts Tom!