@aws/nx-plugin 0.42.1 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +1 -0
  2. package/generators.json +6 -0
  3. package/package.json +7 -7
  4. package/sdk/py.d.ts +2 -0
  5. package/sdk/py.js +3 -1
  6. package/sdk/py.js.map +1 -1
  7. package/src/infra/app/__snapshots__/generator.spec.ts.snap +14 -14
  8. package/src/license/__snapshots__/config.spec.ts.snap +3 -3
  9. package/src/license/config.js +5 -3
  10. package/src/license/config.js.map +1 -1
  11. package/src/mcp-server/tools/create-workspace-command.js +1 -1
  12. package/src/preset/__snapshots__/generator.spec.ts.snap +5 -3
  13. package/src/py/fast-api/generator.js +2 -7
  14. package/src/py/fast-api/generator.js.map +1 -1
  15. package/src/py/fast-api/react/generator.js +2 -2
  16. package/src/py/fast-api/react/generator.js.map +1 -1
  17. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +27 -2
  18. package/src/py/mcp-server/files/Dockerfile.template +1 -5
  19. package/src/py/mcp-server/generator.js +10 -6
  20. package/src/py/mcp-server/generator.js.map +1 -1
  21. package/src/py/mcp-server/schema.json +3 -3
  22. package/src/py/project/generator.js +16 -1
  23. package/src/py/project/generator.js.map +1 -1
  24. package/src/py/strands-agent/__snapshots__/generator.spec.ts.snap +375 -0
  25. package/src/py/strands-agent/files/Dockerfile.template +14 -0
  26. package/src/py/strands-agent/files/__init__.py.template +0 -0
  27. package/src/py/strands-agent/files/agent.py.template +22 -0
  28. package/src/py/strands-agent/files/agentcore_mcp_client.py.template +99 -0
  29. package/src/py/strands-agent/files/main.py.template +24 -0
  30. package/src/py/strands-agent/generator.d.ts +10 -0
  31. package/src/py/strands-agent/generator.js +137 -0
  32. package/src/py/strands-agent/generator.js.map +1 -0
  33. package/src/py/strands-agent/schema.d.ts +12 -0
  34. package/src/py/strands-agent/schema.json +33 -0
  35. package/src/terraform/project/files/application/src/main.tf.template +5 -0
  36. package/src/terraform/project/generator.js +13 -5
  37. package/src/terraform/project/generator.js.map +1 -1
  38. package/src/trpc/backend/generator.js +27 -33
  39. package/src/trpc/backend/generator.js.map +1 -1
  40. package/src/trpc/react/generator.js +2 -2
  41. package/src/trpc/react/generator.js.map +1 -1
  42. package/src/ts/lib/__snapshots__/generator.spec.ts.snap +1 -1
  43. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +22 -1
  44. package/src/ts/mcp-server/generator.js +4 -3
  45. package/src/ts/mcp-server/generator.js.map +1 -1
  46. package/src/ts/mcp-server/schema.json +3 -3
  47. package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +1 -1
  48. package/src/ts/nx-plugin/files/mcp-server/tools/create-workspace-command.ts.template +1 -1
  49. package/src/ts/nx-plugin/generator.js +4 -1
  50. package/src/ts/nx-plugin/generator.js.map +1 -1
  51. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +33 -484
  52. package/src/ts/react-website/cognito-auth/generator.js +0 -25
  53. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  54. package/src/ts/react-website/runtime-config/__snapshots__/generator.spec.ts.snap +6 -5
  55. package/src/ts/react-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +3 -1
  56. package/src/ts/react-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +1 -2
  57. package/src/utils/__snapshots__/shared-constructs.spec.ts.snap +3 -15
  58. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +16 -0
  59. package/src/utils/agent-core-constructs/agent-core-constructs.js +33 -8
  60. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  61. package/src/utils/agent-core-constructs/files/app/{mcp-servers/__mcpServerNameKebabCase__/__mcpServerNameKebabCase__.ts.template → agent-core/__nameKebabCase__/__nameKebabCase__.ts.template} +5 -5
  62. package/src/utils/agent-core-constructs/files/core/agent-core/runtime.ts.template +22 -1
  63. package/src/utils/api-constructs/api-constructs.js +0 -30
  64. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  65. package/src/utils/files/common/constructs/src/core/runtime-config.ts.template +3 -4
  66. package/src/utils/files/terraform/src/metrics/metrics.tf.template +19 -0
  67. package/src/utils/metrics.d.ts +3 -1
  68. package/src/utils/metrics.js +36 -3
  69. package/src/utils/metrics.js.map +1 -1
  70. package/src/utils/port.d.ts +4 -6
  71. package/src/utils/port.js +32 -12
  72. package/src/utils/port.js.map +1 -1
  73. package/src/utils/shared-constructs-constants.d.ts +0 -2
  74. package/src/utils/shared-constructs-constants.js +1 -3
  75. package/src/utils/shared-constructs-constants.js.map +1 -1
  76. package/src/utils/shared-constructs.d.ts +4 -1
  77. package/src/utils/shared-constructs.js +49 -45
  78. package/src/utils/shared-constructs.js.map +1 -1
  79. package/src/utils/versions.d.ts +7 -2
  80. package/src/utils/versions.js +6 -1
  81. package/src/utils/versions.js.map +1 -1
  82. package/src/utils/files/common/types/src/index.ts.template +0 -1
  83. package/src/utils/files/common/types/src/runtime-config.ts.template +0 -2
  84. /package/src/utils/agent-core-constructs/files/app/{mcp-servers/__mcpServerNameKebabCase__ → agent-core/__nameKebabCase__}/Dockerfile.template +0 -0
