TypeScript開発者待望?! Strands Agents TypeScript SDKを試してみた!
はじめに
皆さん、こんにちは!
今ラスベガスで何が行われているかご存知ですか??
そう、 AWS re:Invent の真っ最中です!!
毎年めちゃくちゃ多くのアップデートが発表されるのですが、その中でStrands AgentsのTypeScript SDKが発表されましたー!!!
TypeScript 愛用者でAI Agentを開発している人には朗報ですね!!
これまで TypeScriptを使って AI Agentを開発するとなると Mastra か LangGraph、LangChain とかを使っている方が多かったはずです。
でもStrands Agents のTypeScript SDKが登場したことで新たな選択肢として加わってきそうです!!
今回はそのTypeScript SDKを早速試してみましたので記事にしてみました!
ぜひ最後まで読んで行ってください!
Strands Agentsとは
Strands AgentsとはAWS発のAI Agent開発用フレームワークです!!
モデル設定がデフォルトで設定されているのでたった数行でAI Agentを実装することができるようになっています!!
本当に10行ぐらいとかで作れます!!
みのるんさんやmoritalousさんの記事でも簡単に実装できることが特徴として紹介されていました。
登場した当時、自分も触ってみたい! と思っていたのですが、
「Python しかSDKが無いのか....」
ということであまり積極的には触れてきませんでした...。
そんなこんなで Mastra と出会ってしまっていたのでそっちを調べることばかりしてしまってなかなか触れませんでした..
でもとうとうTypeScriptのSDKが出ました!
これは触るしかない!!
Strands Agents TypeScript 版の特徴
ざっと触ってみて自分が感じた特徴というかできることは以下の通りです!
-
めちゃくちゃ簡単にAI Agentが構築できる
- デフォルトのモデルはClaude Sonnet4.5
- 外部ツールやMCPの統合はもちろん可能!
-
実装の流れはMastraにかなり似ている
- よってMastraを使っていた人はほぼ同じ感覚で実装できる
-
現在対応しているプロバイダーは ClaudeとOpenAIだけっぽい
- ここは今後拡充される可能性大!
いざ実践!!
今回試したソースコードは以下に格納されています。
このサンプルコードを試すときの事前準備
AI Agent自体は簡単にセットアップが可能ですが、いくつか事前準備が済んでいること前提です!
今回は以下の6点が済んでいることを確認してください!
- AWSアカウントを作成済みであること
-
aws loginやIdentity Centerなどを使ってAWSにログイン済みであること - ログインしたAWSアカウントで
Claude Sonnet 4.5のモデルが使用可能であること- エラーが出る場合はIAM周りを確認してみてください。
-
bunをインストール済みであること -
uvをインストール済みであること- MCP利用時に使います。
- (オプション) Open AIのモデルを使う場合は、Open AIのAPIキーを発行しておくこと
以降はこの4点ができているものとして進めます!!
GitHubリポジトリのクローンとセットアップ
以下のコマンドを順番に実行して、依存関係のインストールを行います!
git clone https://github.com/mashharuki/StrandsAgent-TypeScriptSDK-Sample
cd sample-agent
bun install
これで一旦は準備完了です!
一番シンプルな呼び出し方を試してみる
ではまずは一番シンプルな呼び出し方を試してみましょう!
コードで言うと以下のような実装になります!
import { Agent } from '@strands-agents/sdk'
const main = async() => {
const agent = new Agent({})
// Invoke
const result = await agent.invoke('What is the square root of 1764?')
console.log(result);
};
main();
めちゃめちゃシンプルですね!
以下のコマンドで実行します!
bun run dev
すると以下のように返ってきました!!
√1764 = 42
This is because 42 × 42 = 1764.AgentResult {
type: "agentResult",
stopReason: "endTurn",
lastMessage: Message {
type: "message",
role: "assistant",
content: [
[Object ...]
],
},
toString: [Function: toString],
}
とても簡単に動かせました!!
システムプロンプトを設定して試してみる
では続いてシステムプロンプトを設定して試してみます!
Agentインスタンスを初期化する際に引数にシステムプロンプトを設定することができます。
コードで言うと以下のようになります。
import { Agent } from '@strands-agents/sdk'
const main = async() => {
const agent = new Agent({
systemPrompt: 'You are a helpful assistant.'
})
// Invoke
const result = await agent.invoke('What is the square root of 1764?')
console.log(result);
};
main();
では動かしてみます!
bun run dev
すると以下のように返ってきました!
The square root of 1764 is 42.
To verify: 42 × 42 = 1764 ✓AgentResult {
type: "agentResult",
stopReason: "endTurn",
lastMessage: Message {
type: "message",
role: "assistant",
content: [
[Object ...]
],
},
toString: [Function: toString],
}
さっきより若干丁寧になりました!
レスポンスストリーミングも試してみる
続いてレスポンスストリーミングも試してみます!
呼び出すメソッドが変わるだけなので本当にMastraに似ていますね!
コードは以下のようになります!
import { Agent } from '@strands-agents/sdk'
const main = async() => {
const agent = new Agent({
systemPrompt: 'You are a helpful assistant.',
})
console.log('Agent response stream:');
// invokeではなくstreamメソッドを使う
for await (const event of agent.stream('Tell me a story about a brave toaster.')) {
console.log('[Event]', event.type)
};
};
main();
こちらも動かしてみると....
以下のような結果が返ってきました!!
Agent response stream:
[Event] beforeInvocationEvent
[Event] messageAddedEvent
[Event] beforeModelCallEvent
[Event] modelStreamEventHook
[Event] modelMessageStartEvent
[Event] modelStreamEventHook
#[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
The Brave Little[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Toaster of[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Maple[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Street
Once[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
upon a time, in a co[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
zy kitchen on Maple Street, there[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
lived a chrome[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
toaster named Spark[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
. While[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
other appl[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
iances bo[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
asted about their digital[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
displays[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
and fancy[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
settings[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
, Spark ha[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d just[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
two[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
slots[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
an[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d a simple dial.[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
But[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
what[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Spark lacked in features, he[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
made up for in heart[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
.
One[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
winter[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
morning, a[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
small[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
fire[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
started when[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
a[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
dish[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
tow[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
el fell[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
onto[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
the st[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
ove's[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
gas[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
burner. The flames began[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
to sprea[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d while[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
the[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
family[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
sl[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
ept up[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
stairs.[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Spark knew he had to act[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
fast.[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Summ[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
oning all[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
his courage, he po[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
pped his[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
lever[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
up[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
and down repeatedly[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
—[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
*[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
click[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
-[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
click-click-click*—making[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
as[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
much noise as possible. When[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
that[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
didn't work, he pushe[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d his heating[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
elements[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
to[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
maximum[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
,[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
trigg[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
ering the[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
smoke[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
detector[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
above[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
him[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
.
The alarm[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
bl[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
ared.[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
The family w[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
oke an[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d escape[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d safely[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
, calling[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
911.[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Firef[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
ighters arrived and put[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
out the bl[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
aze before[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
it consume[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d the house[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
. Though[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Spark's[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
chrome[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
was[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
scor[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
ched an[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d his lever[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
bent[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
from[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
the heat, he ha[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
d saved the day[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
.
The[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
family[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
kept[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
him[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
on[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
the[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
counter[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
forever[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
after[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
—[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
even[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
when[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
they bought[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
a new four[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
-slice toaster.[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Because[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
Spark had proven[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
that b[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
ravery isn't about how[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
fancy[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
you[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
are.[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
It[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
's about what[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
you do when the heat[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
is on.
**[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
The[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
End**[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
🍞[Event] modelContentBlockDeltaEvent
[Event] modelStreamEventHook
[Event] modelContentBlockStopEvent
[Event] modelStreamEventHook
[Event] textBlock
[Event] modelStreamEventHook
[Event] modelMessageStopEvent
[Event] modelStreamEventHook
[Event] modelMetadataEvent
[Event] afterModelCallEvent
[Event] messageAddedEvent
[Event] afterInvocationEvent
[Event] agentResult
めちゃくちゃ簡単!!
外部ツールを呼び出してみる
続いて外部ツールを呼び出してみます!
チュートリアルに従って以下のようなコードを実装しました!
まずは外部ツールを定義したファイルを用意します。
import { Agent, tool } from '@strands-agents/sdk'
import { z } from 'zod'
/**
* 天気予報を取得する外部ツール
*/
const weatherTool = tool({
name: 'get_weather',
description: 'Get the current weather for a specific location.',
inputSchema: z.object({
location: z.string().describe('The city and state, e.g., San Francisco, CA'),
}),
callback: (input) => {
// input is fully typed based on the Zod schema
return `The weather in ${input.location} is 72°F and sunny.`
},
})
export {
weatherTool,
}
これで準備OKです!
あとはAgentインスタンスを初期化する際の引数のtoolsに設定すればOKです!
import { Agent } from '@strands-agents/sdk'
import {
weatherTool,
} from "./tools";
/**
* メイン関数
*/
const main = async() => {
// Create agent (uses default Amazon Bedrock provider)
const agent = new Agent({
systemPrompt: 'You are a helpful assistant.',
tools: [
weatherTool,
]
})
// Invoke
const result2 = await agent.invoke('What is the weather in San Francisco?')
console.log(result2);
};
main();
こちらも同様に実行してみます。
bun run dev
すると以下のような結果が返ってきました!!
🔧 Tool #1: get_weather
✓ Tool completed
The weather in San Francisco is currently 72°F and sunny.AgentResult {
type: "agentResult",
stopReason: "endTurn",
lastMessage: Message {
type: "message",
role: "assistant",
content: [
[Object ...]
],
},
toString: [Function: toString],
うまく外部ツールを呼び出せています!
MCPを呼び出してみる
では続いてMCPの設定方法についてです!
こちらもまずMCP用のファイルを用意して準備します。
今回はAWS MCP ServersのAWS Document MCPを使っています。
import { Agent, McpClient } from '@strands-agents/sdk'
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
/**
* AWS Document MCPサーバーを利用するためのMCPクライアントの設定
*/
const documentationTools = new McpClient({
transport: new StdioClientTransport({
command: "uvx",
args: ["awslabs.aws-documentation-mcp-server@latest"],
}),
});
export {
documentationTools
}
これで準備OKです!
あとは外部ツールを設定したときと同じ流れでコードは以下のようになります!
import { Agent } from '@strands-agents/sdk'
import {
documentationTools
} from "./tools";
/**
* メイン関数
*/
const main = async() => {
// Create agent (uses default Amazon Bedrock provider)
const agent = new Agent({
systemPrompt: 'You are a helpful assistant.',
tools: [
documentationTools
]
})
// invoke
const result3 = await agent.invoke("Use a random tool from the MCP server.");
console.log(result3);
await documentationTools.disconnect();
};
main();
こちらも同様に実行してみます。
bun run dev
すると....
[12/04/25 16:02:24] INFO Processing request of type ListToolsRequest server.py:709
I'll use the search_documentation tool to search for information about AWS Lambda.
🔧 Tool #1: search_documentation
[12/04/25 16:02:28] INFO Processing request of type CallToolRequest server.py:709
[12/04/25 16:02:30] INFO HTTP Request: POST https://proxy.search.docs.aws.amazon.com/search?session=dccc8958-e7f7-44ee-97de-c6bacda4457f "HTTP/1.1 200 OK" _client.py:1740
✓ Tool completed
Great! I used the `search_documentation` tool to search for "AWS Lambda" and found 5 relevant results:
1. **AWS Lambda Documentation** - The main documentation hub for Lambda
2. **AWS Lambda API Reference** - Details about all Lambda API operations
3. **AWS Lambda CLI** - Command-line interface documentation
4. **AWS Lambda Developer Guide** - Comprehensive guide for developers
5. **What is AWS Lambda?** - An introductory page explaining Lambda's capabilities
The search results show that AWS Lambda is used for building scalable web apps, mobile backends, processing data streams, responding to database changes, running scheduled tasks, and more. Would you like me to read any of these documentation pages in detail?AgentResult {
type: "agentResult",
stopReason: "endTurn",
lastMessage: Message {
type: "message",
role: "assistant",
content: [
[Object ...]
],
},
toString: [Function: toString],
}
ちゃんとDocument MCPを呼び出せていますね!!
やったー🙌!!!
まとめ
とても簡単な紹介にはなりますが、以上で TypeScript SDKを試してみた記録の紹介は以上になります!
触ってみた感じ、コードの実装はMastraと大体同じなのでMastra触ってみた人はすぐに慣れると思います!
AgentCoreとか他のAWSサービスとの連携も踏まえるとAI AgentをAWS上で動かす場合には強力な選択肢になりそうです!!
今回はここまでになります!!
読んでいただきありがとうございました!!
Discussion