@aws/nx-plugin 1.0.0-rc.71 → 1.0.0-rc.72

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 (64) hide show
  1. package/migrations.json +6 -1
  2. package/package.json +1 -1
  3. package/src/agentcore-harness/generator.d.ts +1 -1
  4. package/src/infra/app/generator.d.ts +1 -1
  5. package/src/init/generator.d.ts +1 -1
  6. package/src/license/dependency-check/evaluator.js +55 -10
  7. package/src/license/dependency-check/evaluator.js.map +1 -1
  8. package/src/migrations/latest/py-agent-session-management-support/metadata.json +3 -0
  9. package/src/migrations/latest/py-agent-session-management-support/migration.d.ts +2 -0
  10. package/src/migrations/latest/py-agent-session-management-support/migration.js +308 -0
  11. package/src/migrations/latest/py-agent-session-management-support/migration.js.map +1 -0
  12. package/src/preset/generator.d.ts +1 -1
  13. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +615 -6
  14. package/src/py/agent/__snapshots__/generator.core.spec.ts.snap +186 -0
  15. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +47 -3
  16. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +667 -2
  17. package/src/py/agent/files/langchain/common/__init__.py.template +0 -0
  18. package/src/py/agent/files/langchain/common/agent.py.template +3 -3
  19. package/src/py/agent/files/langchain/common/session.py.template +61 -0
  20. package/src/py/agent/files/strands/ag-ui/main.py.template +5 -1
  21. package/src/py/agent/files/strands/common/agent.py.template +9 -2
  22. package/src/py/agent/files/strands/common/session.py.template +36 -0
  23. package/src/py/agent/generator.d.ts +11 -1
  24. package/src/py/agent/generator.js +78 -28
  25. package/src/py/agent/generator.js.map +1 -1
  26. package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -0
  27. package/src/py/agent/react-connection/generator.d.ts +1 -1
  28. package/src/py/agent/schema.d.js.map +1 -1
  29. package/src/py/agent/schema.d.ts +1 -1
  30. package/src/py/agent/schema.json +3 -3
  31. package/src/py/fast-api/react/generator.d.ts +1 -1
  32. package/src/smithy/project/generator.d.ts +1 -1
  33. package/src/smithy/react-connection/generator.d.ts +1 -1
  34. package/src/terraform/project/generator.d.ts +1 -1
  35. package/src/trpc/react/generator.d.ts +1 -1
  36. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +27 -6
  37. package/src/ts/agent/a2a-connection/generator.d.ts +1 -1
  38. package/src/ts/agent/gateway-connection/generator.d.ts +1 -1
  39. package/src/ts/agent/mcp-connection/generator.d.ts +1 -1
  40. package/src/ts/agent/react-connection/generator.d.ts +1 -1
  41. package/src/ts/astro-docs/generator.d.ts +1 -1
  42. package/src/ts/dcr-proxy/generator.d.ts +1 -1
  43. package/src/ts/dynamodb/generator.d.ts +1 -1
  44. package/src/ts/lambda-function/generator.d.ts +1 -1
  45. package/src/ts/lib/generator.d.ts +1 -1
  46. package/src/ts/nx-generator/generator.d.ts +1 -1
  47. package/src/ts/nx-migration/generator.d.ts +1 -1
  48. package/src/ts/nx-plugin/generator.d.ts +1 -1
  49. package/src/ts/rdb/generator.d.ts +1 -1
  50. package/src/ts/react-website/agui/generator.d.ts +1 -1
  51. package/src/utils/agent-connection/agent-connection.d.ts +10 -0
  52. package/src/utils/agent-connection/agent-connection.js +15 -0
  53. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  54. package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +5 -3
  55. package/src/utils/agent-connection/files/py-core-langchain/s3/s3_checkpoint_saver_langchain.py.template +360 -0
  56. package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +2 -4
  57. package/src/utils/agent-connection/files/py-core-strands/base/tool_errors_strands.py.template +24 -0
  58. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +1 -1
  59. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  60. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +113 -13
  61. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +76 -7
  62. package/src/utils/versions.d.ts +3 -0
  63. package/src/utils/versions.js +3 -0
  64. package/src/utils/versions.js.map +1 -1
