@aws/nx-plugin 1.0.0-rc.11 → 1.0.0-rc.13

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 (105) hide show
  1. package/LICENSE-THIRD-PARTY +81 -3
  2. package/generators.json +31 -1
  3. package/package.json +2 -2
  4. package/sdk/agentcore-gateway.d.ts +6 -0
  5. package/sdk/agentcore-gateway.js +11 -0
  6. package/sdk/agentcore-gateway.js.map +1 -0
  7. package/sdk/license.d.ts +4 -4
  8. package/sdk/license.js +5 -4
  9. package/sdk/license.js.map +1 -1
  10. package/sdk/py.d.ts +6 -6
  11. package/sdk/py.js +7 -7
  12. package/sdk/py.js.map +1 -1
  13. package/sdk/ts.d.ts +18 -14
  14. package/sdk/ts.js +38 -32
  15. package/sdk/ts.js.map +1 -1
  16. package/src/agentcore-gateway/files/cedar/policies/README.md +52 -0
  17. package/src/agentcore-gateway/files/cedar/policies/permit-all.cedar +11 -0
  18. package/src/agentcore-gateway/files/project/serve-local.ts.template +133 -0
  19. package/src/agentcore-gateway/generator.d.ts +25 -0
  20. package/src/agentcore-gateway/generator.js +129 -0
  21. package/src/agentcore-gateway/generator.js.map +1 -0
  22. package/src/agentcore-gateway/mcp-connection/generator.d.ts +19 -0
  23. package/src/agentcore-gateway/mcp-connection/generator.js +79 -0
  24. package/src/agentcore-gateway/mcp-connection/generator.js.map +1 -0
  25. package/src/agentcore-gateway/mcp-connection/schema.d.ts +12 -0
  26. package/src/agentcore-gateway/mcp-connection/schema.json +26 -0
  27. package/src/agentcore-gateway/schema.d.ts +16 -0
  28. package/src/agentcore-gateway/schema.json +65 -0
  29. package/src/connection/generator.d.ts +1 -1
  30. package/src/connection/generator.js +64 -46
  31. package/src/connection/generator.js.map +1 -1
  32. package/src/infra/app/__snapshots__/generator.spec.ts.snap +9 -9
  33. package/src/mcp-server/schema-registry.d.ts +9 -3
  34. package/src/mcp-server/schema-registry.js +22 -6
  35. package/src/mcp-server/schema-registry.js.map +1 -1
  36. package/src/preset/__snapshots__/generator.spec.ts.snap +3 -1
  37. package/src/py/agent/__snapshots__/generator.spec.ts.snap +629 -7
  38. package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client.py.template +9 -3
  39. package/src/py/agent/a2a-connection/generator.js +1 -1
  40. package/src/py/agent/a2a-connection/generator.js.map +1 -1
  41. package/src/py/agent/files/http/init.py.template +5 -23
  42. package/src/py/agent/gateway-connection/files/agent-connection/app/__gatewaySnakeCase___client.py.template +35 -0
  43. package/src/py/agent/gateway-connection/generator.d.ts +10 -0
  44. package/src/py/agent/gateway-connection/generator.js +106 -0
  45. package/src/py/agent/gateway-connection/generator.js.map +1 -0
  46. package/src/py/agent/gateway-connection/schema.d.ts +12 -0
  47. package/src/py/agent/gateway-connection/schema.json +26 -0
  48. package/src/py/agent/generator.js +27 -22
  49. package/src/py/agent/generator.js.map +1 -1
  50. package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +8 -4
  51. package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client.py.template +9 -3
  52. package/src/py/agent/mcp-connection/generator.js +2 -72
  53. package/src/py/agent/mcp-connection/generator.js.map +1 -1
  54. package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +5 -22
  55. package/src/py/fast-api/files/app/__name__/init.py.template +5 -22
  56. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +58 -3
  57. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +619 -2
  58. package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client.ts.template +10 -6
  59. package/src/ts/agent/gateway-connection/files/agent-connection/app/__gatewayKebabCase__-client.ts.template +30 -0
  60. package/src/ts/agent/gateway-connection/generator.d.ts +10 -0
  61. package/src/ts/agent/gateway-connection/generator.js +106 -0
  62. package/src/ts/agent/gateway-connection/generator.js.map +1 -0
  63. package/src/ts/agent/gateway-connection/schema.d.ts +12 -0
  64. package/src/ts/agent/gateway-connection/schema.json +26 -0
  65. package/src/ts/agent/generator.js +23 -19
  66. package/src/ts/agent/generator.js.map +1 -1
  67. package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +9 -4
  68. package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client.ts.template +9 -6
  69. package/src/ts/agent/mcp-connection/generator.js +1 -13
  70. package/src/ts/agent/mcp-connection/generator.js.map +1 -1
  71. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +58 -3
  72. package/src/ts/nx-generator/generator.js +29 -0
  73. package/src/ts/nx-generator/generator.js.map +1 -1
  74. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +86 -39
  75. package/src/utils/agent-chat/agent-chat.d.ts +31 -0
  76. package/src/utils/agent-chat/agent-chat.js +30 -0
  77. package/src/utils/agent-chat/agent-chat.js.map +1 -0
  78. package/src/utils/agent-chat/files/a2a/chat.ts.template +33 -0
  79. package/src/utils/agent-chat/files/ag-ui/chat.ts.template +17 -0
  80. package/src/utils/agent-chat/files/common/agentcore.ts.template +81 -0
  81. package/src/utils/agent-chat/files/http-py/chat.ts.template +43 -0
  82. package/src/utils/agent-chat/files/http-ts/chat.ts.template +54 -0
  83. package/src/utils/agent-connection/agent-connection.d.ts +17 -0
  84. package/src/utils/agent-connection/agent-connection.js +94 -0
  85. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  86. package/src/utils/agent-connection/files/core-gateway/agentcore-gateway-mcp-client.ts.template +78 -0
  87. package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +22 -32
  88. package/src/utils/agent-connection/files/py-core-gateway/agentcore_gateway_mcp_client.py.template +78 -0
  89. package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +5 -18
  90. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +8 -0
  91. package/src/utils/agent-core-constructs/agent-core-constructs.js +54 -1
  92. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  93. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +4 -0
  94. package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +37 -0
  95. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +293 -0
  96. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/readiness-probe/index.js.template +55 -0
  97. package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +242 -0
  98. package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/render-cedar.cjs.template +13 -0
  99. package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +55 -2
  100. package/src/utils/agent-core-constructs/files/terraform/core/agentcore-gateway/gateway.tf.template +14 -0
  101. package/src/utils/versions.d.ts +46 -44
  102. package/src/utils/versions.js +45 -43
  103. package/src/utils/versions.js.map +1 -1
  104. package/src/py/agent/scripts/http/chat.ts.template +0 -38
  105. package/src/ts/agent/scripts/http/chat.ts.template +0 -35
