Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
steps:
- uses: actions/checkout@v7

- uses: astral-sh/setup-uv@v9.0.0
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true

Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
steps:
- uses: actions/checkout@v7

- uses: astral-sh/setup-uv@v9.0.0
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
steps:
- uses: actions/checkout@v7

- uses: astral-sh/setup-uv@v9.0.0
- uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.env
.claude
.kiro/specs
.kiro/settings
.sessions
.converter
.hypothesis
Expand Down
2 changes: 1 addition & 1 deletion .kiro/skills/library-development/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ load it whenever you are unsure where something goes.
3. **The pipeline flows one way** — text -> dict -> validated schema -> live objects. Never resolve during parsing; never parse during resolution (see The Pipeline).
4. **Explicit over implicit** — no auto-registration, no global singletons, no hidden state. Every object is wired by hand and passed as an argument.
5. **Single responsibility** — each module does one thing; one resolver per config concept, one builder per orchestration mode.
6. **Composition over inheritance** — small functions and focused modules that compose. The only base classes are the strands-facing ones (`MCPServer`, `StreamConverter`, `HookProvider`).
6. **Composition over inheritance** — small functions and focused modules that compose. The only base classes are the strands-facing ones (`MCPServer`, `HookProvider`).
7. **Smallest reasonable change** — don't refactor unrelated code to land a feature.

---
Expand Down
3 changes: 1 addition & 2 deletions .kiro/skills/library-development/references/project-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,12 @@ src/strands_compose/
├── tools/
│ ├── loaders.py # resolve_tool_spec(s) — module/file/dir → AgentTool
│ ├── extractors.py # extract_last_message · serialize_multiagent_result
│ └── wrappers.py # node_as_tool / node_as_async_tool — wrap a node as a delegate tool
│ └── wrappers.py # multiagent_as_tool — wrap a Swarm/Graph as a delegate tool
├── hooks/ # reusable HookProvider implementations
│ ├── event_publisher.py # EventPublisher — strands hook events → StreamEvent (the key one)
│ ├── stop_guard.py # StopGuard / MultiAgentStopGuard — external cancel signal
│ ├── max_calls_guard.py # MaxToolCallsGuard — tool-call circuit breaker
│ └── tool_name_sanitizer.py# ToolNameSanitizer — repair model-mangled tool names
├── converters/ # StreamEvent → protocol chunks (base ABC · openai · raw)
├── renderers/ # terminal output (base ABC · ansi)
└── startup/ # opt-in health checks (validator.py) + report (report.py)
```
Expand Down
7 changes: 3 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# https://pre-commit.com
# https://pre-commit.com/hooks.html

# Use the active venv Python — avoids path issues on Windows where
# pre-commit looks for python3.12 at ~/.local/bin/python.exe
# Use the active venv Python
default_language_version:
python: python3

Expand All @@ -29,7 +28,7 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.15.20'
rev: 'v0.16.3'
hooks:
- id: ruff # lint — commit + push
- id: ruff-format # format — commit + push
Expand All @@ -42,7 +41,7 @@ repos:
files: \.(py|yaml|yml|md|toml|json|env)$

- repo: https://github.com/commitizen-tools/commitizen
rev: 'v4.16.4'
rev: 'v4.17.0'
hooks:
- id: commitizen # validates commit message format
stages: [commit-msg] # only on commit-msg event, not push
27 changes: 27 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@ subclasses.

---

## Response Style

Answer with a short executive summary. Lead with the answer or decision in the
first line.

- Direct question -> 1-3 sentences. Yes/no question -> start with yes or no.
- Expand only when asked for details, code, a full review, or a rationale.
- Prefer a compact table or 3-5 bullets over prose sections.
- Report the outcome, not the journey.

### Do not

- No multi-section reports, headers, or background unless requested.
- No narrating what was searched, read, or what sub-agents found.
- No restating earlier turns, no recaps of prior decisions.
- No storytelling, no "what settled it" / "where I was wrong" essays when one line will do.
- No praise, filler, or hedging.

### Still required

Brevity never overrides correctness. Keep these even when short:

- State uncertainty plainly, and say what was verified vs assumed.
- Correct a wrong earlier statement if it would change a decision.
- Flag risk before a destructive or hard-to-reverse action.


## Read the Skill First — MANDATORY

Before touching any code, load the skill for the area you are working in. Skills
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Strands Compose is an ecosystem that includes the following packages:
|-------|---------|-------------|
| **Define the agents** | [**strands-compose**](https://github.com/strands-compose/sdk-python) | Developers |
| Run / deploy the agents | [strands-compose-agentcore](https://github.com/strands-compose/bedrock-agentcore) | Developers, operations |
|*Put the agents in front of people | [strands-compose-chat](https://github.com/strands-compose/chat-ui) | **End users** |
|Put the agents in front of people | [strands-compose-chat](https://github.com/strands-compose/chat) | **End users** |

---

Expand Down
5 changes: 4 additions & 1 deletion docs/configuration/Chapter_10.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ orchestrations:
entry: team
```