@@ -1,5 +1,328 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
+ exports[`py#agent generator > should create DynamoDB checkpoint table and S3 offload bucket infrastructure when session is dynamodb-s3 > agent-construct.ts (dynamodb-s3) 1`] = `
4
+ "import { Fn, Lazy, Names, RemovalPolicy, Stack } from 'aws-cdk-lib';
5
+ import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
6
+ import { Connections, IConnectable } from 'aws-cdk-lib/aws-ec2';
7
+ import {
8
+ BlockPublicAccess,
9
+ Bucket,
10
+ BucketEncryption,
11
+ } from 'aws-cdk-lib/aws-s3';
12
+ import { Key } from 'aws-cdk-lib/aws-kms';
13
+ import {
14
+ CfnDelivery,
15
+ CfnDeliveryDestination,
16
+ CfnDeliverySource,
17
+ LogGroup,
18
+ RetentionDays,
19
+ } from 'aws-cdk-lib/aws-logs';
20
+ import {
21
+ AttributeType,
22
+ BillingMode,
23
+ Table,
24
+ TableEncryption,
25
+ } from 'aws-cdk-lib/aws-dynamodb';
26
+ import { Construct } from 'constructs';
27
+ import * as path from 'path';
28
+ import * as url from 'url';
29
+ import {
30
+ AgentRuntimeArtifact,
31
+ ProtocolType,
32
+ Runtime,
33
+ RuntimeProps,
34
+ } from 'aws-cdk-lib/aws-bedrockagentcore';
35
+ import {
36
+ PolicyStatement,
37
+ Effect,
38
+ ServicePrincipal,
39
+ IGrantable,
40
+ IPrincipal,
41
+ Grant,
42
+ } from 'aws-cdk-lib/aws-iam';
43
+ import { suppressRules } from '../../../core/checkov.js';
44
+ import { RuntimeConfig } from '../../../core/runtime-config.js';
45
+ import { findWorkspaceRoot } from '../../../core/workspace.js';
46
+
47
+ export type DynamodbAgentProps = Omit<
48
+ RuntimeProps,
49
+ | 'runtimeName'
50
+ | 'protocolConfiguration'
51
+ | 'agentRuntimeArtifact'
52
+ | 'authorizerConfiguration'
53
+ > & {
54
+ /**
55
+ * Removal policy for the session bucket holding the agent's conversation
56
+ * history. Defaults to retaining it so a stack \`destroy\` doesn't silently
57
+ * delete session data — set to \`RemovalPolicy.DESTROY\` for sandbox/CI teardown.
58
+ *
59
+ * @default RemovalPolicy.RETAIN
60
+ */
61
+ readonly sessionBucketRemovalPolicy?: RemovalPolicy;
62
+ /**
63
+ * Whether to enable deletion protection on the session checkpoint table.
64
+ * Set to \`false\` to allow a stack \`destroy\` to remove it (e.g. for
65
+ * sandbox/CI teardown).
66
+ *
67
+ * @default true
68
+ */
69
+ readonly sessionTableDeletionProtection?: boolean;
70
+ /**
71
+ * Removal policy for the session checkpoint table.
72
+ *
73
+ * @default RemovalPolicy.RETAIN
74
+ */
75
+ readonly sessionTableRemovalPolicy?: RemovalPolicy;
76
+ };
77
+
78
+ export class DynamodbAgent
79
+ extends Construct
80
+ implements IGrantable, IConnectable
81
+ {
82
+ public readonly dockerImage: AgentRuntimeArtifact;
83
+ public readonly agentCoreRuntime: Runtime;
84
+ /** Default Gateway target name for this agent. */
85
+ public readonly agentName = 'dynamodb-agent';
86
+ /** Inbound auth — a fronting Gateway uses this to pick its outbound credential. */
87
+ public readonly auth = 'iam';
88
+
89
+ constructor(scope: Construct, id: string, props?: DynamodbAgentProps) {
90
+ super(scope, id);
91
+
92
+ const rc = RuntimeConfig.ensure(this);
93
+
94
+ // Resolve the bundle output directory containing the Dockerfile and built artifacts
95
+ const bundleDir = path.join(
96
+ findWorkspaceRoot(url.fileURLToPath(new URL(import.meta.url))),
97
+ 'dist/apps/test-project/docker/dynamodb-agent',
98
+ );
99
+
100
+ this.dockerImage = AgentRuntimeArtifact.fromAsset(bundleDir, {
101
+ platform: Platform.LINUX_ARM64,
102
+ });
103
+
104
+ const {
105
+ sessionBucketRemovalPolicy = RemovalPolicy.RETAIN,
106
+ sessionTableDeletionProtection = true,
107
+ sessionTableRemovalPolicy = RemovalPolicy.RETAIN,
108
+ ...restProps
109
+ } = props ?? {};
110
+
111
+ const sessionKey = new Key(this, 'SessionKey', {
112
+ enableKeyRotation: true,
113
+ });
114
+
115
+ // Allow CloudWatch Logs to use the session key for server access log delivery.
116
+ const stack = Stack.of(this);
117
+ sessionKey.addToResourcePolicy(
118
+ new PolicyStatement({
119
+ effect: Effect.ALLOW,
120
+ principals: [
121
+ new ServicePrincipal(\`logs.\${stack.region}.amazonaws.com\`),
122
+ ],
123
+ actions: [
124
+ 'kms:Encrypt',
125
+ 'kms:Decrypt',
126
+ 'kms:ReEncrypt*',
127
+ 'kms:GenerateDataKey*',
128
+ 'kms:DescribeKey',
129
+ ],
130
+ resources: ['*'],
131
+ conditions: {
132
+ ArnLike: {
133
+ 'kms:EncryptionContext:aws:logs:arn': \`arn:aws:logs:\${stack.region}:\${stack.account}:log-group:*\`,
134
+ },
135
+ },
136
+ }),
137
+ );
138
+
139
+ const sessionAccessLogs = new LogGroup(this, 'SessionAccessLogs', {
140
+ retention: RetentionDays.ONE_YEAR,
141
+ encryptionKey: sessionKey,
142
+ removalPolicy: RemovalPolicy.DESTROY,
143
+ });
144
+
145
+ const sessionBucket = new Bucket(this, 'SessionBucket', {
146
+ enforceSSL: true,
147
+ removalPolicy: sessionBucketRemovalPolicy,
148
+ encryption: BucketEncryption.KMS,
149
+ encryptionKey: sessionKey,
150
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
151
+ });
152
+ suppressRules(
153
+ sessionBucket,
154
+ ['CKV_AWS_21'],
155
+ 'Session data does not need versioning enabled',
156
+ );
157
+ suppressRules(
158
+ sessionBucket,
159
+ ['CKV2_AWS_61'],
160
+ 'Lifecycle configuration not required for session data',
161
+ );
162
+ suppressRules(
163
+ sessionBucket,
164
+ ['CKV_AWS_144'],
165
+ 'Cross-region replication not required for session data',
166
+ );
167
+ suppressRules(
168
+ sessionBucket,
169
+ ['CKV2_AWS_62'],
170
+ 'Event notifications not required for session data',
171
+ );
172
+ suppressRules(
173
+ sessionBucket,
174
+ ['CKV_AWS_18'],
175
+ 'Server access logs are delivered to CloudWatch Logs',
176
+ );
177
+
178
+ const sessionAccessLogsSource: CfnDeliverySource = new CfnDeliverySource(
179
+ this,
180
+ 'SessionAccessLogsSource',
181
+ {
182
+ name: Lazy.string({
183
+ produce: () =>
184
+ Names.uniqueResourceName(sessionAccessLogsSource, {
185
+ maxLength: 60,
186
+ }),
187
+ }),
188
+ logType: 'S3_SERVER_ACCESS_LOGS',
189
+ resourceArn: sessionBucket.bucketArn,
190
+ },
191
+ );
192
+ const sessionBucketPolicy = sessionBucket.policy;
193
+ if (sessionBucketPolicy) {
194
+ sessionAccessLogsSource.node.addDependency(sessionBucketPolicy);
195
+ }
196
+ const sessionAccessLogsDestination: CfnDeliveryDestination =
197
+ new CfnDeliveryDestination(this, 'SessionAccessLogsDestination', {
198
+ name: Lazy.string({
199
+ produce: () =>
200
+ Names.uniqueResourceName(sessionAccessLogsDestination, {
201
+ maxLength: 60,
202
+ }),
203
+ }),
204
+ destinationResourceArn: sessionAccessLogs.logGroupArn,
205
+ });
206
+ const sessionAccessLogsDelivery = new CfnDelivery(
207
+ this,
208
+ 'SessionAccessLogsDelivery',
209
+ {
210
+ deliverySourceName: sessionAccessLogsSource.name,
211
+ deliveryDestinationArn: sessionAccessLogsDestination.attrArn,
212
+ },
213
+ );
214
+ sessionAccessLogsDelivery.addDependency(sessionAccessLogsSource);
215
+
216
+ // Unified checkpoints/writes table, matching the schema
217
+ // langgraph_checkpoint_aws.DynamoDBSaver expects (PK/SK, TTL on \`ttl\`).
218
+ const sessionTable = new Table(this, 'SessionTable', {
219
+ partitionKey: { name: 'PK', type: AttributeType.STRING },
220
+ sortKey: { name: 'SK', type: AttributeType.STRING },
221
+ billingMode: BillingMode.PAY_PER_REQUEST,
222
+ pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: true },
223
+ timeToLiveAttribute: 'ttl',
224
+ encryption: TableEncryption.CUSTOMER_MANAGED,
225
+ encryptionKey: sessionKey,
226
+ deletionProtection: sessionTableDeletionProtection,
227
+ removalPolicy: sessionTableRemovalPolicy,
228
+ });
229
+
230
+ this.agentCoreRuntime = new Runtime(this, 'DynamodbAgent', {
231
+ runtimeName: Lazy.string({
232
+ produce: () =>
233
+ Names.uniqueResourceName(this.agentCoreRuntime, { maxLength: 40 }),
234
+ }),
235
+ protocolConfiguration: ProtocolType.HTTP,
236
+ agentRuntimeArtifact: this.dockerImage,
237
+ ...restProps,
238
+ environmentVariables: {
239
+ RUNTIME_CONFIG_APP_ID: rc.appConfigApplicationId,
240
+ ...restProps?.environmentVariables,
241
+ },
242
+ });
243
+
244
+ // Grant access for the agent to invoke bedrock models
245
+ this.agentCoreRuntime.addToRolePolicy(
246
+ new PolicyStatement({
247
+ actions: [
248
+ 'bedrock:InvokeModel',
249
+ 'bedrock:InvokeModelWithResponseStream',
250
+ ],
251
+ resources: [
252
+ 'arn:aws:bedrock:*:*:foundation-model/*',
253
+ 'arn:aws:bedrock:*:*:inference-profile/*',
254
+ ],
255
+ }),
256
+ );
257
+
258
+ sessionTable.grantReadWriteData(this.agentCoreRuntime);
259
+ sessionBucket.grantReadWrite(this.agentCoreRuntime);
260
+
261
+ rc.grantReadAppConfig(this.agentCoreRuntime);
262
+
263
+ rc.set('agentcore', 'agentRuntimes', {
264
+ ...rc.get('agentcore').agentRuntimes,
265
+ DynamodbAgent: {
266
+ arn: this.agentCoreRuntime.agentRuntimeArn,
267
+ session: {
268
+ tableName: sessionTable.tableName,
269
+ bucketName: sessionBucket.bucketName,
270
+ },
271
+ },
272
+ });
273
+ }
274
+
275
+ /**
276
+ * The principal to grant permissions to.
277
+ */
278
+ public get grantPrincipal(): IPrincipal {
279
+ return this.agentCoreRuntime.grantPrincipal;
280
+ }
281
+
282
+ /**
283
+ * Network connections for this agent runtime.
284
+ */
285
+ public get connections(): Connections {
286
+ return this.agentCoreRuntime.connections;
287
+ }
288
+
289
+ /**
290
+ * The HTTPS invocation URL of the runtime.
291
+ */
292
+ public get invocationUrl(): string {
293
+ // The URL must URL-encode the runtime ARN (':' -> '%3A', '/' -> '%2F').
294
+ // The ARN is a CDK token, so encode at deploy time via Fn.join/Fn.split.
295
+ const encodedArn = Fn.join(
296
+ '%2F',
297
+ Fn.split(
298
+ '/',
299
+ Fn.join('%3A', Fn.split(':', this.agentCoreRuntime.agentRuntimeArn)),
300
+ ),
301
+ );
302
+ return \`https://bedrock-agentcore.\${Stack.of(this).region}.amazonaws.com/runtimes/\${encodedArn}/invocations?qualifier=DEFAULT\`;
303
+ }
304
+
305
+ /**
306
+ * Grants IAM permissions to invoke this agent runtime.
307
+ *
308
+ * @param grantee - The IAM principal to grant permissions to
309
+ */
310
+ public grantInvokeAccess(grantee: IGrantable) {
311
+ this.agentCoreRuntime.grantInvoke(grantee);
312
+
313
+ Grant.addToPrincipal({
314
+ grantee,
315
+ actions: ['bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream'],
316
+ resourceArns: [
317
+ this.agentCoreRuntime.agentRuntimeArn,
318
+ \`\${this.agentCoreRuntime.agentRuntimeArn}/*\`,
319
+ ],
320
+ });
321
+ }
322
+ }
323
+ "
324
+ `;
325
+
3
326
  exports[`py#agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agent-Dockerfile 1`] = `
4
327
  "FROM public.ecr.aws/docker/library/python:3.14-slim
5
328
 
@@ -27,9 +350,22 @@ CMD ["python", "bin/opentelemetry-instrument", "python", "-m", "proj_test_projec
27
350
  `;
