@aws/agentcore 1.0.0-preview.12 → 1.0.0-preview.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.
- package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +414 -14
- package/dist/assets/cdk/bin/cdk.ts +49 -5
- package/dist/assets/cdk/lib/cdk-stack.ts +162 -1
- package/dist/assets/cdk/test/cdk.test.ts +2 -0
- package/dist/assets/python/a2a/langchain_langgraph/base/pyproject.toml +1 -1
- package/dist/assets/python/agui/googleadk/base/pyproject.toml +1 -1
- package/dist/assets/python/agui/langchain_langgraph/base/pyproject.toml +1 -1
- package/dist/assets/python/http/autogen/base/pyproject.toml +1 -1
- package/dist/assets/python/http/langchain_langgraph/base/pyproject.toml +1 -1
- package/dist/assets/python/http/openaiagents/base/pyproject.toml +1 -1
- package/dist/assets/python/http/strands/base/main.py +39 -2
- package/dist/assets/python/http/strands/capabilities/payments/__init__.py +4 -0
- package/dist/assets/python/http/strands/capabilities/payments/payments.py +142 -0
- package/dist/cli/index.mjs +571 -505
- package/dist/lib/packaging/helpers.d.ts.map +1 -1
- package/dist/lib/packaging/helpers.js +50 -10
- package/dist/lib/packaging/helpers.js.map +1 -1
- package/dist/lib/utils/env.d.ts +4 -0
- package/dist/lib/utils/env.d.ts.map +1 -1
- package/dist/lib/utils/env.js +18 -0
- package/dist/lib/utils/env.js.map +1 -1
- package/dist/lib/utils/index.d.ts +1 -1
- package/dist/lib/utils/index.d.ts.map +1 -1
- package/dist/lib/utils/index.js +2 -1
- package/dist/lib/utils/index.js.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +57 -2
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/agentcore-project.js +61 -5
- package/dist/schema/schemas/agentcore-project.js.map +1 -1
- package/dist/schema/schemas/deployed-state.d.ts +97 -0
- package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
- package/dist/schema/schemas/deployed-state.js +24 -4
- package/dist/schema/schemas/deployed-state.js.map +1 -1
- package/dist/schema/schemas/primitives/harness.d.ts +33 -0
- package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/harness.js +42 -1
- package/dist/schema/schemas/primitives/harness.js.map +1 -1
- package/dist/schema/schemas/primitives/index.d.ts +4 -2
- package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/index.js +14 -2
- package/dist/schema/schemas/primitives/index.js.map +1 -1
- package/dist/schema/schemas/primitives/payment.d.ts +54 -0
- package/dist/schema/schemas/primitives/payment.d.ts.map +1 -0
- package/dist/schema/schemas/primitives/payment.js +79 -0
- package/dist/schema/schemas/primitives/payment.js.map +1 -0
- package/npm-shrinkwrap.json +748 -342
- package/package.json +2 -1
- package/scripts/run-e2e-local.sh +9 -3
|
@@ -73,12 +73,14 @@ async function main() {
|
|
|
73
73
|
const spec = await configIO.readProjectSpec();
|
|
74
74
|
const targets = await configIO.readAWSDeploymentTargets();
|
|
75
75
|
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
// dynamically and cast the resulting object.
|
|
76
|
+
// The vended CDK project compiles against the published @aws/agentcore-cdk
|
|
77
|
+
// schema type, which may lag the CLI's own AgentCoreProjectSpec (e.g. payments,
|
|
78
|
+
// harnesses, gateway fields). Cast once so those fields are reachable.
|
|
80
79
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
80
|
const specAny = spec as any;
|
|
81
|
+
|
|
82
|
+
// Extract MCP configuration from project spec.
|
|
83
|
+
// Gateway fields are stored in agentcore.json but may not yet be on the
|
|
82
84
|
const mcpSpec = specAny.agentCoreGateways?.length
|
|
83
85
|
? {
|
|
84
86
|
agentCoreGateways: specAny.agentCoreGateways,
|
|
@@ -113,6 +115,7 @@ async function main() {
|
|
|
113
115
|
apiKeyArn?: string;
|
|
114
116
|
efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
115
117
|
s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
118
|
+
apiFormat?: 'converse_stream' | 'responses' | 'chat_completions';
|
|
116
119
|
}[] = [];
|
|
117
120
|
for (const entry of specAny.harnesses ?? []) {
|
|
118
121
|
const harnessDir = path.resolve(projectRoot, entry.path);
|
|
@@ -131,6 +134,7 @@ async function main() {
|
|
|
131
134
|
apiKeyArn: harnessSpec.model?.apiKeyArn,
|
|
132
135
|
efsAccessPoints: harnessSpec.efsAccessPoints,
|
|
133
136
|
s3AccessPoints: harnessSpec.s3AccessPoints,
|
|
137
|
+
apiFormat: harnessSpec.model?.apiFormat,
|
|
134
138
|
});
|
|
135
139
|
} catch (err) {
|
|
136
140
|
throw new Error(
|
|
@@ -154,11 +158,51 @@ async function main() {
|
|
|
154
158
|
| Record<string, { credentialProviderArn: string; clientSecretArn?: string }>
|
|
155
159
|
| undefined;
|
|
156
160
|
|
|
161
|
+
// Payment credential provider ARNs live in the same credentials map as identity credentials
|
|
162
|
+
const paymentCredentials = credentials;
|
|
163
|
+
|
|
164
|
+
const paymentSpec = specAny.payments?.length
|
|
165
|
+
? specAny.payments.map(
|
|
166
|
+
(p: {
|
|
167
|
+
name: string;
|
|
168
|
+
description?: string;
|
|
169
|
+
authorizerType: 'AWS_IAM' | 'CUSTOM_JWT';
|
|
170
|
+
authorizerConfiguration?: unknown;
|
|
171
|
+
autoPayment?: boolean;
|
|
172
|
+
paymentToolAllowlist?: string[];
|
|
173
|
+
networkPreferences?: string[];
|
|
174
|
+
connectors: { name: string; provider?: string; credentialName: string }[];
|
|
175
|
+
}) => ({
|
|
176
|
+
name: p.name,
|
|
177
|
+
description: p.description,
|
|
178
|
+
authorizerType: p.authorizerType,
|
|
179
|
+
authorizerConfiguration: p.authorizerConfiguration,
|
|
180
|
+
autoPayment: p.autoPayment,
|
|
181
|
+
paymentToolAllowlist: p.paymentToolAllowlist,
|
|
182
|
+
networkPreferences: p.networkPreferences,
|
|
183
|
+
connectors: p.connectors.map(c => {
|
|
184
|
+
const credentialProviderArn = paymentCredentials?.[c.credentialName]?.credentialProviderArn;
|
|
185
|
+
if (!credentialProviderArn) {
|
|
186
|
+
// Fail fast with an actionable message rather than passing an empty
|
|
187
|
+
// ARN that fails opaquely server-side at CreatePaymentConnector.
|
|
188
|
+
throw new Error(
|
|
189
|
+
\`Payment connector "\${c.name}" on manager "\${p.name}" references credential \` +
|
|
190
|
+
\`"\${c.credentialName}", but no deployed credential provider was found for it. \` +
|
|
191
|
+
\`Run \\\`agentcore deploy\\\` so the credential provider is created first.\`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
return { name: c.name, provider: c.provider, credentialProviderArn };
|
|
195
|
+
}),
|
|
196
|
+
})
|
|
197
|
+
)
|
|
198
|
+
: undefined;
|
|
199
|
+
|
|
157
200
|
new AgentCoreStack(app, stackName, {
|
|
158
201
|
spec,
|
|
159
202
|
mcpSpec,
|
|
160
203
|
credentials,
|
|
161
204
|
harnesses: harnessConfigs.length > 0 ? harnessConfigs : undefined,
|
|
205
|
+
paymentSpec,
|
|
162
206
|
env,
|
|
163
207
|
description: \`AgentCore stack for \${spec.name} deployed to \${target.name} (\${target.region})\`,
|
|
164
208
|
tags: {
|
|
@@ -173,7 +217,7 @@ async function main() {
|
|
|
173
217
|
|
|
174
218
|
main().catch((error: unknown) => {
|
|
175
219
|
console.error('AgentCore CDK synthesis failed:', error instanceof Error ? error.message : error);
|
|
176
|
-
process.
|
|
220
|
+
process.exit(1);
|
|
177
221
|
});
|
|
178
222
|
"
|
|
179
223
|
`;
|
|
@@ -300,10 +344,14 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/lib/cdk-stack.ts shou
|
|
|
300
344
|
"import {
|
|
301
345
|
AgentCoreApplication,
|
|
302
346
|
AgentCoreMcp,
|
|
347
|
+
AgentCorePaymentManager,
|
|
348
|
+
AgentCorePaymentConnector,
|
|
303
349
|
type AgentCoreProjectSpec,
|
|
304
350
|
type AgentCoreMcpSpec,
|
|
351
|
+
type CustomJWTAuthorizerConfig,
|
|
305
352
|
} from '@aws/agentcore-cdk';
|
|
306
353
|
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
|
|
354
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
307
355
|
import { Construct } from 'constructs';
|
|
308
356
|
|
|
309
357
|
export interface HarnessConfig {
|
|
@@ -320,6 +368,23 @@ export interface HarnessConfig {
|
|
|
320
368
|
s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
321
369
|
}
|
|
322
370
|
|
|
371
|
+
export interface PaymentConnectorSpec {
|
|
372
|
+
name: string;
|
|
373
|
+
provider: 'CoinbaseCDP' | 'StripePrivy';
|
|
374
|
+
credentialProviderArn: string;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export interface PaymentSpec {
|
|
378
|
+
name: string;
|
|
379
|
+
description?: string;
|
|
380
|
+
authorizerType: 'AWS_IAM' | 'CUSTOM_JWT';
|
|
381
|
+
authorizerConfiguration?: { customJWTAuthorizer: CustomJWTAuthorizerConfig };
|
|
382
|
+
autoPayment?: boolean;
|
|
383
|
+
paymentToolAllowlist?: string[];
|
|
384
|
+
networkPreferences?: string[];
|
|
385
|
+
connectors: PaymentConnectorSpec[];
|
|
386
|
+
}
|
|
387
|
+
|
|
323
388
|
export interface AgentCoreStackProps extends StackProps {
|
|
324
389
|
/**
|
|
325
390
|
* The AgentCore project specification containing agents, memories, and credentials.
|
|
@@ -337,6 +402,30 @@ export interface AgentCoreStackProps extends StackProps {
|
|
|
337
402
|
* Harness role configurations.
|
|
338
403
|
*/
|
|
339
404
|
harnesses?: HarnessConfig[];
|
|
405
|
+
/**
|
|
406
|
+
* Payment specifications with resolved credential provider ARNs.
|
|
407
|
+
*/
|
|
408
|
+
paymentSpec?: PaymentSpec[];
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function toCdkId(name: string): string {
|
|
412
|
+
return name.replace(/_/g, '');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Decide whether a deployed runtime should receive payment env vars + IAM grants.
|
|
417
|
+
* Payments today only ships a runtime shim for Python HTTP runtimes; injecting
|
|
418
|
+
* AGENTCORE_PAYMENT_* env vars into TypeScript / MCP / A2A / AGUI runtimes
|
|
419
|
+
* would surface env vars they cannot consume and would dilute least-privilege
|
|
420
|
+
* IAM grants for runtimes that never call ProcessPayment.
|
|
421
|
+
*/
|
|
422
|
+
function isPaymentEligibleAgent(agent: { entrypoint?: string; protocol?: string }): boolean {
|
|
423
|
+
if (agent.protocol && agent.protocol !== 'HTTP') {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
const entrypoint = typeof agent.entrypoint === 'string' ? agent.entrypoint : '';
|
|
427
|
+
const entrypointFile = entrypoint.split(':')[0] ?? '';
|
|
428
|
+
return entrypointFile.endsWith('.py');
|
|
340
429
|
}
|
|
341
430
|
|
|
342
431
|
/**
|
|
@@ -352,7 +441,7 @@ export class AgentCoreStack extends Stack {
|
|
|
352
441
|
constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
|
|
353
442
|
super(scope, id, props);
|
|
354
443
|
|
|
355
|
-
const { spec, mcpSpec, credentials, harnesses } = props;
|
|
444
|
+
const { spec, mcpSpec, credentials, harnesses, paymentSpec } = props;
|
|
356
445
|
|
|
357
446
|
// Create AgentCoreApplication with all agents and harness roles
|
|
358
447
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -373,6 +462,122 @@ export class AgentCoreStack extends Stack {
|
|
|
373
462
|
});
|
|
374
463
|
}
|
|
375
464
|
|
|
465
|
+
// Create payment infrastructure via CFN constructs
|
|
466
|
+
if (paymentSpec && paymentSpec.length > 0) {
|
|
467
|
+
for (const payment of paymentSpec) {
|
|
468
|
+
const mgrId = toCdkId(payment.name);
|
|
469
|
+
const manager = new AgentCorePaymentManager(this, \`Payment\${mgrId}\`, {
|
|
470
|
+
projectName: spec.name,
|
|
471
|
+
name: payment.name,
|
|
472
|
+
authorizerType: payment.authorizerType,
|
|
473
|
+
description: payment.description,
|
|
474
|
+
authorizerConfiguration: payment.authorizerConfiguration,
|
|
475
|
+
tags: spec.tags,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
const prefix = \`AGENTCORE_PAYMENT_\${payment.name.toUpperCase().replace(/-/g, '_')}\`;
|
|
479
|
+
|
|
480
|
+
// Wire env vars from construct output tokens into eligible agent environments only.
|
|
481
|
+
// See isPaymentEligibleAgent — non-Python or non-HTTP runtimes have no shim that
|
|
482
|
+
// can consume these env vars, and giving them sts:AssumeRole on the
|
|
483
|
+
// ProcessPaymentRole would broaden the privilege surface unnecessarily.
|
|
484
|
+
for (const env of this.application.environments.values()) {
|
|
485
|
+
if (!isPaymentEligibleAgent(env.agent)) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
env.runtime.addEnvironmentVariable(\`\${prefix}_MANAGER_ARN\`, manager.paymentManagerArn);
|
|
489
|
+
env.runtime.addEnvironmentVariable(\`\${prefix}_PROCESS_PAYMENT_ROLE_ARN\`, manager.processPaymentRoleArn);
|
|
490
|
+
|
|
491
|
+
// Grant runtime execution role permission to assume the ProcessPaymentRole.
|
|
492
|
+
// The ProcessPaymentRole's trust policy allows AccountRootPrincipal, but the
|
|
493
|
+
// caller still needs sts:AssumeRole on its own role to perform the assumption.
|
|
494
|
+
env.runtime.role.addToPrincipalPolicy(
|
|
495
|
+
new iam.PolicyStatement({
|
|
496
|
+
actions: ['sts:AssumeRole'],
|
|
497
|
+
resources: [manager.processPaymentRoleArn],
|
|
498
|
+
})
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
// Grant payment data-plane actions directly to the runtime role.
|
|
502
|
+
//
|
|
503
|
+
// NOTE: This deviates from the canonical role model in the AgentCore Payments
|
|
504
|
+
// beta guide, which assigns Get/List/Create instrument+session actions to a
|
|
505
|
+
// separate ManagementRole and limits the agent's role to ProcessPayment only.
|
|
506
|
+
// The current SDK plugin (AgentCorePaymentsPlugin.generate_payment_header)
|
|
507
|
+
// calls GetPaymentInstrument internally during the 402 auto-pay path, so the
|
|
508
|
+
// runtime role needs read access. CreatePaymentSession is included so
|
|
509
|
+
// \`agentcore invoke --auto-session\` works without a separate ManagementRole
|
|
510
|
+
// call. Tighten this if the SDK is updated to accept pre-fetched instrument
|
|
511
|
+
// details and split create-session into a backend-only flow.
|
|
512
|
+
env.runtime.role.addToPrincipalPolicy(
|
|
513
|
+
new iam.PolicyStatement({
|
|
514
|
+
actions: [
|
|
515
|
+
'bedrock-agentcore:GetPaymentInstrument',
|
|
516
|
+
'bedrock-agentcore:ListPaymentInstruments',
|
|
517
|
+
'bedrock-agentcore:GetPaymentInstrumentBalance',
|
|
518
|
+
'bedrock-agentcore:GetPaymentSession',
|
|
519
|
+
'bedrock-agentcore:ListPaymentSessions',
|
|
520
|
+
'bedrock-agentcore:CreatePaymentSession',
|
|
521
|
+
'bedrock-agentcore:ProcessPayment',
|
|
522
|
+
],
|
|
523
|
+
resources: [manager.paymentManagerArn, \`\${manager.paymentManagerArn}/*\`],
|
|
524
|
+
})
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
if (payment.autoPayment !== undefined) {
|
|
528
|
+
env.runtime.addEnvironmentVariable(\`\${prefix}_AUTO_PAYMENT\`, String(payment.autoPayment));
|
|
529
|
+
}
|
|
530
|
+
if (payment.paymentToolAllowlist) {
|
|
531
|
+
env.runtime.addEnvironmentVariable(\`\${prefix}_TOOL_ALLOWLIST\`, payment.paymentToolAllowlist.join(','));
|
|
532
|
+
}
|
|
533
|
+
if (payment.networkPreferences) {
|
|
534
|
+
env.runtime.addEnvironmentVariable(\`\${prefix}_NETWORK_PREFERENCES\`, payment.networkPreferences.join(','));
|
|
535
|
+
}
|
|
536
|
+
if (payment.authorizerType === 'CUSTOM_JWT') {
|
|
537
|
+
env.runtime.addEnvironmentVariable(\`\${prefix}_AUTH_MODE\`, 'bearer');
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Create connectors for this manager
|
|
542
|
+
for (const connector of payment.connectors) {
|
|
543
|
+
const connId = toCdkId(connector.name);
|
|
544
|
+
const conn = new AgentCorePaymentConnector(this, \`Payment\${mgrId}\${connId}\`, {
|
|
545
|
+
projectName: spec.name,
|
|
546
|
+
paymentManager: manager,
|
|
547
|
+
connectorName: connector.name,
|
|
548
|
+
connectorType: connector.provider,
|
|
549
|
+
credentialProviderArn: connector.credentialProviderArn,
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// Wire first connector's ID as env var (eligible agents only)
|
|
553
|
+
if (connector === payment.connectors[0]) {
|
|
554
|
+
for (const env of this.application.environments.values()) {
|
|
555
|
+
if (!isPaymentEligibleAgent(env.agent)) continue;
|
|
556
|
+
env.runtime.addEnvironmentVariable(\`\${prefix}_CONNECTOR_ID\`, conn.paymentConnectorId);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
new CfnOutput(this, \`Payment\${mgrId}\${connId}ConnectorId\`, {
|
|
561
|
+
value: conn.paymentConnectorId,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// CFN Outputs for post-deploy state parsing
|
|
566
|
+
new CfnOutput(this, \`Payment\${mgrId}ManagerArn\`, {
|
|
567
|
+
value: manager.paymentManagerArn,
|
|
568
|
+
});
|
|
569
|
+
new CfnOutput(this, \`Payment\${mgrId}ManagerId\`, {
|
|
570
|
+
value: manager.paymentManagerId,
|
|
571
|
+
});
|
|
572
|
+
new CfnOutput(this, \`Payment\${mgrId}ProcessPaymentRoleArn\`, {
|
|
573
|
+
value: manager.processPaymentRoleArn,
|
|
574
|
+
});
|
|
575
|
+
new CfnOutput(this, \`Payment\${mgrId}ResourceRetrievalRoleArn\`, {
|
|
576
|
+
value: manager.resourceRetrievalRoleArn,
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
376
581
|
// Stack-level output
|
|
377
582
|
new CfnOutput(this, 'StackNameOutput', {
|
|
378
583
|
description: 'Name of the CloudFormation Stack',
|
|
@@ -445,6 +650,8 @@ test('AgentCoreStack synthesizes with empty spec', () => {
|
|
|
445
650
|
evaluators: [],
|
|
446
651
|
onlineEvalConfigs: [],
|
|
447
652
|
policyEngines: [],
|
|
653
|
+
payments: [],
|
|
654
|
+
configBundles: [],
|
|
448
655
|
agentCoreGateways: [],
|
|
449
656
|
mcpRuntimeTools: [],
|
|
450
657
|
unassignedTargets: [],
|
|
@@ -605,6 +812,8 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f
|
|
|
605
812
|
"python/http/strands/base/pyproject.toml",
|
|
606
813
|
"python/http/strands/capabilities/memory/__init__.py",
|
|
607
814
|
"python/http/strands/capabilities/memory/session.py",
|
|
815
|
+
"python/http/strands/capabilities/payments/__init__.py",
|
|
816
|
+
"python/http/strands/capabilities/payments/payments.py",
|
|
608
817
|
"python/mcp/standalone/base/README.md",
|
|
609
818
|
"python/mcp/standalone/base/gitignore.template",
|
|
610
819
|
"python/mcp/standalone/base/main.py",
|
|
@@ -1629,7 +1838,7 @@ dependencies = [
|
|
|
1629
1838
|
{{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
|
|
1630
1839
|
{{/if}}"aws-opentelemetry-distro",
|
|
1631
1840
|
"opentelemetry-instrumentation-langchain >= 0.59.0",
|
|
1632
|
-
"bedrock-agentcore[a2a] >= 1.0
|
|
1841
|
+
"bedrock-agentcore[a2a] >= 1.8.0",
|
|
1633
1842
|
"botocore[crt] >= 1.35.0",
|
|
1634
1843
|
"langgraph >= 0.2.0",
|
|
1635
1844
|
]
|
|
@@ -2276,7 +2485,7 @@ requires-python = ">=3.10"
|
|
|
2276
2485
|
dependencies = [
|
|
2277
2486
|
"ag-ui-adk >= 0.6.0",
|
|
2278
2487
|
"ag-ui-protocol >= 0.1.10",
|
|
2279
|
-
"bedrock-agentcore >= 1.0
|
|
2488
|
+
"bedrock-agentcore >= 1.8.0",
|
|
2280
2489
|
"fastapi >= 0.115.12",
|
|
2281
2490
|
"google-adk >= 1.16.0, < 2.0.0",
|
|
2282
2491
|
"google-genai >= 1.0.0, < 2.0.0",
|
|
@@ -2648,7 +2857,7 @@ dependencies = [
|
|
|
2648
2857
|
{{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
|
|
2649
2858
|
{{/if}}"aws-opentelemetry-distro",
|
|
2650
2859
|
"opentelemetry-instrumentation-langchain >= 0.59.0",
|
|
2651
|
-
"bedrock-agentcore >= 1.0
|
|
2860
|
+
"bedrock-agentcore >= 1.8.0",
|
|
2652
2861
|
"botocore[crt] >= 1.35.0",
|
|
2653
2862
|
"langgraph >= 0.3.25",
|
|
2654
2863
|
"langchain >= 0.3.0",
|
|
@@ -3467,7 +3676,7 @@ dependencies = [
|
|
|
3467
3676
|
"autogen-ext[mcp] >= 0.7.5",
|
|
3468
3677
|
"opentelemetry-distro",
|
|
3469
3678
|
"opentelemetry-exporter-otlp",
|
|
3470
|
-
"bedrock-agentcore >= 1.0
|
|
3679
|
+
"bedrock-agentcore >= 1.8.0",
|
|
3471
3680
|
"botocore[crt] >= 1.35.0",
|
|
3472
3681
|
"tiktoken",
|
|
3473
3682
|
{{#if (eq modelProvider "Bedrock")}}
|
|
@@ -4422,7 +4631,7 @@ dependencies = [
|
|
|
4422
4631
|
"mcp >= 1.19.0",
|
|
4423
4632
|
"langchain-mcp-adapters >= 0.1.11",
|
|
4424
4633
|
"langchain >= 1.0.3",
|
|
4425
|
-
"bedrock-agentcore >= 1.0
|
|
4634
|
+
"bedrock-agentcore >= 1.8.0",
|
|
4426
4635
|
"botocore[crt] >= 1.35.0",
|
|
4427
4636
|
{{#if (eq modelProvider "Bedrock")}}
|
|
4428
4637
|
"langchain-aws >= 1.0.0",
|
|
@@ -4858,7 +5067,7 @@ requires-python = ">=3.10"
|
|
|
4858
5067
|
dependencies = [
|
|
4859
5068
|
"aws-opentelemetry-distro",
|
|
4860
5069
|
"openai-agents >= 0.4.2",
|
|
4861
|
-
"bedrock-agentcore >= 1.0
|
|
5070
|
+
"bedrock-agentcore >= 1.8.0",
|
|
4862
5071
|
"botocore[crt] >= 1.35.0",
|
|
4863
5072
|
{{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
|
|
4864
5073
|
{{/if}}{{/if}}
|
|
@@ -4977,6 +5186,9 @@ from memory.session import get_memory_session_manager
|
|
|
4977
5186
|
{{#if needsOs}}
|
|
4978
5187
|
import os
|
|
4979
5188
|
{{/if}}
|
|
5189
|
+
{{#if hasPayment}}
|
|
5190
|
+
from capabilities.payments.payments import create_payments_plugin, PAYMENT_SYSTEM_PROMPT
|
|
5191
|
+
{{/if}}
|
|
4980
5192
|
|
|
4981
5193
|
app = BedrockAgentCoreApp()
|
|
4982
5194
|
log = app.logger
|
|
@@ -5112,12 +5324,12 @@ class ConfigBundleHook(HookProvider):
|
|
|
5112
5324
|
{{/if}}
|
|
5113
5325
|
|
|
5114
5326
|
{{#if hasMemory}}
|
|
5327
|
+
{{#unless hasPayment}}
|
|
5115
5328
|
def agent_factory():
|
|
5116
5329
|
cache = {}
|
|
5117
5330
|
def get_or_create_agent(session_id, user_id):
|
|
5118
5331
|
key = f"{session_id}/{user_id}"
|
|
5119
5332
|
if key not in cache:
|
|
5120
|
-
# Create an agent for the given session_id and user_id
|
|
5121
5333
|
cache[key] = Agent(
|
|
5122
5334
|
model=load_model(),
|
|
5123
5335
|
session_manager=get_memory_session_manager(session_id, user_id),
|
|
@@ -5128,6 +5340,7 @@ def agent_factory():
|
|
|
5128
5340
|
return cache[key]
|
|
5129
5341
|
return get_or_create_agent
|
|
5130
5342
|
get_or_create_agent = agent_factory()
|
|
5343
|
+
{{/unless}}
|
|
5131
5344
|
{{else}}
|
|
5132
5345
|
{{#if hasConfigBundle}}
|
|
5133
5346
|
def create_agent():
|
|
@@ -5138,6 +5351,7 @@ def create_agent():
|
|
|
5138
5351
|
hooks=[ConfigBundleHook()],
|
|
5139
5352
|
)
|
|
5140
5353
|
{{else}}
|
|
5354
|
+
{{#unless hasPayment}}
|
|
5141
5355
|
_agent = None
|
|
5142
5356
|
|
|
5143
5357
|
def get_or_create_agent():
|
|
@@ -5146,9 +5360,10 @@ def get_or_create_agent():
|
|
|
5146
5360
|
_agent = Agent(
|
|
5147
5361
|
model=load_model(),
|
|
5148
5362
|
system_prompt=DEFAULT_SYSTEM_PROMPT,
|
|
5149
|
-
tools=tools
|
|
5363
|
+
tools=tools,
|
|
5150
5364
|
)
|
|
5151
5365
|
return _agent
|
|
5366
|
+
{{/unless}}
|
|
5152
5367
|
{{/if}}
|
|
5153
5368
|
{{/if}}
|
|
5154
5369
|
|
|
@@ -5157,16 +5372,47 @@ def get_or_create_agent():
|
|
|
5157
5372
|
async def invoke(payload, context):
|
|
5158
5373
|
log.info("Invoking Agent.....")
|
|
5159
5374
|
|
|
5375
|
+
{{#if hasPayment}}
|
|
5376
|
+
user_id = payload.get("user_id") or getattr(context, "user_id", "default-user")
|
|
5377
|
+
instrument_id = payload.get("payment_instrument_id")
|
|
5378
|
+
session_id = payload.get("payment_session_id")
|
|
5379
|
+
payments_plugin = create_payments_plugin(user_id, instrument_id, session_id)
|
|
5380
|
+
plugins = [payments_plugin] if payments_plugin else []
|
|
5381
|
+
{{/if}}
|
|
5382
|
+
|
|
5160
5383
|
{{#if hasMemory}}
|
|
5384
|
+
{{#if hasPayment}}
|
|
5385
|
+
mem_session_id = getattr(context, 'session_id', 'default-session')
|
|
5386
|
+
mem_user_id = getattr(context, 'user_id', 'default-user')
|
|
5387
|
+
agent = Agent(
|
|
5388
|
+
model=load_model(),
|
|
5389
|
+
session_manager=get_memory_session_manager(mem_session_id, mem_user_id),
|
|
5390
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT + PAYMENT_SYSTEM_PROMPT,
|
|
5391
|
+
tools=tools,
|
|
5392
|
+
plugins=plugins,{{#if hasConfigBundle}}
|
|
5393
|
+
hooks=[ConfigBundleHook()],{{/if}}
|
|
5394
|
+
)
|
|
5395
|
+
{{else}}
|
|
5161
5396
|
session_id = getattr(context, 'session_id', 'default-session')
|
|
5162
5397
|
user_id = getattr(context, 'user_id', 'default-user')
|
|
5163
5398
|
agent = get_or_create_agent(session_id, user_id)
|
|
5399
|
+
{{/if}}
|
|
5400
|
+
{{else}}
|
|
5401
|
+
{{#if hasPayment}}
|
|
5402
|
+
agent = Agent(
|
|
5403
|
+
model=load_model(),
|
|
5404
|
+
system_prompt=DEFAULT_SYSTEM_PROMPT + PAYMENT_SYSTEM_PROMPT,
|
|
5405
|
+
tools=tools,
|
|
5406
|
+
plugins=plugins,{{#if hasConfigBundle}}
|
|
5407
|
+
hooks=[ConfigBundleHook()],{{/if}}
|
|
5408
|
+
)
|
|
5164
5409
|
{{else}}
|
|
5165
5410
|
{{#if hasConfigBundle}}
|
|
5166
5411
|
agent = create_agent()
|
|
5167
5412
|
{{else}}
|
|
5168
5413
|
agent = get_or_create_agent()
|
|
5169
5414
|
{{/if}}
|
|
5415
|
+
{{/if}}
|
|
5170
5416
|
{{/if}}
|
|
5171
5417
|
|
|
5172
5418
|
# Execute and format response
|
|
@@ -5479,6 +5725,160 @@ def get_memory_session_manager(session_id: Optional[str], actor_id: str) -> Opti
|
|
|
5479
5725
|
"
|
|
5480
5726
|
`;
|
|
5481
5727
|
|
|
5728
|
+
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/capabilities/payments/__init__.py should match snapshot 1`] = `
|
|
5729
|
+
""""Payment capabilities for Strands agents."""
|
|
5730
|
+
from .payments import create_payments_plugin
|
|
5731
|
+
|
|
5732
|
+
__all__ = ["create_payments_plugin"]
|
|
5733
|
+
"
|
|
5734
|
+
`;
|
|
5735
|
+
|
|
5736
|
+
exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/capabilities/payments/payments.py should match snapshot 1`] = `
|
|
5737
|
+
""""Payment capability -- auto-generated by agentcore CLI.
|
|
5738
|
+
|
|
5739
|
+
Configures AgentCorePaymentsPlugin for Strands agents.
|
|
5740
|
+
Manager config is auto-discovered from AGENTCORE_PAYMENT_*
|
|
5741
|
+
environment variables set at deploy time.
|
|
5742
|
+
|
|
5743
|
+
Uses a per-invocation factory pattern so each request gets its own
|
|
5744
|
+
plugin instance with the correct user_id, instrument_id, and session_id.
|
|
5745
|
+
This prevents concurrency bugs where one user's payment context
|
|
5746
|
+
could leak to another user's request.
|
|
5747
|
+
|
|
5748
|
+
Uses the official SDK plugin which handles:
|
|
5749
|
+
- x402 v1 (body-based) and v2 (header-based) payment detection
|
|
5750
|
+
- Automatic 402 response interception and payment processing
|
|
5751
|
+
- Retry limiting (max 3 payment retries per tool use)
|
|
5752
|
+
- Error management and logging
|
|
5753
|
+
"""
|
|
5754
|
+
import os
|
|
5755
|
+
import logging
|
|
5756
|
+
|
|
5757
|
+
import boto3
|
|
5758
|
+
from bedrock_agentcore.payments.integrations.strands import AgentCorePaymentsPlugin
|
|
5759
|
+
from bedrock_agentcore.payments.integrations.config import AgentCorePaymentsPluginConfig
|
|
5760
|
+
|
|
5761
|
+
logger = logging.getLogger(__name__)
|
|
5762
|
+
|
|
5763
|
+
PAYMENT_SYSTEM_PROMPT = """
|
|
5764
|
+
You have payment capabilities via the x402 protocol:
|
|
5765
|
+
- Use http_request to call HTTP endpoints. 402 Payment Required responses are settled automatically by the plugin and the call is retried.
|
|
5766
|
+
- Use get_payment_session to check your remaining budget before expensive operations
|
|
5767
|
+
- Use get_payment_instrument_balance to check wallet USDC balance
|
|
5768
|
+
- Use list_payment_instruments to see available payment instruments
|
|
5769
|
+
- If budget is low, inform the user before proceeding with paid requests
|
|
5770
|
+
"""
|
|
5771
|
+
|
|
5772
|
+
_manager_arn = None
|
|
5773
|
+
_connector_id = None
|
|
5774
|
+
_process_payment_role_arn = None
|
|
5775
|
+
_name_segment = None
|
|
5776
|
+
_region = None
|
|
5777
|
+
_auth_mode = None
|
|
5778
|
+
_manager_count = 0
|
|
5779
|
+
for key, value in os.environ.items():
|
|
5780
|
+
if key.startswith("AGENTCORE_PAYMENT_") and key.endswith("_MANAGER_ARN"):
|
|
5781
|
+
if _manager_arn is None:
|
|
5782
|
+
_manager_arn = value
|
|
5783
|
+
_name_segment = key[len("AGENTCORE_PAYMENT_"):-len("_MANAGER_ARN")]
|
|
5784
|
+
_manager_count += 1
|
|
5785
|
+
if _manager_count > 1:
|
|
5786
|
+
logger.warning(
|
|
5787
|
+
"Multiple payment managers detected in environment. Using the first one found. "
|
|
5788
|
+
"Remove extra AGENTCORE_PAYMENT_*_MANAGER_ARN env vars to eliminate ambiguity."
|
|
5789
|
+
)
|
|
5790
|
+
_region = os.getenv("AWS_REGION")
|
|
5791
|
+
|
|
5792
|
+
_prefix = f"AGENTCORE_PAYMENT_{_name_segment}_" if _name_segment else "AGENTCORE_PAYMENT_"
|
|
5793
|
+
_auth_mode = os.getenv(f"{_prefix}AUTH_MODE", "sigv4")
|
|
5794
|
+
_connector_id = os.getenv(f"{_prefix}CONNECTOR_ID")
|
|
5795
|
+
_process_payment_role_arn = os.getenv(f"{_prefix}PROCESS_PAYMENT_ROLE_ARN")
|
|
5796
|
+
_auto_payment = os.getenv(f"{_prefix}AUTO_PAYMENT", "true").lower() == "true"
|
|
5797
|
+
_allowlist_raw = os.getenv(f"{_prefix}TOOL_ALLOWLIST")
|
|
5798
|
+
_allowlist = _allowlist_raw.split(",") if _allowlist_raw else None
|
|
5799
|
+
_network_prefs_raw = os.getenv(f"{_prefix}NETWORK_PREFERENCES")
|
|
5800
|
+
_network_prefs = _network_prefs_raw.split(",") if _network_prefs_raw else None
|
|
5801
|
+
|
|
5802
|
+
if not _manager_arn:
|
|
5803
|
+
logger.warning("No payment manager config found in environment")
|
|
5804
|
+
if not _connector_id:
|
|
5805
|
+
logger.warning("No payment connector config found in environment")
|
|
5806
|
+
|
|
5807
|
+
|
|
5808
|
+
def _assume_role_session(role_arn):
|
|
5809
|
+
"""Assume an IAM role and return a boto3 session with temporary credentials."""
|
|
5810
|
+
sts = boto3.client("sts", region_name=_region)
|
|
5811
|
+
creds = sts.assume_role(
|
|
5812
|
+
RoleArn=role_arn,
|
|
5813
|
+
RoleSessionName="agentcore-payment-plugin",
|
|
5814
|
+
)["Credentials"]
|
|
5815
|
+
return boto3.Session(
|
|
5816
|
+
aws_access_key_id=creds["AccessKeyId"],
|
|
5817
|
+
aws_secret_access_key=creds["SecretAccessKey"],
|
|
5818
|
+
aws_session_token=creds["SessionToken"],
|
|
5819
|
+
region_name=_region,
|
|
5820
|
+
)
|
|
5821
|
+
|
|
5822
|
+
|
|
5823
|
+
def create_payments_plugin(user_id, instrument_id=None, session_id=None):
|
|
5824
|
+
"""Create a fresh plugin instance per invocation.
|
|
5825
|
+
|
|
5826
|
+
Args:
|
|
5827
|
+
user_id: From invocation context (required for SigV4, derived from JWT for bearer)
|
|
5828
|
+
instrument_id: From invocation payload (created by app backend per user)
|
|
5829
|
+
session_id: From invocation payload (created by app backend per conversation)
|
|
5830
|
+
|
|
5831
|
+
Returns:
|
|
5832
|
+
AgentCorePaymentsPlugin instance, or None if no manager is configured.
|
|
5833
|
+
"""
|
|
5834
|
+
if not _manager_arn:
|
|
5835
|
+
return None
|
|
5836
|
+
|
|
5837
|
+
config_kwargs = {
|
|
5838
|
+
"payment_manager_arn": _manager_arn,
|
|
5839
|
+
"region": _region,
|
|
5840
|
+
"payment_instrument_id": instrument_id,
|
|
5841
|
+
"payment_session_id": session_id,
|
|
5842
|
+
"payment_connector_id": _connector_id,
|
|
5843
|
+
}
|
|
5844
|
+
|
|
5845
|
+
config_kwargs["auto_payment"] = _auto_payment
|
|
5846
|
+
if _allowlist:
|
|
5847
|
+
config_kwargs["payment_tool_allowlist"] = _allowlist
|
|
5848
|
+
if _network_prefs:
|
|
5849
|
+
config_kwargs["network_preferences_config"] = _network_prefs
|
|
5850
|
+
|
|
5851
|
+
if _process_payment_role_arn:
|
|
5852
|
+
# Only pass boto3_session if SDK supports it (added in bedrock-agentcore >= 1.11).
|
|
5853
|
+
# Older SDKs use the runtime role's default credentials and can still call ProcessPayment
|
|
5854
|
+
# if the runtime role has been granted permission directly.
|
|
5855
|
+
import inspect
|
|
5856
|
+
if "boto3_session" in inspect.signature(AgentCorePaymentsPluginConfig).parameters:
|
|
5857
|
+
config_kwargs["boto3_session"] = _assume_role_session(_process_payment_role_arn)
|
|
5858
|
+
else:
|
|
5859
|
+
logger.warning(
|
|
5860
|
+
"PROCESS_PAYMENT_ROLE_ARN set but bedrock-agentcore SDK does not support boto3_session. "
|
|
5861
|
+
"Upgrade to bedrock-agentcore>=1.11 to enable cross-role payment processing."
|
|
5862
|
+
)
|
|
5863
|
+
|
|
5864
|
+
if _auth_mode == "bearer":
|
|
5865
|
+
bearer_token = os.getenv("AGENTCORE_BEARER_TOKEN")
|
|
5866
|
+
if bearer_token:
|
|
5867
|
+
config_kwargs["bearer_token"] = bearer_token
|
|
5868
|
+
else:
|
|
5869
|
+
logger.warning(
|
|
5870
|
+
"Bearer auth mode configured but AGENTCORE_BEARER_TOKEN not set. "
|
|
5871
|
+
"Falling back to SigV4. Set AGENTCORE_BEARER_TOKEN or pass bearer_token in invoke context."
|
|
5872
|
+
)
|
|
5873
|
+
config_kwargs["user_id"] = user_id or "default-user"
|
|
5874
|
+
else:
|
|
5875
|
+
config_kwargs["user_id"] = user_id or "default-user"
|
|
5876
|
+
|
|
5877
|
+
config = AgentCorePaymentsPluginConfig(**config_kwargs)
|
|
5878
|
+
return AgentCorePaymentsPlugin(config=config)
|
|
5879
|
+
"
|
|
5880
|
+
`;
|
|
5881
|
+
|
|
5482
5882
|
exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/README.md should match snapshot 1`] = `
|
|
5483
5883
|
"# {{ name }}
|
|
5484
5884
|
|