**How it works**: strands-compose **forks** a new agent from the `entry_name` agent's blueprint (model, system_prompt, hooks, tools) and adds delegate tools for each connection. The original `coordinator` agent is **never mutated**. Each connection becomes an async tool that the coordinator can call.
**How it works**: strands-compose **forks** a new agent from the `entry_name` agent's blueprint (model, system_prompt, hooks, tools) and adds delegate tools for each connection. The original `coordinator` agent is **never mutated**.

> **Two limits.** A delegate cannot be called twice concurrently — the second call comes back as a tool error, so declare a second agent to fan out. And an interrupt (such as an approval) can be answered and resumed only for an agent connection; raised inside a nested Swarm or Graph it reaches the coordinator as a tool error.

**Fields**:

Expand All @@ -54,6 +56,7 @@ entry: team
| `connections` | list | Yes | Sub-agents to wire as tools |
| `connections[].agent` | string | Yes | Name of the target agent or orchestration |
| `connections[].description` | string | Yes | Tool description the LLM sees |
| `connections[].preserve_context` | bool | No | Keep the delegate's history between calls (default `true`). Set `false` for a stateless delegate that starts from its construction-time baseline every call. Rejected for a nested orchestration, or for an agent carrying a session manager |
| `session_manager` | dict | No | Override session manager for the forked agent |
| `hooks` | list | No | Additional hooks for the forked agent |
| `agent_kwargs` | dict | No | Override agent kwargs (merged with entry agent's kwargs) |
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/Chapter_12.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ entry: manager
1. strands-compose collects all orchestration dependencies.
2. It performs a **topological sort** — inner orchestrations are built before outer ones.
3. Built orchestrations become nodes in the node pool, available for outer orchestrations to reference.
4. For delegate mode, inner orchestrations are wrapped as async tools (just like regular agents).
4. For delegate mode, inner orchestrations become callable tools on the coordinator.

## Circular Dependencies

Expand Down
4 changes: 2 additions & 2 deletions examples/12_streaming/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ bracketing all per-agent activity.
`invoke_async` so both the agent and the queue consumer share the same event loop.

**`AnsiRenderer` is optional.** It's a convenience for terminals. In production you'd
consume the queue and convert events to SSE chunks (see `OpenAIStreamConverter`) or
NDJSON (`RawStreamConverter`).
consume the queue and serialize each event into whatever wire format your transport
needs — SSE chunks, NDJSON, or your own envelope.

**`queue.flush()`** resets the queue between turns so events from one invocation
don't leak into the next. It also resets the `session_start` / `session_end` guards.
Expand Down
20 changes: 10 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"strands-agents>=1.48.0,<2.0.0",
"strands-agents>=1.52.0,<2.0.0",
"pydantic>=2.12.5",
"pyyaml>=6.0.0",
"mcp>=1.24.0",
Expand All @@ -36,16 +36,16 @@ agentcore-memory = [
"bedrock-agentcore>=1.4.0",
]
ollama = [
"strands-agents[ollama]>=1.48.0,<2.0.0",
"strands-agents[ollama]>=1.52.0,<2.0.0",
]
openai = [
"strands-agents[openai]>=1.48.0,<2.0.0",
"strands-agents[openai]>=1.52.0,<2.0.0",
]
gemini = [
"strands-agents[gemini]>=1.48.0,<2.0.0",
"strands-agents[gemini]>=1.52.0,<2.0.0",
]
anthropic = [
"strands-agents[anthropic]>=1.48.0,<2.0.0",
"strands-agents[anthropic]>=1.52.0,<2.0.0",
]

[project.urls]
Expand All @@ -57,16 +57,16 @@ Changelog = "https://github.com/strands-compose/sdk-python/blob/main/CHANGELOG.m

[dependency-groups]
dev = [
"ty>=0.0.29",
"ty>=0.0.72",
"bandit>=1.9.2",
"coverage>=7.12.0",
"coverage>=7.15.4",
"pytest-asyncio>=1.2.0",
"pytest-cov>=7.0.0",
"pytest-mock>=3.15.1",
"pytest-xdist>=3.8.0",
"pytest>=9.0.2",
"ruff>=0.14.8",
"rust-just>=1.42.4",
"pytest>=9.1.1",
"ruff>=0.16.3",
"rust-just>=1.58.0",
"commitizen>=4.8.4",
"pre-commit>=4.3.0",
"hypothesis>=6.155.7",
Expand Down
6 changes: 2 additions & 4 deletions src/strands_compose/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
from .mcp import MCPLifecycle, create_mcp_client, create_mcp_server
from .renderers import AnsiRenderer
from .tools import (
node_as_async_tool,
node_as_tool,
multiagent_as_tool,
serialize_multiagent_result,
)
from .types import EventType, StreamEvent
Expand Down Expand Up @@ -59,8 +58,7 @@
"load_config",
"load_session",
"make_event_queue",
"node_as_async_tool",
"node_as_tool",
"multiagent_as_tool",
"resolve_infra",
"serialize_multiagent_result",
]
Loading