28
351
 
29
352
  exports[`py#agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agent-construct.ts 1`] = `
30
- "import { Fn, Lazy, Names, Stack } from 'aws-cdk-lib';
353
+ "import { Fn, Lazy, Names, RemovalPolicy, Stack } from 'aws-cdk-lib';
31
354
  import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
32
355
  import { Connections, IConnectable } from 'aws-cdk-lib/aws-ec2';
356
+ import {
357
+ BlockPublicAccess,
358
+ Bucket,
359
+ BucketEncryption,
360
+ } from 'aws-cdk-lib/aws-s3';
361
+ import { Key } from 'aws-cdk-lib/aws-kms';
362
+ import {
363
+ CfnDelivery,
364
+ CfnDeliveryDestination,
365
+ CfnDeliverySource,
366
+ LogGroup,
367
+ RetentionDays,
368
+ } from 'aws-cdk-lib/aws-logs';
33
369
  import { Construct } from 'constructs';
34
370
  import * as path from 'path';
35
371
  import * as url from 'url';
@@ -41,10 +377,13 @@ import {
41
377
  } from 'aws-cdk-lib/aws-bedrockagentcore';
42
378
  import {
43
379
  PolicyStatement,
380
+ Effect,
381
+ ServicePrincipal,
44
382
  IGrantable,
45
383
  IPrincipal,
46
384
  Grant,
47
385
  } from 'aws-cdk-lib/aws-iam';
386
+ import { suppressRules } from '../../../core/checkov.js';
48
387
  import { RuntimeConfig } from '../../../core/runtime-config.js';
49
388
  import { findWorkspaceRoot } from '../../../core/workspace.js';
50
389
 
@@ -54,7 +393,16 @@ export type SnapshotBedrockAgentProps = Omit<
54
393
  | 'protocolConfiguration'
55
394
  | 'agentRuntimeArtifact'
56
395
  | 'authorizerConfiguration'
57
- >;
396
+ > & {
397
+ /**
398
+ * Removal policy for the session bucket holding the agent's conversation
399
+ * history. Defaults to retaining it so a stack \`destroy\` doesn't silently
400
+ * delete session data — set to \`RemovalPolicy.DESTROY\` for sandbox/CI teardown.
401
+ *
402
+ * @default RemovalPolicy.RETAIN
403
+ */
404
+ readonly sessionBucketRemovalPolicy?: RemovalPolicy;
405
+ };
58
406
 
59
407
  export class SnapshotBedrockAgent
60
408
  extends Construct
@@ -82,6 +430,114 @@ export class SnapshotBedrockAgent
82
430
  platform: Platform.LINUX_ARM64,
83
431
  });
84
432
 
433
+ const { sessionBucketRemovalPolicy = RemovalPolicy.RETAIN, ...restProps } =
434
+ props ?? {};
435
+
436
+ const sessionKey = new Key(this, 'SessionKey', {
437
+ enableKeyRotation: true,
438
+ });
439
+
440
+ // Allow CloudWatch Logs to use the session key for server access log delivery.
441
+ const stack = Stack.of(this);
442
+ sessionKey.addToResourcePolicy(
443
+ new PolicyStatement({
444
+ effect: Effect.ALLOW,
445
+ principals: [
446
+ new ServicePrincipal(\`logs.\${stack.region}.amazonaws.com\`),
447
+ ],
448
+ actions: [
449
+ 'kms:Encrypt',
450
+ 'kms:Decrypt',
451
+ 'kms:ReEncrypt*',
452
+ 'kms:GenerateDataKey*',
453
+ 'kms:DescribeKey',
454
+ ],
455
+ resources: ['*'],
456
+ conditions: {
457
+ ArnLike: {
458
+ 'kms:EncryptionContext:aws:logs:arn': \`arn:aws:logs:\${stack.region}:\${stack.account}:log-group:*\`,
459
+ },
460
+ },
461
+ }),
462
+ );
463
+
464
+ const sessionAccessLogs = new LogGroup(this, 'SessionAccessLogs', {
465
+ retention: RetentionDays.ONE_YEAR,
466
+ encryptionKey: sessionKey,
467
+ removalPolicy: RemovalPolicy.DESTROY,
468
+ });
469
+
470
+ const sessionBucket = new Bucket(this, 'SessionBucket', {
471
+ enforceSSL: true,
472
+ removalPolicy: sessionBucketRemovalPolicy,
473
+ encryption: BucketEncryption.KMS,
474
+ encryptionKey: sessionKey,
475
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
476
+ });
477
+ suppressRules(
478
+ sessionBucket,
479
+ ['CKV_AWS_21'],
480
+ 'Session data does not need versioning enabled',
481
+ );
482
+ suppressRules(
483
+ sessionBucket,
484
+ ['CKV2_AWS_61'],
485
+ 'Lifecycle configuration not required for session data',
486
+ );
487
+ suppressRules(
488
+ sessionBucket,
489
+ ['CKV_AWS_144'],
490
+ 'Cross-region replication not required for session data',
491
+ );
492
+ suppressRules(
493
+ sessionBucket,
494
+ ['CKV2_AWS_62'],
495
+ 'Event notifications not required for session data',
496
+ );
497
+ suppressRules(
498
+ sessionBucket,
499
+ ['CKV_AWS_18'],
500
+ 'Server access logs are delivered to CloudWatch Logs',
501
+ );
502
+
503
+ const sessionAccessLogsSource: CfnDeliverySource = new CfnDeliverySource(
504
+ this,
505
+ 'SessionAccessLogsSource',
506
+ {
507
+ name: Lazy.string({
508
+ produce: () =>
509
+ Names.uniqueResourceName(sessionAccessLogsSource, {
510
+ maxLength: 60,
511
+ }),
512
+ }),
513
+ logType: 'S3_SERVER_ACCESS_LOGS',
514
+ resourceArn: sessionBucket.bucketArn,
515
+ },
516
+ );
517
+ const sessionBucketPolicy = sessionBucket.policy;
518
+ if (sessionBucketPolicy) {
519
+ sessionAccessLogsSource.node.addDependency(sessionBucketPolicy);
520
+ }
521
+ const sessionAccessLogsDestination: CfnDeliveryDestination =
522
+ new CfnDeliveryDestination(this, 'SessionAccessLogsDestination', {
523
+ name: Lazy.string({
524
+ produce: () =>
525
+ Names.uniqueResourceName(sessionAccessLogsDestination, {
526
+ maxLength: 60,
527
+ }),
528
+ }),
529
+ destinationResourceArn: sessionAccessLogs.logGroupArn,
530
+ });
531
+ const sessionAccessLogsDelivery = new CfnDelivery(
532
+ this,
533
+ 'SessionAccessLogsDelivery',
534
+ {
535
+ deliverySourceName: sessionAccessLogsSource.name,
536
+ deliveryDestinationArn: sessionAccessLogsDestination.attrArn,
537
+ },
538
+ );
539
+ sessionAccessLogsDelivery.addDependency(sessionAccessLogsSource);
540
+
85
541
  this.agentCoreRuntime = new Runtime(this, 'SnapshotBedrockAgent', {
86
542
  runtimeName: Lazy.string({
87
543
  produce: () =>
@@ -89,10 +545,10 @@ export class SnapshotBedrockAgent
89
545
  }),
90
546
  protocolConfiguration: ProtocolType.HTTP,
91
547
  agentRuntimeArtifact: this.dockerImage,
92
- ...props,
548
+ ...restProps,
93
549
  environmentVariables: {
94
550
  RUNTIME_CONFIG_APP_ID: rc.appConfigApplicationId,
95
- ...props?.environmentVariables,
551
+ ...restProps?.environmentVariables,
96
552
  },
97
553
  });
98
554
 
@@ -110,12 +566,17 @@ export class SnapshotBedrockAgent
110
566
  }),
111
567
  );
112
568
 
569
+ sessionBucket.grantReadWrite(this.agentCoreRuntime);
570
+
113
571
  rc.grantReadAppConfig(this.agentCoreRuntime);
114
572
 
115
573
  rc.set('agentcore', 'agentRuntimes', {
116
574
  ...rc.get('agentcore').agentRuntimes,
117
575
  SnapshotBedrockAgent: {
118
576
  arn: this.agentCoreRuntime.agentRuntimeArn,
577
+ session: {
578
+ bucketName: sessionBucket.bucketName,
579
+ },
119
580
  },
120
581
  });
121
582
  }
@@ -195,10 +656,12 @@ exports[`py#agent generator > should match snapshot for generated files > agent-
195
656
  exports[`py#agent generator > should match snapshot for generated files > agent-agent.py 1`] = `
196
657
  "from contextlib import contextmanager
197
658
 
198
- from proj_agent_connection import log_model_errors
659
+ from proj_agent_connection import log_model_errors, log_tool_errors
199
660
  from strands import Agent, tool
200
661
  from strands_tools import current_time
201
662
 
663
+ from .session import get_session_manager
664
+
202
665
 
203
666
  @tool
204
667
  def subtract(a: int, b: int) -> int:
@@ -216,7 +679,8 @@ Use your tools for mathematical tasks.
216
679
  Refer to tools as your 'spellbook'.
217
680
  """,
218
681
  tools=[subtract, current_time],
219
- hooks=[log_model_errors],
682
+ hooks=[log_model_errors, log_tool_errors],
683
+ session_manager=get_session_manager(),
220
684
  )
221
685
  "
222
686
  `;