@@ -0,0 +1,375 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`py#strands-agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agent-Dockerfile 1`] = `
4
+ "FROM public.ecr.aws/docker/library/python:3.12-slim
5
+
6
+ WORKDIR /app
7
+
8
+ # Copy bundled package
9
+ COPY --from=workspace dist/apps/test-project/bundle /app
10
+
11
+ EXPOSE 8080
12
+
13
+ ENV PYTHONPATH=/app
14
+
15
+ # Auto-instrument with AWS Distro for OpenTelemetry
16
+ # https://aws-otel.github.io/docs/getting-started/python-sdk/auto-instr
17
+ CMD ["python", "bin/opentelemetry-instrument", "python", "-m", "proj_test_project.snapshot_bedrock_agent.main"]
18
+ "
19
+ `;
20
+
21
+ exports[`py#strands-agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agent-construct.ts 1`] = `
22
+ "import { DockerImageAsset, Platform } from 'aws-cdk-lib/aws-ecr-assets';
23
+ import { Construct } from 'constructs';
24
+ import { execSync } from 'child_process';
25
+ import * as path from 'path';
26
+ import * as url from 'url';
27
+ import {
28
+ AgentCoreRuntime,
29
+ AgentCoreRuntimeProps,
30
+ } from '../../../core/agent-core/runtime.js';
31
+
32
+ export type SnapshotBedrockAgentProps = Omit<
33
+ AgentCoreRuntimeProps,
34
+ 'runtimeName' | 'serverProtocol' | 'containerUri'
35
+ >;
36
+
37
+ export class SnapshotBedrockAgent extends Construct {
38
+ public readonly dockerImage: DockerImageAsset;
39
+ public readonly agentCoreRuntime: AgentCoreRuntime;
40
+
41
+ constructor(scope: Construct, id: string, props?: SnapshotBedrockAgentProps) {
42
+ super(scope, id);
43
+
44
+ this.dockerImage = new DockerImageAsset(this, 'DockerImage', {
45
+ platform: Platform.LINUX_ARM64,
46
+ directory: path.dirname(url.fileURLToPath(new URL(import.meta.url))),
47
+ extraHash: execSync(
48
+ \`docker inspect proj-snapshot-bedrock-agent:latest --format '{{.Descriptor.digest}}'\`,
49
+ { encoding: 'utf-8' },
50
+ ).trim(),
51
+ });
52
+
53
+ this.agentCoreRuntime = new AgentCoreRuntime(this, 'AgentCore', {
54
+ runtimeName: 'SnapshotBedrockAgent',
55
+ serverProtocol: 'HTTP',
56
+ containerUri: this.dockerImage.imageUri,
57
+ ...props,
58
+ });
59
+ }
60
+ }
61
+ "
62
+ `;
63
+
64
+ exports[`py#strands-agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agent-core-runtime.ts 1`] = `
65
+ "import {
66
+ Role,
67
+ ServicePrincipal,
68
+ PolicyStatement,
69
+ Effect,
70
+ PolicyDocument,
71
+ IGrantable,
72
+ Grant,
73
+ IPrincipal,
74
+ } from 'aws-cdk-lib/aws-iam';
75
+ import {
76
+ AwsCustomResource,
77
+ AwsCustomResourcePolicy,
78
+ PhysicalResourceId,
79
+ PhysicalResourceIdReference,
80
+ } from 'aws-cdk-lib/custom-resources';
81
+ import { Construct } from 'constructs';
82
+ import type { AuthorizerConfiguration } from '@aws-sdk/client-bedrock-agentcore-control';
83
+ import { Stack } from 'aws-cdk-lib';
84
+
85
+ /**
86
+ * Options for the AgentCoreRuntime construct
87
+ */
88
+ export interface AgentCoreRuntimeProps {
89
+ runtimeName: string;
90
+ description?: string;
91
+ containerUri: string;
92
+ serverProtocol: 'MCP' | 'HTTP';
93
+ environment?: Record<string, string>;
94
+ authorizerConfiguration?: AuthorizerConfiguration;
95
+ }
96
+
97
+ /**
98
+ * A construct for creating a Bedrock AgentCore Runtime
99
+ */
100
+ export class AgentCoreRuntime extends Construct implements IGrantable {
101
+ public readonly role: Role;
102
+ public readonly arn: string;
103
+
104
+ public readonly grantPrincipal: IPrincipal;
105
+
106
+ constructor(scope: Construct, id: string, props: AgentCoreRuntimeProps) {
107
+ super(scope, id);
108
+
109
+ const region = Stack.of(this).region;
110
+ const accountId = Stack.of(this).account;
111
+
112
+ this.role = new Role(this, 'AgentCoreRole', {
113
+ assumedBy: new ServicePrincipal('bedrock-agentcore.amazonaws.com'),
114
+ inlinePolicies: {
115
+ AgentCorePolicy: new PolicyDocument({
116
+ statements: [
117
+ new PolicyStatement({
118
+ sid: 'ECRImageAccess',
119
+ effect: Effect.ALLOW,
120
+ actions: ['ecr:BatchGetImage', 'ecr:GetDownloadUrlForLayer'],
121
+ resources: [\`arn:aws:ecr:\${region}:\${accountId}:repository/*\`],
122
+ }),
123
+ new PolicyStatement({
124
+ effect: Effect.ALLOW,
125
+ actions: ['logs:DescribeLogStreams', 'logs:CreateLogGroup'],
126
+ resources: [
127
+ \`arn:aws:logs:\${region}:\${accountId}:log-group:/aws/bedrock-agentcore/runtimes/*\`,
128
+ ],
129
+ }),
130
+ new PolicyStatement({
131
+ effect: Effect.ALLOW,
132
+ actions: ['logs:DescribeLogGroups'],
133
+ resources: [\`arn:aws:logs:\${region}:\${accountId}:log-group:*\`],
134
+ }),
135
+ new PolicyStatement({
136
+ effect: Effect.ALLOW,
137
+ actions: ['logs:CreateLogStream', 'logs:PutLogEvents'],
138
+ resources: [
139
+ \`arn:aws:logs:\${region}:\${accountId}:log-group:/aws/bedrock-agentcore/runtimes/*:log-stream:*\`,
140
+ ],
141
+ }),
142
+ new PolicyStatement({
143
+ sid: 'ECRTokenAccess',
144
+ effect: Effect.ALLOW,
145
+ actions: ['ecr:GetAuthorizationToken'],
146
+ resources: ['*'],
147
+ }),
148
+ new PolicyStatement({
149
+ effect: Effect.ALLOW,
150
+ actions: [
151
+ 'xray:PutTraceSegments',
152
+ 'xray:PutTelemetryRecords',
153
+ 'xray:GetSamplingRules',
154
+ 'xray:GetSamplingTargets',
155
+ ],
156
+ resources: ['*'],
157
+ }),
158
+ new PolicyStatement({
159
+ effect: Effect.ALLOW,
160
+ actions: ['cloudwatch:PutMetricData'],
161
+ resources: ['*'],
162
+ conditions: {
163
+ StringEquals: {
164
+ 'cloudwatch:namespace': 'bedrock-agentcore',
165
+ },
166
+ },
167
+ }),
168
+ new PolicyStatement({
169
+ sid: 'GetAgentAccessToken',
170
+ effect: Effect.ALLOW,
171
+ actions: [
172
+ 'bedrock-agentcore:GetWorkloadAccessToken',
173
+ 'bedrock-agentcore:GetWorkloadAccessTokenForJWT',
174
+ 'bedrock-agentcore:GetWorkloadAccessTokenForUserId',
175
+ ],
176
+ resources: [
177
+ \`arn:aws:bedrock-agentcore:\${region}:\${accountId}:workload-identity-directory/default\`,
178
+ \`arn:aws:bedrock-agentcore:\${region}:\${accountId}:workload-identity-directory/default/workload-identity/*\`,
179
+ ],
180
+ }),
181
+ new PolicyStatement({
182
+ sid: 'BedrockModelInvocation',
183
+ effect: Effect.ALLOW,
184
+ actions: [
185
+ 'bedrock:InvokeModel',
186
+ 'bedrock:InvokeModelWithResponseStream',
187
+ ],
188
+ resources: [
189
+ 'arn:aws:bedrock:*::foundation-model/*',
190
+ \`arn:aws:bedrock:\${region}:\${accountId}:*\`,
191
+ ],
192
+ }),
193
+ ],
194
+ }),
195
+ },
196
+ });
197
+ this.grantPrincipal = this.role.grantPrincipal;
198
+
199
+ const agentRuntime = new AwsCustomResource(this, 'MCPSeverRuntime', {
200
+ onCreate: {
201
+ service: 'bedrock-agentcore-control',
202
+ action: 'CreateAgentRuntime',
203
+ parameters: {
204
+ agentRuntimeName: props.runtimeName,
205
+ agentRuntimeArtifact: {
206
+ containerConfiguration: {
207
+ containerUri: props.containerUri,
208
+ },
209
+ },
210
+ description: props.description,
211
+ environmentVariables: props.environment,
212
+ networkConfiguration: {
213
+ networkMode: 'PUBLIC',
214
+ },
215
+ protocolConfiguration: {
216
+ serverProtocol: props.serverProtocol,
217
+ },
218
+ roleArn: this.role.roleArn,
219
+ authorizerConfiguration: props.authorizerConfiguration,
220
+ },
221
+ physicalResourceId: PhysicalResourceId.fromResponse('agentRuntimeId'),
222
+ },
223
+ onUpdate: {
224
+ service: 'bedrock-agentcore-control',
225
+ action: 'UpdateAgentRuntime',
226
+ parameters: {
227
+ agentRuntimeId: new PhysicalResourceIdReference(),
228
+ agentRuntimeName: props.runtimeName,
229
+ agentRuntimeArtifact: {
230
+ containerConfiguration: {
231
+ containerUri: props.containerUri,
232
+ },
233
+ },
234
+ description: props.description,
235
+ environmentVariables: props.environment,
236
+ networkConfiguration: {
237
+ networkMode: 'PUBLIC',
238
+ },
239
+ protocolConfiguration: {
240
+ serverProtocol: props.serverProtocol,
241
+ },
242
+ roleArn: this.role.roleArn,
243
+ authorizerConfiguration: props.authorizerConfiguration,
244
+ },
245
+ physicalResourceId: PhysicalResourceId.fromResponse('agentRuntimeId'),
246
+ },
247
+ onDelete: {
248
+ service: 'bedrock-agentcore-control',
249
+ action: 'DeleteAgentRuntime',
250
+ parameters: {
251
+ agentRuntimeId: new PhysicalResourceIdReference(),
252
+ },
253
+ },
254
+ policy: AwsCustomResourcePolicy.fromStatements([
255
+ new PolicyStatement({
256
+ actions: ['bedrock-agentcore:*'],
257
+ resources: ['*'],
258
+ }),
259
+ new PolicyStatement({
260
+ actions: ['iam:PassRole'],
261
+ resources: [this.role.roleArn],
262
+ }),
263
+ ]),
264
+ installLatestAwsSdk: true,
265
+ });
266
+
267
+ this.arn = agentRuntime.getResponseField('agentRuntimeArn');
268
+ }
269
+
270
+ /**
271
+ * Grant permissions to invoke the agent runtime (if using IAM auth - not required for JWT auth)
272
+ */
273
+ public grantInvoke = (grantee: IGrantable) => {
274
+ Grant.addToPrincipal({
275
+ grantee,
276
+ actions: ['bedrock-agentcore:InvokeAgentRuntime'],
277
+ resourceArns: [this.arn, \`\${this.arn}/*\`],
278
+ });
279
+ };
280
+ }
281
+ "
282
+ `;
283
+
284
+ exports[`py#strands-agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agents-index.ts 1`] = `
285
+ "export * from './snapshot-bedrock-agent/snapshot-bedrock-agent.js';
286
+ "
287
+ `;
288
+
289
+ exports[`py#strands-agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > app-index.ts 1`] = `
290
+ "export * from './agents/index.js';
291
+ "
292
+ `;
293
+
294
+ exports[`py#strands-agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > core-index.ts 1`] = `
295
+ "export * from './app.js';
296
+ export * from './runtime-config.js';
297
+ "
298
+ `;
299
+
300
+ exports[`py#strands-agent generator > should match snapshot for generated files > strands-agent-__init__.py 1`] = `""`;
301
+
302
+ exports[`py#strands-agent generator > should match snapshot for generated files > strands-agent-agent.py 1`] = `
303
+ "from contextlib import contextmanager
304
+
305
+ from strands import Agent, tool
306
+ from strands_tools import current_time
307
+
308
+
309
+ # Define a custom tool
310
+ @tool
311
+ def add(a: int, b: int) -> int:
312
+ return a + b
313
+
314
+
315
+ @contextmanager
316
+ def get_agent(session_id: str):
317
+ yield Agent(
318
+ system_prompt="""
319
+ You are an addition wizard.
320
+ Use the 'add' tool for addition tasks.
321
+ Refer to tools as your 'spellbook'.
322
+ """,
323
+ tools=[add, current_time],
324
+ )
325
+ "
326
+ `;
327
+
328
+ exports[`py#strands-agent generator > should match snapshot for generated files > strands-agent-main.py 1`] = `
329
+ "from bedrock_agentcore.runtime import BedrockAgentCoreApp
330
+
331
+ from .agent import get_agent
332
+
333
+ app = BedrockAgentCoreApp()
334
+
335
+
336
+ @app.entrypoint
337
+ async def invoke(payload, context):
338
+ """Handler for agent invocation"""
339
+ prompt = payload.get(
340
+ "prompt", "No prompt found in input, please guide the user "
341
+ "to create a json payload with prompt key"
342
+ )
343
+
344
+ with get_agent(session_id=context.session_id) as agent:
345
+ stream = agent.stream_async(prompt)
346
+ async for event in stream:
347
+ print(event)
348
+ yield (event)
349
+
350
+
351
+ if __name__ == "__main__":
352
+ app.run()
353
+ "
354
+ `;
355
+
356
+ exports[`py#strands-agent generator > should match snapshot for generated files > updated-pyproject.toml 1`] = `
357
+ "[project]
358
+ name = "proj.test_project"
359
+ version = "0.1.0"
360
+ dependencies = [
361
+ "aws-opentelemetry-distro~=0.11.0",
362
+ "bedrock-agentcore~=0.1.2",
363
+ "boto3~=1.40.14",
364
+ "mcp~=1.13.0",
365
+ "strands-agents~=1.5.0",
366
+ "strands-agents-tools~=0.2.4"
367
+ ]
368
+
369
+ [dependency-groups]
370
+ dev = [ ]
371
+
372
+ [tool.uv]
373
+ dev-dependencies = [ ]
374
+ "
375
+ `;
@@ -0,0 +1,14 @@
1
+ FROM public.ecr.aws/docker/library/python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Copy bundled package
6
+ COPY --from=workspace <%- distDir %>/bundle /app
7
+
8
+ EXPOSE 8080
9
+
10
+ ENV PYTHONPATH=/app
11
+
12
+ # Auto-instrument with AWS Distro for OpenTelemetry
13
+ # https://aws-otel.github.io/docs/getting-started/python-sdk/auto-instr
14
+ CMD ["python", "bin/opentelemetry-instrument", "python", "-m", "<%- moduleName %>.<%- agentNameSnakeCase %>.main"]
@@ -0,0 +1,22 @@
1
+ from contextlib import contextmanager
2
+
3
+ from strands import Agent, tool
4
+ from strands_tools import current_time
5
+
6
+
7
+ # Define a custom tool
8
+ @tool
9
+ def add(a: int, b: int) -> int:
10
+ return a + b
11
+
12
+
13
+ @contextmanager
14
+ def get_agent(session_id: str):
15
+ yield Agent(
16
+ system_prompt="""
17
+ You are an addition wizard.
18
+ Use the 'add' tool for addition tasks.
19
+ Refer to tools as your 'spellbook'.
20
+ """,
21
+ tools=[add, current_time],
22
+ )
@@ -0,0 +1,99 @@
1
+ import hashlib
2
+ from collections.abc import Generator
3
+ from typing import Any
4
+
5
+ import httpx
6
+ from botocore.auth import SigV4Auth
7
+ from botocore.awsrequest import AWSRequest
8
+ from mcp.client.streamable_http import streamablehttp_client
9
+ from strands.tools.mcp.mcp_client import MCPClient
10
+
11
+
12
+ class SigV4HTTPXAuth(httpx.Auth):
13
+ """HTTPX Auth class that signs requests with AWS SigV4."""
14
+
15
+ def __init__(self, credentials: Any, region: str):
16
+ self.credentials = credentials
17
+ self.service = "bedrock-agentcore"
18
+ self.region = region
19
+ self.signer = SigV4Auth(credentials, self.service, region)
20
+
21
+ def auth_flow(
22
+ self, request: httpx.Request
23
+ ) -> Generator[httpx.Request, httpx.Response, None]:
24
+ headers = dict(request.headers)
25
+
26
+ headers.pop("connection", None)
27
+ headers["x-amz-content-sha256"] = hashlib.sha256(
28
+ request.content if request.content else b""
29
+ ).hexdigest()
30
+
31
+ aws_request = AWSRequest(
32
+ method=request.method,
33
+ url=str(request.url),
34
+ data=request.content,
35
+ headers=headers,
36
+ )
37
+
38
+ self.signer.add_auth(aws_request)
39
+
40
+ request.headers.clear()
41
+ request.headers.update(dict(aws_request.headers))
42
+
43
+ yield request
44
+
45
+
46
+ class AgentCoreMCPClient:
47
+ """Factory for clients to call MCP servers hosted on Bedrock AgentCore Runtime"""
48
+
49
+ @staticmethod
50
+ def _create(
51
+ agent_runtime_arn: str,
52
+ region: str,
53
+ session_id: str,
54
+ headers: dict = None,
55
+ auth_handler: httpx.Auth = None,
56
+ ):
57
+ # Build the URL
58
+ encoded_arn = agent_runtime_arn.replace(":", "%3A").replace("/", "%2F")
59
+ url = f"https://bedrock-agentcore.{region}.amazonaws.com/runtimes/{encoded_arn}/invocations?qualifier=DEFAULT"
60
+
61
+ # Create and return the MCP client
62
+ return MCPClient(
63
+ lambda: streamablehttp_client(
64
+ url,
65
+ auth=auth_handler,
66
+ timeout=120,
67
+ terminate_on_close=False,
68
+ headers={
69
+ "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id": session_id,
70
+ **(headers if headers is not None else {}),
71
+ },
72
+ )
73
+ )
74
+
75
+ @staticmethod
76
+ def with_iam_auth(
77
+ agent_runtime_arn: str, credentials: Any, region: str, session_id: str
78
+ ) -> MCPClient:
79
+ """Create an MCP client with IAM (SigV4) authentication."""
80
+ return AgentCoreMCPClient._create(
81
+ agent_runtime_arn=agent_runtime_arn,
82
+ region=region,
83
+ session_id=session_id,
84
+ auth_handler=SigV4HTTPXAuth(credentials, region),
85
+ )
86
+
87
+ @staticmethod
88
+ def with_jwt_auth(
89
+ agent_runtime_arn: str, access_token: str, region: str, session_id: str
90
+ ) -> MCPClient:
91
+ """Create an MCP client with JWT authentication."""
92
+ return AgentCoreMCPClient._create(
93
+ agent_runtime_arn=agent_runtime_arn,
94
+ region=region,
95
+ session_id=session_id,
96
+ headers={
97
+ "Authorization": f"Bearer {access_token}",
98
+ },
99
+ )
@@ -0,0 +1,24 @@
1
+ from bedrock_agentcore.runtime import BedrockAgentCoreApp
2
+
3
+ from .agent import get_agent
4
+
5
+ app = BedrockAgentCoreApp()
6
+
7
+
8
+ @app.entrypoint
9
+ async def invoke(payload, context):
10
+ """Handler for agent invocation"""
11
+ prompt = payload.get(
12
+ "prompt", "No prompt found in input, please guide the user "
13
+ "to create a json payload with prompt key"
14
+ )
15
+
16
+ with get_agent(session_id=context.session_id) as agent:
17
+ stream = agent.stream_async(prompt)
18
+ async for event in stream:
19
+ print(event)
20
+ yield (event)
21
+
22
+
23
+ if __name__ == "__main__":
24
+ app.run()
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { GeneratorCallback, Tree } from '@nx/devkit';
6
+ import { PyStrandsAgentGeneratorSchema } from './schema';
7
+ import { NxGeneratorInfo } from '../../utils/nx';
8
+ export declare const PY_STRANDS_AGENT_GENERATOR_INFO: NxGeneratorInfo;
9
+ export declare const pyStrandsAgentGenerator: (tree: Tree, options: PyStrandsAgentGeneratorSchema) => Promise<GeneratorCallback>;
10
+ export default pyStrandsAgentGenerator;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pyStrandsAgentGenerator = exports.PY_STRANDS_AGENT_GENERATOR_INFO = void 0;
4
+ const tslib_1 = require("tslib");
5
+ /**
6
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
7
+ * SPDX-License-Identifier: Apache-2.0
8
+ */
9
+ const devkit_1 = require("@nx/devkit");
10
+ const nx_1 = require("../../utils/nx");
11
+ const metrics_1 = require("../../utils/metrics");
12
+ const format_1 = require("../../utils/format");
13
+ const names_1 = require("../../utils/names");
14
+ const py_1 = require("../../utils/py");
15
+ const agent_core_constructs_1 = require("../../utils/agent-core-constructs/agent-core-constructs");
16
+ const bundle_1 = require("../../utils/bundle");
17
+ const npm_scope_1 = require("../../utils/npm-scope");
18
+ const shared_constructs_1 = require("../../utils/shared-constructs");
19
+ const shared_constructs_constants_1 = require("../../utils/shared-constructs-constants");
20
+ const logger_1 = require("@nxlv/python/src/executors/utils/logger");
21
+ const provider_1 = require("@nxlv/python/src/provider/uv/provider");
22
+ exports.PY_STRANDS_AGENT_GENERATOR_INFO = (0, nx_1.getGeneratorInfo)(__filename);
23
+ const pyStrandsAgentGenerator = (tree, options) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
24
+ var _a, _b, _c, _d, _e, _f, _g;
25
+ const project = (0, nx_1.readProjectConfigurationUnqualified)(tree, options.project);
26
+ const pyProjectPath = (0, devkit_1.joinPathFragments)(project.root, 'pyproject.toml');
27
+ // Check if the project has a pyproject.toml file
28
+ if (!pyProjectPath) {
29
+ throw new Error(`Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`);
30
+ }
31
+ if (!project.sourceRoot) {
32
+ throw new Error(`This project does not have a source root. Please add a source root to the project configuration before running this generator.`);
33
+ }
34
+ // Module name is the last part of the source root,
35
+ const sourceParts = project.sourceRoot.split('/');
36
+ const moduleName = sourceParts[sourceParts.length - 1];
37
+ const name = (0, names_1.kebabCase)((_a = options.name) !== null && _a !== void 0 ? _a : `${(0, names_1.kebabCase)(project.name.split('.').pop())}-agent`);
38
+ const agentNameSnakeCase = (0, names_1.toSnakeCase)((_b = options.name) !== null && _b !== void 0 ? _b : 'agent');
39
+ const agentNameClassName = (0, names_1.toClassName)(name);
40
+ const targetSourceDir = (0, devkit_1.joinPathFragments)(project.sourceRoot, agentNameSnakeCase);
41
+ const distDir = (0, devkit_1.joinPathFragments)('dist', project.root);
42
+ const computeType = (_c = options.computeType) !== null && _c !== void 0 ? _c : 'BedrockAgentCoreRuntime';
43
+ // Generate example agent
44
+ (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files'), targetSourceDir, {
45
+ name,
46
+ agentNameSnakeCase,
47
+ agentNameClassName,
48
+ moduleName,
49
+ distDir,
50
+ }, { overwriteStrategy: devkit_1.OverwriteStrategy.KeepExisting });
51
+ (0, py_1.addDependenciesToPyProjectToml)(tree, project.root, [
52
+ 'aws-opentelemetry-distro',
53
+ 'bedrock-agentcore',
54
+ 'boto3',
55
+ 'mcp',
56
+ 'strands-agents',
57
+ 'strands-agents-tools',
58
+ ]);
59
+ if (computeType === 'BedrockAgentCoreRuntime') {
60
+ const dockerImageTag = `${(0, npm_scope_1.getNpmScope)(tree)}-${name}:latest`;
61
+ // Add bundle target
62
+ (0, bundle_1.addPythonBundleTarget)(project, {
63
+ pythonPlatform: 'aarch64-manylinux2014',
64
+ });
65
+ const dockerTargetName = `${name}-docker`;
66
+ // Add a docker target specific to this MCP server
67
+ project.targets[dockerTargetName] = {
68
+ cache: true,
69
+ executor: 'nx:run-commands',
70
+ options: {
71
+ commands: [
72
+ `docker build --platform linux/arm64 -t ${dockerImageTag} ${targetSourceDir} --build-context workspace=.`,
73
+ ],
74
+ parallel: false,
75
+ },
76
+ dependsOn: ['bundle'],
77
+ };
78
+ project.targets.docker = Object.assign(Object.assign({}, project.targets.docker), { dependsOn: [
79
+ ...((_e = (_d = project.targets.docker) === null || _d === void 0 ? void 0 : _d.dependsOn) !== null && _e !== void 0 ? _e : []).filter((t) => t !== dockerTargetName),
80
+ dockerTargetName,
81
+ ] });
82
+ project.targets.build = Object.assign(Object.assign({}, project.targets.build), { dependsOn: [
83
+ ...((_g = (_f = project.targets.build) === null || _f === void 0 ? void 0 : _f.dependsOn) !== null && _g !== void 0 ? _g : []).filter((t) => t !== 'docker'),
84
+ 'docker',
85
+ ] });
86
+ // Add shared constructs
87
+ yield (0, shared_constructs_1.sharedConstructsGenerator)(tree);
88
+ // Ensure common constructs builds after our agent project
89
+ (0, devkit_1.updateJson)(tree, (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR, 'project.json'), (config) => {
90
+ var _a;
91
+ if (!config.targets) {
92
+ config.targets = {};
93
+ }
94
+ if (!config.targets.build) {
95
+ config.targets.build = {};
96
+ }
97
+ config.targets.build.dependsOn = [
98
+ ...((_a = config.targets.build.dependsOn) !== null && _a !== void 0 ? _a : []).filter((t) => t !== `${project.name}:build`),
99
+ `${project.name}:build`,
100
+ ];
101
+ return config;
102
+ });
103
+ // Add the construct to deploy the agent
104
+ (0, agent_core_constructs_1.addAgentConstruct)(tree, {
105
+ agentNameKebabCase: name,
106
+ agentNameClassName,
107
+ dockerImageTag,
108
+ });
109
+ }
110
+ else {
111
+ // No Dockerfile needed for non-hosted Agent
112
+ tree.delete((0, devkit_1.joinPathFragments)(targetSourceDir, 'Dockerfile'));
113
+ }
114
+ (0, devkit_1.updateProjectConfiguration)(tree, project.name, Object.assign(Object.assign({}, project), { targets: Object.assign(Object.assign({}, project.targets), {
115
+ // TODO: Add hot-reload
116
+ [`${options.name ? name : 'agent'}-serve`]: {
117
+ executor: 'nx:run-commands',
118
+ options: {
119
+ commands: [
120
+ `uv run python -m ${moduleName}.${agentNameSnakeCase}.main`,
121
+ ],
122
+ cwd: '{projectRoot}',
123
+ },
124
+ continuous: true,
125
+ } }) }));
126
+ yield (0, metrics_1.addGeneratorMetricsIfApplicable)(tree, [
127
+ exports.PY_STRANDS_AGENT_GENERATOR_INFO,
128
+ ]);
129
+ yield (0, format_1.formatFilesInSubtree)(tree);
130
+ return () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
131
+ (0, devkit_1.installPackagesTask)(tree);
132
+ yield new provider_1.UVProvider(tree.root, new logger_1.Logger(), tree).install();
133
+ });
134
+ });
135
+ exports.pyStrandsAgentGenerator = pyStrandsAgentGenerator;
136
+ exports.default = exports.pyStrandsAgentGenerator;
137
+ //# sourceMappingURL=generator.js.map