The Strands Agents SDK, which was released as open source in May 2025, recently added TypeScript support as a public preview. Developers who prefer Python have had access to Strands since launch. Now TypeScript developers can build AI agents using the same model-driven approach, with full type safety and modern async patterns.
This article compares the Python and TypeScript implementations side by side, building a practical example along the way.
Because the Strands Agents TypeScript SDK is currently in public preview, APIs may change as the SDK is refined, and some features available in the Strands Agents Python SDK are not yet implemented. The core functionality—agents, tools, MCP integration, streaming—works as expected, but this is an early release. Feedback and contributions are welcome via the GitHub repository.
The Model-Driven Approach
Many agent frameworks are workflow-driven: you define explicit chains of actions where the agent does A, then B, then C. You're essentially programming the agent's behavior in advance. This works well for predictable tasks but becomes brittle when dealing with novel situations.
Strands Agents takes a different approach. Instead of prescribing steps, you give the agent a goal and a set of tools and let the LLM figure out how to accomplish the task. The model's reasoning capabilities—its ability to plan, reflect, and adapt—drive the behavior. This is what Strands calls the "model-driven" approach.
At the core of every Strands agent is the agent loop: the model receives context (conversation history, system prompt, tool descriptions), decides what to do next, optionally calls tools, observes the results, and repeats until it produces a final response.
flowchart LR
A[User Request] --> B[Agent]
B --> C{LLM Reasoning}
C --> D[Tool Calls]
D --> C
C --> E[Response]
For details on how this works, see the Agent Loop documentation.
Building a Task Planning Agent
Let's build something practical: an agent that helps break down a project into tasks. We'll give it two tools—one to add tasks and one to list them—and let it figure out how to help the user.
Defining Tools
The two Strands SDKs take different approaches to tool definition that reflect each language's idioms.
Python uses the @tool decorator with docstrings and type hints:
from strands import Agent, tool
tasks = []
@tool
def add_task(description: str, priority: str = "medium") -> str:
"""Add a task to the plan.
Args:
description: What needs to be done
priority: Priority level (high, medium, low)
"""
tasks.append({"description": description, "priority": priority})
return f"Added: {description} [{priority}]"
@tool
def list_tasks() -> str:
"""Show all tasks in the current plan."""
if not tasks:
return "No tasks yet."
return "\n".join(
f"- [{t['priority'].upper()}] {t['description']}"
for t in tasks
)
Strands extracts the tool specification from the function signature, type hints, and docstring automatically.
TypeScript uses Zod schemas:
import { Agent, tool } from '@strands-agents/sdk'
import { z } from 'zod'
const tasks: Array<{description: string, priority: string}> = []
const addTask = tool({
name: 'add_task',
description: 'Add a task to the plan.',
inputSchema: z.object({
description: z.string().describe('What needs to be done'),
priority: z.string().default('medium').describe('Priority level (high, medium, low)')
}),
callback: async (input) => {
tasks.push(input)
return `Added: ${input.description} [${input.priority}]`
}
})
const listTasks = tool({
name: 'list_tasks',
description: 'Show all tasks in the current plan.',
inputSchema: z.object({}),
callback: async () => {
if (tasks.length === 0) return 'No tasks yet.'
return tasks
.map(t => `- [${t.priority.toUpperCase()}] ${t.description}`)
.join('\n')
}
})
Zod is a TypeScript-first schema validation library that solves two problems at once: runtime validation and type inference. TypeScript's type system only works at compile time, but when your agent receives input from an LLM, you need runtime validation. Zod validates the data and automatically infers TypeScript types from your schema—define once, get both.
Creating and Running the Agent
Python:
agent = Agent(
system_prompt="You are a planning assistant. Help users break down projects into actionable tasks.",
tools=[add_task, list_tasks]
)
result = agent("Help me plan a surprise birthday party for next Saturday")
print(result.message)
TypeScript:
const agent = new Agent({
systemPrompt: 'You are a planning assistant. Help users break down projects into actionable tasks.',
tools: [addTask, listTasks]
})
const result = await agent.invoke('Help me plan a surprise birthday party for next Saturday')
console.log(result.message)
The agent will reason through what's needed—venue, guest list, food, decorations, timeline—call add_task multiple times with appropriate priorities, then call list_tasks to show the plan. You didn't program that sequence; the model figured it out.
Sample Output
I've created a plan for the surprise birthday party:
- [HIGH] Confirm venue and time for Saturday
- [HIGH] Create guest list and send invitations ASAP
- [HIGH] Arrange for someone to bring the birthday person to the venue
- [MEDIUM] Order or bake birthday cake
- [MEDIUM] Plan food and drinks menu
- [MEDIUM] Buy decorations (balloons, banner, etc.)
- [LOW] Create a party playlist
- [LOW] Plan games or activities
- [LOW] Arrange for someone to take photos
Given the short timeline, I've prioritized the items that need immediate action.
Would you like me to break any of these down further?
How the Two Languages Differ
The most visible difference is in tool definition. Python extracts schemas from docstrings and type hints—you write documentation as you normally would, and Strands uses it. TypeScript relies on Zod schemas, which provide both runtime validation and compile-time type inference in a single definition.
Invocation patterns also differ slightly. In Python, you call the agent directly with agent("prompt"), and async is optional. In TypeScript, you use await agent.invoke("prompt"), and async is the default model throughout. Both approaches describe the same thing to the LLM—they just do it in ways idiomatic to each language.
Streaming Responses
For interactive applications, both Strands SDKs support streaming so users see output as it's generated.
Python:
async for event in agent.stream_async("Plan a weekend hiking trip"):
if "data" in event:
print(event["data"], end="", flush=True)
TypeScript:
for await (const event of agent.stream('Plan a weekend hiking trip')) {
if (event.type === 'text') {
process.stdout.write(event.data)
}
}
Model Context Protocol (MCP)
The Model Context Protocol lets you connect agents to external tools and services. Both Strands SDKs have built-in MCP support.
Python:
from mcp import stdio_client, StdioServerParameters
from strands import Agent
from strands.tools.mcp import MCPClient
mcp_client = MCPClient(lambda: stdio_client(
StdioServerParameters(command="uvx", args=["awslabs.aws-documentation-mcp-server@latest"])
))
with mcp_client:
agent = Agent(tools=mcp_client.list_tools_sync())
agent("How do I configure an S3 bucket?")
TypeScript:
import { Agent, McpClient, StdioClientTransport } from '@strands-agents/sdk'
const mcpClient = new McpClient({
transport: new StdioClientTransport({
command: 'uvx',
args: ['awslabs.aws-documentation-mcp-server@latest']
})
})
const agent = new Agent({ tools: [mcpClient] })
await agent.invoke('How do I configure an S3 bucket?')
See the MCP Tools documentation for more transport options.
Beyond the Basics
The example above covers the core workflow, but both Strands SDKs offer more. Long-running conversations can exhaust the model's context window, so both provide conversation managers that automatically maintain a sliding window of recent messages. The Strands Agents Python SDK goes further with a summarizing conversation manager that compresses old messages rather than discarding them—useful when you need to preserve context over very long interactions.
For complex problems where a single agent isn't enough, the Strands Agents Python SDK provides multi-agent patterns. You can wrap specialized agents as tools that an orchestrator calls, create swarms where agents hand off tasks to each other autonomously, or define explicit graphs with deterministic execution order. These patterns aren't yet available in the TypeScript SDK. See the Multi-Agent Patterns documentation for details.
The Strands Agents Python SDK also supports structured output through Pydantic models, letting you constrain the agent's response to a specific schema. This is particularly useful when you need to parse the agent's output programmatically.
Feature Comparison
The table below summarizes what's available in each SDK. The Strands Agents Python SDK is stable with the full feature set, and the Strands Agents TypeScript SDK is in preview with core functionality available.
| Feature | Strands Python (stable) | Strands TypeScript (preview) |
|---|---|---|
| Core agent loop | ✅ | ✅ |
| Custom tools | ✅ (decorator) | ✅ (Zod) |
| MCP integration | ✅ | ✅ |
| Amazon Bedrock | ✅ | ✅ |
| OpenAI | ✅ | ✅ |
| Anthropic API | ✅ | — |
| Ollama | ✅ | — |
| Streaming | ✅ | ✅ |
| Conversation management | ✅ | ✅ |
| Structured output | ✅ | — |
| Multi-agent (Swarm/Graph) | ✅ | — |
| Community tools package | ✅ | — |
| Session persistence | ✅ | — |
| OpenTelemetry traces | ✅ | — |
When to Choose Which
The choice between SDKs often comes down to your existing stack and requirements. If your application is already in JavaScript or TypeScript and you're comfortable with preview-stage software, the Strands Agents TypeScript SDK gives you the core agent functionality with compile-time type safety and modern async patterns. It works in both Node.js and browser environments.
If you need the full feature set—multi-agent orchestration, structured output, more model providers, or the community tools package—the Strands Agents Python SDK is the more complete option for now.
Getting Started
Python:
uv init my-agent && cd my-agent
uv add strands-agents strands-agents-tools
TypeScript:
mkdir my-agent && cd my-agent
npm init -y
npm install @strands-agents/sdk zod
Both SDKs default to Amazon Bedrock as the model provider, which requires valid AWS credentials. If you're new to AWS, the AWS Free Tier provides $100 in credits at sign-up plus up to $100 more by completing onboarding activities— one of which involves using Amazon Bedrock. The free plan lasts six months, and you won't be charged unless you upgrade. See the Strands Agents Quickstart guide for setup details.
Resources
The Strands Agents documentation is the best starting point, with guides for both SDKs. The source code is available on GitHub for both the Python SDK and the TypeScript SDK. For Python, the community tools package provides ready-to-use tools, and the samples repository has complete example agents.
Wrapping Up
The Strands Agents TypeScript SDK brings the model-driven approach to the JavaScript ecosystem. While the Python SDK currently remains the fully featured option, the TypeScript preview delivers the core experience: define tools, create an agent, and let the model reason through problems.
The Strands Agents TypeScript SDK's preview status means now is a good time to experiment, provide feedback, and help shape its development.
Top comments (0)