@@ -324,3 +788,148 @@ dev-dependencies = [ ]
324
788
  workspace = true
325
789
  "
326
790
  `;
791
+
792
+ exports[`py#agent generator > should not create session bucket infrastructure when session is in-memory > agent-construct.ts (in-memory) 1`] = `
793
+ "import { Fn, Lazy, Names, Stack } from 'aws-cdk-lib';
794
+ import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
795
+ import { Connections, IConnectable } from 'aws-cdk-lib/aws-ec2';
796
+ import { Construct } from 'constructs';
797
+ import * as path from 'path';
798
+ import * as url from 'url';
799
+ import {
800
+ AgentRuntimeArtifact,
801
+ ProtocolType,
802
+ Runtime,
803
+ RuntimeProps,
804
+ } from 'aws-cdk-lib/aws-bedrockagentcore';
805
+ import {
806
+ PolicyStatement,
807
+ IGrantable,
808
+ IPrincipal,
809
+ Grant,
810
+ } from 'aws-cdk-lib/aws-iam';
811
+ import { RuntimeConfig } from '../../../core/runtime-config.js';
812
+ import { findWorkspaceRoot } from '../../../core/workspace.js';
813
+
814
+ export type InMemoryAgentProps = Omit<
815
+ RuntimeProps,
816
+ | 'runtimeName'
817
+ | 'protocolConfiguration'
818
+ | 'agentRuntimeArtifact'
819
+ | 'authorizerConfiguration'
820
+ >;
821
+
822
+ export class InMemoryAgent
823
+ extends Construct
824
+ implements IGrantable, IConnectable
825
+ {
826
+ public readonly dockerImage: AgentRuntimeArtifact;
827
+ public readonly agentCoreRuntime: Runtime;
828
+ /** Default Gateway target name for this agent. */
829
+ public readonly agentName = 'in-memory-agent';
830
+ /** Inbound auth — a fronting Gateway uses this to pick its outbound credential. */
831
+ public readonly auth = 'iam';
832
+
833
+ constructor(scope: Construct, id: string, props?: InMemoryAgentProps) {
834
+ super(scope, id);
835
+
836
+ const rc = RuntimeConfig.ensure(this);
837
+
838
+ // Resolve the bundle output directory containing the Dockerfile and built artifacts
839
+ const bundleDir = path.join(
840
+ findWorkspaceRoot(url.fileURLToPath(new URL(import.meta.url))),
841
+ 'dist/apps/test-project/docker/in-memory-agent',
842
+ );
843
+
844
+ this.dockerImage = AgentRuntimeArtifact.fromAsset(bundleDir, {
845
+ platform: Platform.LINUX_ARM64,
846
+ });
847
+
848
+ this.agentCoreRuntime = new Runtime(this, 'InMemoryAgent', {
849
+ runtimeName: Lazy.string({
850
+ produce: () =>
851
+ Names.uniqueResourceName(this.agentCoreRuntime, { maxLength: 40 }),
852
+ }),
853
+ protocolConfiguration: ProtocolType.HTTP,
854
+ agentRuntimeArtifact: this.dockerImage,
855
+ ...props,
856
+ environmentVariables: {
857
+ RUNTIME_CONFIG_APP_ID: rc.appConfigApplicationId,
858
+ ...props?.environmentVariables,
859
+ },
860
+ });
861
+
862
+ // Grant access for the agent to invoke bedrock models
863
+ this.agentCoreRuntime.addToRolePolicy(
864
+ new PolicyStatement({
865
+ actions: [
866
+ 'bedrock:InvokeModel',
867
+ 'bedrock:InvokeModelWithResponseStream',
868
+ ],
869
+ resources: [
870
+ 'arn:aws:bedrock:*:*:foundation-model/*',
871
+ 'arn:aws:bedrock:*:*:inference-profile/*',
872
+ ],
873
+ }),
874
+ );
875
+
876
+ rc.grantReadAppConfig(this.agentCoreRuntime);
877
+
878
+ rc.set('agentcore', 'agentRuntimes', {
879
+ ...rc.get('agentcore').agentRuntimes,
880
+ InMemoryAgent: {
881
+ arn: this.agentCoreRuntime.agentRuntimeArn,
882
+ },
883
+ });
884
+ }
885
+
886
+ /**
887
+ * The principal to grant permissions to.
888
+ */
889
+ public get grantPrincipal(): IPrincipal {
890
+ return this.agentCoreRuntime.grantPrincipal;
891
+ }
892
+
893
+ /**
894
+ * Network connections for this agent runtime.
895
+ */
896
+ public get connections(): Connections {
897
+ return this.agentCoreRuntime.connections;
898
+ }
899
+
900
+ /**
901
+ * The HTTPS invocation URL of the runtime.
902
+ */
903
+ public get invocationUrl(): string {
904
+ // The URL must URL-encode the runtime ARN (':' -> '%3A', '/' -> '%2F').
905
+ // The ARN is a CDK token, so encode at deploy time via Fn.join/Fn.split.
906
+ const encodedArn = Fn.join(
907
+ '%2F',
908
+ Fn.split(
909
+ '/',
910
+ Fn.join('%3A', Fn.split(':', this.agentCoreRuntime.agentRuntimeArn)),
911
+ ),
912
+ );
913
+ return \`https://bedrock-agentcore.\${Stack.of(this).region}.amazonaws.com/runtimes/\${encodedArn}/invocations?qualifier=DEFAULT\`;
914
+ }
915
+
916
+ /**
917
+ * Grants IAM permissions to invoke this agent runtime.
918
+ *
919
+ * @param grantee - The IAM principal to grant permissions to
920
+ */
921
+ public grantInvokeAccess(grantee: IGrantable) {
922
+ this.agentCoreRuntime.grantInvoke(grantee);
923
+
924
+ Grant.addToPrincipal({
925
+ grantee,
926
+ actions: ['bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream'],
927
+ resourceArns: [
928
+ this.agentCoreRuntime.agentRuntimeArn,
929
+ \`\${this.agentCoreRuntime.agentRuntimeArn}/*\`,
930
+ ],
931
+ });
932
+ }
933
+ }
934
+ "
935
+ `;