Skip to content

Commit bfb9ca1

Browse files
committed
Add the Strands example
1 parent 6b2eb9a commit bfb9ca1

37 files changed

Lines changed: 903 additions & 359 deletions

File tree

.github/dependabot.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ updates:
2525
- '/agents/agent-mastra/'
2626
- '/agents/agent-voltagent/'
2727
- '/agents/agent-sdk/'
28+
- '/agents/agent-strands/'
2829
- '/basic/cdk/'
2930
- '/basic/app/'
3031
- '/mcp/clients/langgraph-mcp-client/'

agents/agent-sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"vitest": "^4.0.15"
3535
},
3636
"dependencies": {
37-
"@anthropic-ai/claude-agent-sdk": "^0.1.59",
37+
"@anthropic-ai/claude-agent-sdk": "^0.1.60",
3838
"source-map-support": "^0.5.21",
3939
"uuid": "^13.0.0",
4040
"zod": "^4.1.13"

agents/agent-strands/.gitignore

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
9+
# Diagnostic reports (https://nodejs.org/api/report.html)
10+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
*.pid.lock
17+
18+
# Directory for instrumented libs generated by jscoverage/JSCover
19+
lib-cov
20+
21+
# Coverage directory used by tools like istanbul
22+
coverage
23+
*.lcov
24+
25+
# nyc test coverage
26+
.nyc_output
27+
28+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29+
.grunt
30+
31+
# Bower dependency directory (https://bower.io/)
32+
bower_components
33+
34+
# node-waf configuration
35+
.lock-wscript
36+
37+
# Compiled binary addons (https://nodejs.org/api/addons.html)
38+
build/Release
39+
40+
# Dependency directories
41+
node_modules/
42+
jspm_packages/
43+
44+
# TypeScript v1 declaration files
45+
typings/
46+
47+
# TypeScript cache
48+
*.tsbuildinfo
49+
50+
# Optional npm cache directory
51+
.npm
52+
53+
# Optional eslint cache
54+
.eslintcache
55+
56+
# Microbundle cache
57+
.rpt2_cache/
58+
.rts2_cache_cjs/
59+
.rts2_cache_es/
60+
.rts2_cache_umd/
61+
62+
# Optional REPL history
63+
.node_repl_history
64+
65+
# Output of 'npm pack'
66+
*.tgz
67+
68+
# Yarn Integrity file
69+
.yarn-integrity
70+
71+
# dotenv environment variables file
72+
.env
73+
.env.test
74+
75+
# parcel-bundler cache (https://parceljs.org/)
76+
.cache
77+
78+
# Next.js build output
79+
.next
80+
81+
# Nuxt.js build / generate output
82+
.nuxt
83+
# dist
84+
85+
# Gatsby files
86+
.cache/
87+
# Comment in the public line in if your project uses Gatsby and *not* Next.js
88+
# https://nextjs.org/blog/next-9-1#public-directory-support
89+
# public
90+
91+
# vuepress build output
92+
.vuepress/dist
93+
94+
# Serverless directories
95+
.serverless/
96+
97+
# FuseBox cache
98+
.fusebox/
99+
100+
# DynamoDB Local files
101+
.dynamodb/
102+
103+
# TernJS port file
104+
.tern-port
105+
.DS_Store
106+
107+
eslint.config.js
108+
eslint.config.d.ts
109+
**/*.d.ts
110+
**/*.js
111+
cdk.out
112+
!**/awslambda.d.ts

agents/agent-strands/bin/cdk.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env node
2+
import * as cdk from 'aws-cdk-lib';
3+
import {
4+
CloudfrontCdnTemplateStack,
5+
} from '../lib/cdk-stack.js';
6+
7+
const app = new cdk.App();
8+
9+
new CloudfrontCdnTemplateStack(app, 'agent-strands-lambda-example', {
10+
appName: 'agent-strands-lambda-example',
11+
env: {
12+
account: app.account,
13+
region: app.region,
14+
},
15+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"acknowledged-issue-numbers": [
3+
34892
4+
],
5+
"cli-telemetry": false
6+
}

agents/agent-strands/cdk.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"app": "pnpm dlx tsx bin/cdk.ts",
3+
"watch": {
4+
"include": [
5+
"**"
6+
],
7+
"exclude": [
8+
"README.md",
9+
"cdk*.json",
10+
"**/*.d.ts",
11+
"**/*.js",
12+
"tsconfig.json",
13+
"package*.json",
14+
"yarn.lock",
15+
"node_modules",
16+
"test",
17+
"eslint.config.mjs"
18+
]
19+
},
20+
"requireApproval": "never",
21+
"versionReporting": false,
22+
"pathMetadata": false,
23+
"context": {
24+
}
25+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { Config, defineConfig } from 'eslint/config';
2+
import eslint from '@eslint/js';
3+
import { configs, parser } from 'typescript-eslint';
4+
import stylistic from '@stylistic/eslint-plugin';
5+
import importPlugin from 'eslint-plugin-import';
6+
// @ts-expect-error ignore type errors
7+
import pluginPromise from 'eslint-plugin-promise';
8+
9+
import { includeIgnoreFile } from '@eslint/compat';
10+
import path from 'node:path';
11+
import { fileURLToPath } from 'node:url';
12+
13+
const __filename = fileURLToPath(import.meta.url);
14+
const __dirname = path.dirname(__filename);
15+
const gitignorePath = path.resolve(__dirname, '.gitignore');
16+
17+
const eslintConfig: Config[] = defineConfig(
18+
{
19+
ignores: [
20+
...(includeIgnoreFile(gitignorePath).ignores || []),
21+
'**/*.d.ts',
22+
'src/tsconfig.json',
23+
'src/stories',
24+
'**/*.css',
25+
'node_modules/**/*',
26+
'out',
27+
'cdk.out',
28+
'dist',
29+
'app',
30+
'**/*.js',
31+
],
32+
},
33+
eslint.configs.recommended,
34+
configs.strict,
35+
configs.stylistic,
36+
pluginPromise.configs['flat/recommended'],
37+
{
38+
files: ['**/*.ts', '*.js'],
39+
plugins: {
40+
'@stylistic': stylistic,
41+
},
42+
languageOptions: {
43+
ecmaVersion: 'latest',
44+
sourceType: 'module',
45+
parser,
46+
parserOptions: {
47+
projectService: true,
48+
tsconfigRootDir: __dirname,
49+
allowDefaultProject: ['eslint.config.ts'],
50+
},
51+
},
52+
extends: [
53+
importPlugin.flatConfigs.recommended,
54+
importPlugin.flatConfigs.typescript,
55+
],
56+
settings: {
57+
'import/resolver': {
58+
// You will also need to install and configure the TypeScript resolver
59+
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
60+
'typescript': true,
61+
'node': true,
62+
},
63+
},
64+
rules: {
65+
'@stylistic/semi': ['error', 'always'],
66+
'@stylistic/indent': ['error', 2],
67+
'@stylistic/comma-dangle': ['error', 'always-multiline'],
68+
'@stylistic/arrow-parens': ['error', 'always'],
69+
'@stylistic/quotes': ['error', 'single'],
70+
},
71+
},
72+
);
73+
74+
export default eslintConfig;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Agent, BedrockModel } from '@strands-agents/sdk';
2+
3+
const createAgent = ({ model: modelId }: { model: string }) => {
4+
const model = new BedrockModel({
5+
region: 'us-east-1',
6+
modelId: modelId,
7+
maxTokens: 4096,
8+
temperature: 0.7,
9+
});
10+
11+
return new Agent({ model });
12+
};
13+
14+
export { createAgent };
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
import { APIGatewayProxyEvent, APIGatewayProxyEvent, Context, Callback } from 'aws-lambda';
4+
import { Stream } from 'stream'
5+
6+
export type Event = APIGatewayProxyEvent | APIGatewayProxyEventV2;
7+
8+
export class HttpResponseStream {
9+
static from(underlyingStream: any, prelude: any): any;
10+
}
11+
12+
export type RequestHandler = (
13+
event: Event,
14+
streamResponse: Stream.WritableStream,
15+
ctx?: Context,
16+
callback?: Callback<any>,
17+
) => any | Promise<any>;
18+
19+
declare global {
20+
namespace awslambda {
21+
function streamifyResponse(handler: RequestHandler, option?: any): RequestHandler;
22+
let HttpResponseStream: HttpResponseStream;
23+
}
24+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { logger } from '@llm-ts-example/common-backend';
2+
import { APIGatewayProxyEvent } from 'aws-lambda';
3+
import { createAgent } from './agent.js';
4+
5+
export const handle = async ({ message: message = 'こんにちは!', model: model = 'us.amazon.nova-micro-v1:0' }: { message: string, model: string }, output: NodeJS.WritableStream) => {
6+
const agent = createAgent({ model });
7+
for await (const event of agent.stream(message)) {
8+
// console.log('[Event]', event.type);
9+
if (event.type === 'modelContentBlockDeltaEvent') {
10+
if (event.delta.type === 'textDelta') {
11+
output.write(event.delta.text);
12+
}
13+
}
14+
}
15+
};
16+
17+
export const handler = awslambda.streamifyResponse(
18+
async (
19+
event: APIGatewayProxyEvent, responseStream: NodeJS.WritableStream,
20+
) => {
21+
logger.debug('event', { event });
22+
const { message, model } = event.body ? JSON.parse(event.body) : {};
23+
await handle({ message, model }, responseStream);
24+
responseStream.end();
25+
});
26+
27+
export default handler;

0 commit comments

Comments
 (0)