@@ -1,5 +1,574 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
+ exports[`py#agent generator > chat scripts for a2a protocol > should match snapshot for chat scripts with cognito auth > agentcore.ts (a2a, cognito) 1`] = `
4
+ "// Resolves the deployed TestProjectAgent agent from runtime config and authenticates requests to it.
5
+ import { randomUUID } from 'node:crypto';
6
+ import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
7
+
8
+ const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
9
+
10
+ // AgentCore session ids must be at least 33 characters.
11
+ export const SESSION_ID = randomUUID().replaceAll('-', '').padEnd(33, '0');
12
+
13
+ export interface RemoteAgent {
14
+ /** ARN of the deployed Bedrock AgentCore runtime. */
15
+ arn: string;
16
+ /** AWS region parsed from the runtime ARN. */
17
+ region: string;
18
+ }
19
+
20
+ // Returns the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set, otherwise \`undefined\` to chat locally.
21
+ export const resolveRemoteAgent = async (): Promise<
22
+ RemoteAgent | undefined
23
+ > => {
24
+ const application = process.env.RUNTIME_CONFIG_APP_ID;
25
+ if (!application) {
26
+ return undefined;
27
+ }
28
+ const config = (await getAppConfig('agentcore', {
29
+ application,
30
+ environment: 'default',
31
+ transform: 'json',
32
+ })) as { agentRuntimes?: Record<string, string> };
33
+ const arn = config?.agentRuntimes?.['TestProjectAgent'];
34
+ if (!arn) {
35
+ throw new Error(
36
+ \`No deployed agent named 'TestProjectAgent' found in runtime configuration (application \${application}).\`,
37
+ );
38
+ }
39
+ return { arn, region: arn.split(':')[3] };
40
+ };
41
+
42
+ /** The Cognito access token used to authenticate with the deployed agent. */
43
+ export const getAccessToken = (): string => {
44
+ const accessToken = process.env.AGENT_ACCESS_TOKEN;
45
+ if (!accessToken) {
46
+ throw new Error(
47
+ 'AGENT_ACCESS_TOKEN is not set. Provide a Cognito access token to chat with the deployed agent.',
48
+ );
49
+ }
50
+ return accessToken;
51
+ };
52
+
53
+ // A \`fetch\` that authenticates requests to the deployed agent and forwards the session id.
54
+ export const createAgentCoreFetch = (): typeof fetch => {
55
+ const accessToken = getAccessToken();
56
+ return (input, init) => {
57
+ const headers = new Headers(init?.headers);
58
+ headers.set(SESSION_HEADER, SESSION_ID);
59
+ headers.set('Authorization', \`Bearer \${accessToken}\`);
60
+ return fetch(input, { ...init, headers });
61
+ };
62
+ };
63
+ "
64
+ `;
65
+
66
+ exports[`py#agent generator > chat scripts for a2a protocol > should match snapshot for chat scripts with cognito auth > chat.ts (a2a, cognito) 1`] = `
67
+ "// Chat CLI for TestProjectAgent (A2A protocol). Connects to the local
68
+ // \`serve-local\` server, or the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set.
69
+ import {
70
+ ClientFactory,
71
+ ClientFactoryOptions,
72
+ DefaultAgentCardResolver,
73
+ JsonRpcTransportFactory,
74
+ } from '@a2a-js/sdk/client';
75
+ import { A2AChatAdapter, chatLoop } from 'agent-chat-cli';
76
+ import { createAgentCoreFetch, resolveRemoteAgent } from './agentcore.js';
77
+
78
+ const remote = await resolveRemoteAgent();
79
+
80
+ const url = remote
81
+ ? \`https://bedrock-agentcore.\${remote.region}.amazonaws.com/runtimes/\${encodeURIComponent(remote.arn)}/invocations/\`
82
+ : process.env.URL!;
83
+
84
+ // Remote requests are authenticated via a custom fetch; locally the default client talks plain HTTP.
85
+ const clientFactory = remote
86
+ ? new ClientFactory({
87
+ ...ClientFactoryOptions.default,
88
+ transports: [
89
+ new JsonRpcTransportFactory({
90
+ fetchImpl: createAgentCoreFetch(),
91
+ }),
92
+ ],
93
+ cardResolver: new DefaultAgentCardResolver({
94
+ fetchImpl: createAgentCoreFetch(),
95
+ }),
96
+ })
97
+ : undefined;
98
+
99
+ await chatLoop(new A2AChatAdapter({ clientFactory }), url);
100
+ "
101
+ `;
102
+
103
+ exports[`py#agent generator > chat scripts for a2a protocol > should match snapshot for chat scripts with iam auth > agentcore.ts (a2a, iam) 1`] = `
104
+ "// Resolves the deployed TestProjectAgent agent from runtime config and authenticates requests to it.
105
+ import { randomUUID } from 'node:crypto';
106
+ import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
107
+ import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
108
+ import { AwsClient } from 'aws4fetch';
109
+
110
+ const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
111
+
112
+ // AgentCore session ids must be at least 33 characters.
113
+ export const SESSION_ID = randomUUID().replaceAll('-', '').padEnd(33, '0');
114
+
115
+ export interface RemoteAgent {
116
+ /** ARN of the deployed Bedrock AgentCore runtime. */
117
+ arn: string;
118
+ /** AWS region parsed from the runtime ARN. */
119
+ region: string;
120
+ }
121
+
122
+ // Returns the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set, otherwise \`undefined\` to chat locally.
123
+ export const resolveRemoteAgent = async (): Promise<
124
+ RemoteAgent | undefined
125
+ > => {
126
+ const application = process.env.RUNTIME_CONFIG_APP_ID;
127
+ if (!application) {
128
+ return undefined;
129
+ }
130
+ const config = (await getAppConfig('agentcore', {
131
+ application,
132
+ environment: 'default',
133
+ transform: 'json',
134
+ })) as { agentRuntimes?: Record<string, string> };
135
+ const arn = config?.agentRuntimes?.['TestProjectAgent'];
136
+ if (!arn) {
137
+ throw new Error(
138
+ \`No deployed agent named 'TestProjectAgent' found in runtime configuration (application \${application}).\`,
139
+ );
140
+ }
141
+ return { arn, region: arn.split(':')[3] };
142
+ };
143
+
144
+ // A \`fetch\` that authenticates requests to the deployed agent and forwards the session id.
145
+ export const createAgentCoreFetch = (region: string): typeof fetch => {
146
+ const credentialProvider = fromNodeProviderChain();
147
+ return async (input, init) => {
148
+ const headers = new Headers(init?.headers);
149
+ headers.set(SESSION_HEADER, SESSION_ID);
150
+ const client = new AwsClient({
151
+ ...(await credentialProvider()),
152
+ service: 'bedrock-agentcore',
153
+ region,
154
+ });
155
+ return client.fetch(input, { ...init, headers });
156
+ };
157
+ };
158
+ "
159
+ `;
160
+
161
+ exports[`py#agent generator > chat scripts for a2a protocol > should match snapshot for chat scripts with iam auth > chat.ts (a2a, iam) 1`] = `
162
+ "// Chat CLI for TestProjectAgent (A2A protocol). Connects to the local
163
+ // \`serve-local\` server, or the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set.
164
+ import {
165
+ ClientFactory,
166
+ ClientFactoryOptions,
167
+ DefaultAgentCardResolver,
168
+ JsonRpcTransportFactory,
169
+ } from '@a2a-js/sdk/client';
170
+ import { A2AChatAdapter, chatLoop } from 'agent-chat-cli';
171
+ import { createAgentCoreFetch, resolveRemoteAgent } from './agentcore.js';
172
+
173
+ const remote = await resolveRemoteAgent();
174
+
175
+ const url = remote
176
+ ? \`https://bedrock-agentcore.\${remote.region}.amazonaws.com/runtimes/\${encodeURIComponent(remote.arn)}/invocations/\`
177
+ : process.env.URL!;
178
+
179
+ // Remote requests are authenticated via a custom fetch; locally the default client talks plain HTTP.
180
+ const clientFactory = remote
181
+ ? new ClientFactory({
182
+ ...ClientFactoryOptions.default,
183
+ transports: [
184
+ new JsonRpcTransportFactory({
185
+ fetchImpl: createAgentCoreFetch(remote.region),
186
+ }),
187
+ ],
188
+ cardResolver: new DefaultAgentCardResolver({
189
+ fetchImpl: createAgentCoreFetch(remote.region),
190
+ }),
191
+ })
192
+ : undefined;
193
+
194
+ await chatLoop(new A2AChatAdapter({ clientFactory }), url);
195
+ "
196
+ `;
197
+
198
+ exports[`py#agent generator > chat scripts for ag-ui protocol > should match snapshot for chat scripts with cognito auth > agentcore.ts (ag-ui, cognito) 1`] = `
199
+ "// Resolves the deployed TestProjectAgent agent from runtime config and authenticates requests to it.
200
+ import { randomUUID } from 'node:crypto';
201
+ import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
202
+
203
+ const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
204
+
205
+ // AgentCore session ids must be at least 33 characters.
206
+ export const SESSION_ID = randomUUID().replaceAll('-', '').padEnd(33, '0');
207
+
208
+ export interface RemoteAgent {
209
+ /** ARN of the deployed Bedrock AgentCore runtime. */
210
+ arn: string;
211
+ /** AWS region parsed from the runtime ARN. */
212
+ region: string;
213
+ }
214
+
215
+ // Returns the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set, otherwise \`undefined\` to chat locally.
216
+ export const resolveRemoteAgent = async (): Promise<
217
+ RemoteAgent | undefined
218
+ > => {
219
+ const application = process.env.RUNTIME_CONFIG_APP_ID;
220
+ if (!application) {
221
+ return undefined;
222
+ }
223
+ const config = (await getAppConfig('agentcore', {
224
+ application,
225
+ environment: 'default',
226
+ transform: 'json',
227
+ })) as { agentRuntimes?: Record<string, string> };
228
+ const arn = config?.agentRuntimes?.['TestProjectAgent'];
229
+ if (!arn) {
230
+ throw new Error(
231
+ \`No deployed agent named 'TestProjectAgent' found in runtime configuration (application \${application}).\`,
232
+ );
233
+ }
234
+ return { arn, region: arn.split(':')[3] };
235
+ };
236
+
237
+ /** The Cognito access token used to authenticate with the deployed agent. */
238
+ export const getAccessToken = (): string => {
239
+ const accessToken = process.env.AGENT_ACCESS_TOKEN;
240
+ if (!accessToken) {
241
+ throw new Error(
242
+ 'AGENT_ACCESS_TOKEN is not set. Provide a Cognito access token to chat with the deployed agent.',
243
+ );
244
+ }
245
+ return accessToken;
246
+ };
247
+
248
+ // A \`fetch\` that authenticates requests to the deployed agent and forwards the session id.
249
+ export const createAgentCoreFetch = (): typeof fetch => {
250
+ const accessToken = getAccessToken();
251
+ return (input, init) => {
252
+ const headers = new Headers(init?.headers);
253
+ headers.set(SESSION_HEADER, SESSION_ID);
254
+ headers.set('Authorization', \`Bearer \${accessToken}\`);
255
+ return fetch(input, { ...init, headers });
256
+ };
257
+ };
258
+ "
259
+ `;
260
+
261
+ exports[`py#agent generator > chat scripts for ag-ui protocol > should match snapshot for chat scripts with cognito auth > chat.ts (ag-ui, cognito) 1`] = `
262
+ "// Chat CLI for TestProjectAgent (AG-UI protocol). Connects to the local
263
+ // \`serve-local\` server, or the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set.
264
+ import { AGUIChatAdapter, chatLoop } from 'agent-chat-cli';
265
+ import { createAgentCoreFetch, resolveRemoteAgent } from './agentcore.js';
266
+
267
+ const remote = await resolveRemoteAgent();
268
+
269
+ const url = remote
270
+ ? \`https://bedrock-agentcore.\${remote.region}.amazonaws.com/runtimes/\${encodeURIComponent(remote.arn)}/invocations?qualifier=DEFAULT\`
271
+ : process.env.URL!;
272
+
273
+ // Remote requests are authenticated via a custom fetch; locally the default agent talks plain HTTP.
274
+ const fetchImpl = remote ? createAgentCoreFetch() : undefined;
275
+
276
+ await chatLoop(new AGUIChatAdapter({ fetch: fetchImpl }), url);
277
+ "
278
+ `;
279
+
280
+ exports[`py#agent generator > chat scripts for ag-ui protocol > should match snapshot for chat scripts with iam auth > agentcore.ts (ag-ui, iam) 1`] = `
281
+ "// Resolves the deployed TestProjectAgent agent from runtime config and authenticates requests to it.
282
+ import { randomUUID } from 'node:crypto';
283
+ import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
284
+ import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
285
+ import { AwsClient } from 'aws4fetch';
286
+
287
+ const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
288
+
289
+ // AgentCore session ids must be at least 33 characters.
290
+ export const SESSION_ID = randomUUID().replaceAll('-', '').padEnd(33, '0');
291
+
292
+ export interface RemoteAgent {
293
+ /** ARN of the deployed Bedrock AgentCore runtime. */
294
+ arn: string;
295
+ /** AWS region parsed from the runtime ARN. */
296
+ region: string;
297
+ }
298
+
299
+ // Returns the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set, otherwise \`undefined\` to chat locally.
300
+ export const resolveRemoteAgent = async (): Promise<
301
+ RemoteAgent | undefined
302
+ > => {
303
+ const application = process.env.RUNTIME_CONFIG_APP_ID;
304
+ if (!application) {
305
+ return undefined;
306
+ }
307
+ const config = (await getAppConfig('agentcore', {
308
+ application,
309
+ environment: 'default',
310
+ transform: 'json',
311
+ })) as { agentRuntimes?: Record<string, string> };
312
+ const arn = config?.agentRuntimes?.['TestProjectAgent'];
313
+ if (!arn) {
314
+ throw new Error(
315
+ \`No deployed agent named 'TestProjectAgent' found in runtime configuration (application \${application}).\`,
316
+ );
317
+ }
318
+ return { arn, region: arn.split(':')[3] };
319
+ };
320
+
321
+ // A \`fetch\` that authenticates requests to the deployed agent and forwards the session id.
322
+ export const createAgentCoreFetch = (region: string): typeof fetch => {
323
+ const credentialProvider = fromNodeProviderChain();
324
+ return async (input, init) => {
325
+ const headers = new Headers(init?.headers);
326
+ headers.set(SESSION_HEADER, SESSION_ID);
327
+ const client = new AwsClient({
328
+ ...(await credentialProvider()),
329
+ service: 'bedrock-agentcore',
330
+ region,
331
+ });
332
+ return client.fetch(input, { ...init, headers });
333
+ };
334
+ };
335
+ "
336
+ `;
337
+
338
+ exports[`py#agent generator > chat scripts for ag-ui protocol > should match snapshot for chat scripts with iam auth > chat.ts (ag-ui, iam) 1`] = `
339
+ "// Chat CLI for TestProjectAgent (AG-UI protocol). Connects to the local
340
+ // \`serve-local\` server, or the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set.
341
+ import { AGUIChatAdapter, chatLoop } from 'agent-chat-cli';
342
+ import { createAgentCoreFetch, resolveRemoteAgent } from './agentcore.js';
343
+
344
+ const remote = await resolveRemoteAgent();
345
+
346
+ const url = remote
347
+ ? \`https://bedrock-agentcore.\${remote.region}.amazonaws.com/runtimes/\${encodeURIComponent(remote.arn)}/invocations?qualifier=DEFAULT\`
348
+ : process.env.URL!;
349
+
350
+ // Remote requests are authenticated via a custom fetch; locally the default agent talks plain HTTP.
351
+ const fetchImpl = remote ? createAgentCoreFetch(remote.region) : undefined;
352
+
353
+ await chatLoop(new AGUIChatAdapter({ fetch: fetchImpl }), url);
354
+ "
355
+ `;
356
+
357
+ exports[`py#agent generator > chat scripts for http protocol > should match snapshot for chat scripts with cognito auth > agentcore.ts (http, cognito) 1`] = `
358
+ "// Resolves the deployed TestProjectAgent agent from runtime config and authenticates requests to it.
359
+ import { randomUUID } from 'node:crypto';
360
+ import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
361
+
362
+ const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
363
+
364
+ // AgentCore session ids must be at least 33 characters.
365
+ export const SESSION_ID = randomUUID().replaceAll('-', '').padEnd(33, '0');
366
+
367
+ export interface RemoteAgent {
368
+ /** ARN of the deployed Bedrock AgentCore runtime. */
369
+ arn: string;
370
+ /** AWS region parsed from the runtime ARN. */
371
+ region: string;
372
+ }
373
+
374
+ // Returns the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set, otherwise \`undefined\` to chat locally.
375
+ export const resolveRemoteAgent = async (): Promise<
376
+ RemoteAgent | undefined
377
+ > => {
378
+ const application = process.env.RUNTIME_CONFIG_APP_ID;
379
+ if (!application) {
380
+ return undefined;
381
+ }
382
+ const config = (await getAppConfig('agentcore', {
383
+ application,
384
+ environment: 'default',
385
+ transform: 'json',
386
+ })) as { agentRuntimes?: Record<string, string> };
387
+ const arn = config?.agentRuntimes?.['TestProjectAgent'];
388
+ if (!arn) {
389
+ throw new Error(
390
+ \`No deployed agent named 'TestProjectAgent' found in runtime configuration (application \${application}).\`,
391
+ );
392
+ }
393
+ return { arn, region: arn.split(':')[3] };
394
+ };
395
+
396
+ /** The Cognito access token used to authenticate with the deployed agent. */
397
+ export const getAccessToken = (): string => {
398
+ const accessToken = process.env.AGENT_ACCESS_TOKEN;
399
+ if (!accessToken) {
400
+ throw new Error(
401
+ 'AGENT_ACCESS_TOKEN is not set. Provide a Cognito access token to chat with the deployed agent.',
402
+ );
403
+ }
404
+ return accessToken;
405
+ };
406
+
407
+ // A \`fetch\` that authenticates requests to the deployed agent and forwards the session id.
408
+ export const createAgentCoreFetch = (): typeof fetch => {
409
+ const accessToken = getAccessToken();
410
+ return (input, init) => {
411
+ const headers = new Headers(init?.headers);
412
+ headers.set(SESSION_HEADER, SESSION_ID);
413
+ headers.set('Authorization', \`Bearer \${accessToken}\`);
414
+ return fetch(input, { ...init, headers });
415
+ };
416
+ };
417
+ "
418
+ `;
419
+
420
+ exports[`py#agent generator > chat scripts for http protocol > should match snapshot for chat scripts with cognito auth > chat.ts (http, cognito) 1`] = `
421
+ "// Chat CLI for TestProjectAgent (Python FastAPI / JSONL streaming), using the
422
+ // generated client. Connects to the local \`serve-local\` server, or the deployed
423
+ // agent when \`RUNTIME_CONFIG_APP_ID\` is set.
424
+ import { chatLoop, type ChatAdapter } from 'agent-chat-cli';
425
+ import { TestProjectAgent } from './generated/client.gen.js';
426
+ import {
427
+ createAgentCoreFetch,
428
+ resolveRemoteAgent,
429
+ SESSION_ID,
430
+ } from './agentcore.js';
431
+
432
+ const SESSION_ID_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
433
+
434
+ const remote = await resolveRemoteAgent();
435
+
436
+ class TestProjectAgentAdapter implements ChatAdapter {
437
+ private client!: TestProjectAgent;
438
+
439
+ async connect(url: string) {
440
+ this.client = remote
441
+ ? new TestProjectAgent({
442
+ url: \`https://bedrock-agentcore.\${remote.region}.amazonaws.com/runtimes/\${encodeURIComponent(remote.arn)}\`,
443
+ fetch: createAgentCoreFetch(),
444
+ })
445
+ : new TestProjectAgent({
446
+ url,
447
+ fetch: (input, init) => {
448
+ const headers = new Headers(init?.headers);
449
+ headers.set(SESSION_ID_HEADER, SESSION_ID);
450
+ return fetch(input, { ...init, headers });
451
+ },
452
+ });
453
+ return { agentName: 'TestProjectAgent' };
454
+ }
455
+
456
+ async *sendMessage(text: string): AsyncIterable<string> {
457
+ for await (const chunk of this.client.invoke({ message: text })) {
458
+ if (typeof chunk.content === 'string') yield chunk.content;
459
+ }
460
+ }
461
+ }
462
+
463
+ await chatLoop(new TestProjectAgentAdapter(), process.env.URL ?? '');
464
+ "
465
+ `;
466
+
467
+ exports[`py#agent generator > chat scripts for http protocol > should match snapshot for chat scripts with iam auth > agentcore.ts (http, iam) 1`] = `
468
+ "// Resolves the deployed TestProjectAgent agent from runtime config and authenticates requests to it.
469
+ import { randomUUID } from 'node:crypto';
470
+ import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
471
+ import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
472
+ import { AwsClient } from 'aws4fetch';
473
+
474
+ const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
475
+
476
+ // AgentCore session ids must be at least 33 characters.
477
+ export const SESSION_ID = randomUUID().replaceAll('-', '').padEnd(33, '0');
478
+
479
+ export interface RemoteAgent {
480
+ /** ARN of the deployed Bedrock AgentCore runtime. */
481
+ arn: string;
482
+ /** AWS region parsed from the runtime ARN. */
483
+ region: string;
484
+ }
485
+
486
+ // Returns the deployed agent when \`RUNTIME_CONFIG_APP_ID\` is set, otherwise \`undefined\` to chat locally.
487
+ export const resolveRemoteAgent = async (): Promise<
488
+ RemoteAgent | undefined
489
+ > => {
490
+ const application = process.env.RUNTIME_CONFIG_APP_ID;
491
+ if (!application) {
492
+ return undefined;
493
+ }
494
+ const config = (await getAppConfig('agentcore', {
495
+ application,
496
+ environment: 'default',
497
+ transform: 'json',
498
+ })) as { agentRuntimes?: Record<string, string> };
499
+ const arn = config?.agentRuntimes?.['TestProjectAgent'];
500
+ if (!arn) {
501
+ throw new Error(
502
+ \`No deployed agent named 'TestProjectAgent' found in runtime configuration (application \${application}).\`,
503
+ );
504
+ }
505
+ return { arn, region: arn.split(':')[3] };
506
+ };
507
+
508
+ // A \`fetch\` that authenticates requests to the deployed agent and forwards the session id.
509
+ export const createAgentCoreFetch = (region: string): typeof fetch => {
510
+ const credentialProvider = fromNodeProviderChain();
511
+ return async (input, init) => {
512
+ const headers = new Headers(init?.headers);
513
+ headers.set(SESSION_HEADER, SESSION_ID);
514
+ const client = new AwsClient({
515
+ ...(await credentialProvider()),
516
+ service: 'bedrock-agentcore',
517
+ region,
518
+ });
519
+ return client.fetch(input, { ...init, headers });
520
+ };
521
+ };
522
+ "
523
+ `;
524
+
525
+ exports[`py#agent generator > chat scripts for http protocol > should match snapshot for chat scripts with iam auth > chat.ts (http, iam) 1`] = `
526
+ "// Chat CLI for TestProjectAgent (Python FastAPI / JSONL streaming), using the
527
+ // generated client. Connects to the local \`serve-local\` server, or the deployed
528
+ // agent when \`RUNTIME_CONFIG_APP_ID\` is set.
529
+ import { chatLoop, type ChatAdapter } from 'agent-chat-cli';
530
+ import { TestProjectAgent } from './generated/client.gen.js';
531
+ import {
532
+ createAgentCoreFetch,
533
+ resolveRemoteAgent,
534
+ SESSION_ID,
535
+ } from './agentcore.js';
536
+
537
+ const SESSION_ID_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
538
+
539
+ const remote = await resolveRemoteAgent();
540
+
541
+ class TestProjectAgentAdapter implements ChatAdapter {
542
+ private client!: TestProjectAgent;
543
+
544
+ async connect(url: string) {
545
+ this.client = remote
546
+ ? new TestProjectAgent({
547
+ url: \`https://bedrock-agentcore.\${remote.region}.amazonaws.com/runtimes/\${encodeURIComponent(remote.arn)}\`,
548
+ fetch: createAgentCoreFetch(remote.region),
549
+ })
550
+ : new TestProjectAgent({
551
+ url,
552
+ fetch: (input, init) => {
553
+ const headers = new Headers(init?.headers);
554
+ headers.set(SESSION_ID_HEADER, SESSION_ID);
555
+ return fetch(input, { ...init, headers });
556
+ },
557
+ });
558
+ return { agentName: 'TestProjectAgent' };
559
+ }
560
+
561
+ async *sendMessage(text: string): AsyncIterable<string> {
562
+ for await (const chunk of this.client.invoke({ message: text })) {
563
+ if (typeof chunk.content === 'string') yield chunk.content;
564
+ }
565
+ }
566
+ }
567
+
568
+ await chatLoop(new TestProjectAgentAdapter(), process.env.URL ?? '');
569
+ "
570
+ `;
571
+
3
572
  exports[`py#agent generator > should match snapshot for BedrockAgentCoreRuntime generated constructs files > agent-Dockerfile 1`] = `
4
573
  "FROM public.ecr.aws/docker/library/python:3.14-slim
5
574
 
@@ -593,6 +1162,59 @@ resource "aws_bedrockagentcore_agent_runtime" "agent_runtime" {
593
1162
  ]
594
1163
  }
595
1164
 
1165
+ # MCP consumers (e.g. gateway targets, which fetch tools at creation) can race
1166
+ # the runtime's first cold start, so probe it until it serves MCP. The ARN
1167
+ # output is routed through this resource so consumers wait for readiness.
1168
+ resource "null_resource" "runtime_ready" {
1169
+ count = var.server_protocol == "MCP" ? 1 : 0
1170
+
1171
+ triggers = {
1172
+ runtime_arn = aws_bedrockagentcore_agent_runtime.agent_runtime.agent_runtime_arn
1173
+ }
1174
+
1175
+ provisioner "local-exec" {
1176
+ command = <<-EOT
1177
+ uv run --with boto3 python -c "
1178
+ import boto3
1179
+ import json
1180
+ import time
1181
+ import uuid
1182
+
1183
+ runtime_arn = '\${self.triggers.runtime_arn}'
1184
+ client = boto3.client('bedrock-agentcore')
1185
+ initialize_request = json.dumps({
1186
+ 'jsonrpc': '2.0',
1187
+ 'id': 1,
1188
+ 'method': 'initialize',
1189
+ 'params': {
1190
+ 'protocolVersion': '2025-03-26',
1191
+ 'capabilities': {},
1192
+ 'clientInfo': {'name': 'readiness-probe', 'version': '1.0'},
1193
+ },
1194
+ })
1195
+
1196
+ deadline = time.time() + 3 * 60
1197
+ while True:
1198
+ try:
1199
+ client.invoke_agent_runtime(
1200
+ agentRuntimeArn=runtime_arn,
1201
+ runtimeSessionId=f'readiness-probe-{uuid.uuid4()}',
1202
+ contentType='application/json',
1203
+ accept='application/json, text/event-stream',
1204
+ payload=initialize_request,
1205
+ )
1206
+ break
1207
+ except Exception:
1208
+ if time.time() >= deadline:
1209
+ raise
1210
+ time.sleep(5)
1211
+
1212
+ print(f'Runtime {runtime_arn} is serving MCP')
1213
+ "
1214
+ EOT
1215
+ }
1216
+ }
1217
+
596
1218
  # Outputs
597
1219
  output "agent_core_runtime_role_arn" {
598
1220
  description = "ARN of the Agent Core Runtime IAM role"
@@ -610,8 +1232,8 @@ output "agent_runtime_name" {
610
1232
  }
611
1233
 
612
1234
  output "agent_core_runtime_arn" {
613
- description = "ARN of the Bedrock Agent Core runtime"
614
- value = aws_bedrockagentcore_agent_runtime.agent_runtime.agent_runtime_arn
1235
+ description = "ARN of the Bedrock Agent Core runtime. For MCP runtimes the value flows through the readiness probe, so consumers wait until the runtime serves MCP."
1236
+ value = var.server_protocol == "MCP" ? null_resource.runtime_ready[0].triggers.runtime_arn : aws_bedrockagentcore_agent_runtime.agent_runtime.agent_runtime_arn
615
1237
  }
616
1238
 
617
1239
  output "agent_runtime_id" {
@@ -749,17 +1371,17 @@ dependencies = [
749
1371
  "proj.agent_connection",
750
1372
  "aws-lambda-powertools==3.29.0",
751
1373
  "aws-opentelemetry-distro==0.17.1",
752
- "bedrock-agentcore==1.14.0",
753
- "boto3==1.43.24",
754
- "fastapi==0.136.3",
1374
+ "bedrock-agentcore==1.14.1",
1375
+ "boto3==1.43.29",
1376
+ "fastapi==0.137.1",
755
1377
  "mcp==1.27.2",
756
- "strands-agents==1.42.0",
1378
+ "strands-agents==1.43.0",
757
1379
  "strands-agents-tools==0.8.0",
758
1380
  "uvicorn==0.49.0"
759
1381
  ]
760
1382
 
761
1383
  [dependency-groups]
762
- dev = [ "fastapi[standard]==0.136.3" ]
1384
+ dev = [ "fastapi[standard]==0.137.1" ]
763
1385
 
764
1386
  [tool.uv]
765
1387
  dev-dependencies = [ ]
@@ -4,7 +4,7 @@ from strands.agent.a2a_agent import A2AAgent
4
4
 
5
5
  from <%- agentConnectionModuleName %>.core.agentcore_a2a_client import AgentCoreA2aClient
6
6
  from <%- agentConnectionModuleName %>.core.runtime_config import (
7
- get_connected_agent_runtime_arn,
7
+ get_agentcore_runtime_config,
8
8
  )
9
9
 
10
10
 
@@ -17,6 +17,12 @@ class <%- targetAgentClassName %>Client:
17
17
  return AgentCoreA2aClient.without_auth(
18
18
  "http://localhost:<%- targetAgentPort %>/"
19
19
  )
20
- return AgentCoreA2aClient.with_iam_auth(
21
- get_connected_agent_runtime_arn("<%- targetAgentClassName %>")
20
+ config = get_agentcore_runtime_config()
21
+ agent_runtime_arn = config.get("agentRuntimes", {}).get(
22
+ "<%- targetAgentClassName %>"
22
23
  )
24
+ if not agent_runtime_arn:
25
+ raise RuntimeError(
26
+ "No connected agent runtime named '<%- targetAgentClassName %>' found in runtime configuration."
27
+ )
28
+ return AgentCoreA2aClient.with_iam_auth(agent_runtime_arn)
@@ -133,7 +133,7 @@ const addToolToAgent = async (tree, filePath, toolName) => {
133
133
  * top of the function body.
134
134
  */
135
135
  const addClientToolToGetAgent = async (tree, filePath, clientClassName, clientVarName, toolName, targetAgentClassName) => {
136
- if (await (0, ast_1.matchGritQL)(tree, filePath, `\`${clientClassName}.create\``)) {
136
+ if (await (0, ast_1.matchGritQL)(tree, filePath, py(`\`${clientClassName}.create\``))) {
137
137
  return;
138
138
  }
139
139
  // The tool function we'll insert. Strands tools in Python are just