@aws/agentcore 1.0.0-preview.12 → 1.0.0-preview.14
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/README.md +31 -17
- package/dist/agent-inspector/index.css +1 -1
- package/dist/agent-inspector/index.js +90 -85
- package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +1373 -113
- package/dist/assets/agents/AGENTS.md +14 -0
- package/dist/assets/cdk/bin/cdk.ts +90 -24
- package/dist/assets/cdk/lib/cdk-stack.ts +178 -12
- package/dist/assets/cdk/test/cdk.test.ts +3 -0
- package/dist/assets/container/python/Dockerfile +4 -0
- package/dist/assets/python/a2a/langchain_langgraph/base/pyproject.toml +1 -1
- package/dist/assets/python/a2a/strands/capabilities/memory/session.py +4 -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/agui/strands/capabilities/memory/session.py +4 -1
- package/dist/assets/python/http/autogen/base/pyproject.toml +1 -1
- package/dist/assets/python/http/googleadk/base/mcp_client/client.py +7 -7
- package/dist/assets/python/http/googleadk/base/pyproject.toml +1 -1
- package/dist/assets/python/http/langchain_langgraph/base/mcp_client/client.py +10 -8
- package/dist/assets/python/http/langchain_langgraph/base/pyproject.toml +2 -2
- package/dist/assets/python/http/openaiagents/base/main.py +19 -9
- package/dist/assets/python/http/openaiagents/base/mcp_client/client.py +4 -4
- package/dist/assets/python/http/openaiagents/base/pyproject.toml +2 -2
- package/dist/assets/python/http/strands/base/main.py +475 -27
- package/dist/assets/python/http/strands/base/mcp_client/client.py +45 -5
- package/dist/assets/python/http/strands/base/model/load.py +3 -3
- package/dist/assets/python/http/strands/base/pyproject.toml +5 -2
- package/dist/assets/python/http/strands/base/skills/fetcher.py +279 -0
- package/dist/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
- package/dist/assets/python/http/strands/capabilities/memory/session.py +4 -1
- 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 +1235 -983
- package/dist/lib/errors/types.d.ts +18 -0
- package/dist/lib/errors/types.d.ts.map +1 -1
- package/dist/lib/errors/types.js +28 -1
- package/dist/lib/errors/types.js.map +1 -1
- 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/schemas/io/config-io.d.ts.map +1 -1
- package/dist/lib/schemas/io/config-io.js +0 -2
- package/dist/lib/schemas/io/config-io.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/constants.d.ts +20 -0
- package/dist/schema/constants.d.ts.map +1 -1
- package/dist/schema/constants.js +25 -1
- package/dist/schema/constants.js.map +1 -1
- package/dist/schema/schemas/agent-env.d.ts +35 -0
- package/dist/schema/schemas/agent-env.d.ts.map +1 -1
- package/dist/schema/schemas/agentcore-project.d.ts +239 -25
- package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
- package/dist/schema/schemas/agentcore-project.js +140 -34
- package/dist/schema/schemas/agentcore-project.js.map +1 -1
- package/dist/schema/schemas/auth.d.ts +175 -0
- package/dist/schema/schemas/auth.d.ts.map +1 -1
- package/dist/schema/schemas/auth.js +126 -3
- package/dist/schema/schemas/auth.js.map +1 -1
- package/dist/schema/schemas/deployed-state.d.ts +237 -46
- package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
- package/dist/schema/schemas/deployed-state.js +62 -17
- package/dist/schema/schemas/deployed-state.js.map +1 -1
- package/dist/schema/schemas/mcp-defs.d.ts +2 -1
- package/dist/schema/schemas/mcp-defs.d.ts.map +1 -1
- package/dist/schema/schemas/mcp-defs.js +3 -2
- package/dist/schema/schemas/mcp-defs.js.map +1 -1
- package/dist/schema/schemas/mcp.d.ts +186 -0
- package/dist/schema/schemas/mcp.d.ts.map +1 -1
- package/dist/schema/schemas/mcp.js +479 -4
- package/dist/schema/schemas/mcp.js.map +1 -1
- package/dist/schema/schemas/primitives/ab-test.d.ts +0 -6
- package/dist/schema/schemas/primitives/ab-test.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/ab-test.js +0 -2
- package/dist/schema/schemas/primitives/ab-test.js.map +1 -1
- package/dist/schema/schemas/primitives/harness.d.ts +242 -11
- package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/harness.js +309 -21
- package/dist/schema/schemas/primitives/harness.js.map +1 -1
- package/dist/schema/schemas/primitives/index.d.ts +8 -8
- package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/index.js +18 -5
- package/dist/schema/schemas/primitives/index.js.map +1 -1
- package/dist/schema/schemas/primitives/knowledge-base.d.ts +104 -0
- package/dist/schema/schemas/primitives/knowledge-base.d.ts.map +1 -0
- package/dist/schema/schemas/primitives/knowledge-base.js +99 -0
- package/dist/schema/schemas/primitives/knowledge-base.js.map +1 -0
- package/dist/schema/schemas/primitives/online-eval-config.d.ts +20 -2
- package/dist/schema/schemas/primitives/online-eval-config.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/online-eval-config.js +43 -5
- package/dist/schema/schemas/primitives/online-eval-config.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/dist/schema/schemas/primitives/policy.d.ts +26 -0
- package/dist/schema/schemas/primitives/policy.d.ts.map +1 -1
- package/dist/schema/schemas/primitives/policy.js +5 -1
- package/dist/schema/schemas/primitives/policy.js.map +1 -1
- package/npm-shrinkwrap.json +941 -670
- package/package.json +11 -8
- package/scripts/bundle.mjs +51 -0
- package/scripts/run-e2e-local.sh +48 -10
- package/dist/schema/schemas/primitives/http-gateway.d.ts +0 -21
- package/dist/schema/schemas/primitives/http-gateway.d.ts.map +0 -1
- package/dist/schema/schemas/primitives/http-gateway.js +0 -34
- package/dist/schema/schemas/primitives/http-gateway.js.map +0 -1
|
@@ -122,6 +122,19 @@ When modifying JSON config files:
|
|
|
122
122
|
4. Use CloudFormation-safe names (alphanumeric, start with letter)
|
|
123
123
|
5. Run `agentcore validate` to verify changes
|
|
124
124
|
|
|
125
|
+
## Harness Export
|
|
126
|
+
|
|
127
|
+
`agentcore export harness` converts a harness configuration into a deployable Strands Python agent under `app/<agentName>/`.
|
|
128
|
+
|
|
129
|
+
**After every export, you MUST read `app/<agentName>/EXPORT_NOTES.md` before proceeding.**
|
|
130
|
+
|
|
131
|
+
This file lists any manual follow-up items required before the agent will deploy or run correctly — missing files to create, IAM policies to add, or configuration steps the exporter could not automate. A clean export produces "No manual steps required." Complete every item in the file before running `agentcore deploy`.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
agentcore export harness --name <harnessName> # generates app/<agentName>/EXPORT_NOTES.md
|
|
135
|
+
cat app/<agentName>/EXPORT_NOTES.md # read this before touching anything else
|
|
136
|
+
```
|
|
137
|
+
|
|
125
138
|
## CLI Commands
|
|
126
139
|
|
|
127
140
|
| Command | Description |
|
|
@@ -129,6 +142,7 @@ When modifying JSON config files:
|
|
|
129
142
|
| `agentcore create` | Create a new project |
|
|
130
143
|
| `agentcore add <resource>` | Add agent, memory, credential, gateway, evaluator, policy |
|
|
131
144
|
| `agentcore remove <resource>` | Remove a resource |
|
|
145
|
+
| `agentcore export harness` | Export a harness to a Strands runtime agent |
|
|
132
146
|
| `agentcore dev` | Run agent locally with hot-reload |
|
|
133
147
|
| `agentcore deploy` | Deploy to AWS |
|
|
134
148
|
| `agentcore status` | Show deployment status |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { AgentCoreStack } from '../lib/cdk-stack';
|
|
3
|
-
import { ConfigIO, type AwsDeploymentTarget } from '@aws/agentcore-cdk';
|
|
2
|
+
import { AgentCoreStack, type HarnessConfig } from '../lib/cdk-stack';
|
|
3
|
+
import { ConfigIO, HarnessSpecSchema, type AwsDeploymentTarget } from '@aws/agentcore-cdk';
|
|
4
4
|
import { App, type Environment } from 'aws-cdk-lib';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import * as fs from 'fs';
|
|
@@ -28,12 +28,14 @@ async function main() {
|
|
|
28
28
|
const spec = await configIO.readProjectSpec();
|
|
29
29
|
const targets = await configIO.readAWSDeploymentTargets();
|
|
30
30
|
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
// dynamically and cast the resulting object.
|
|
31
|
+
// The vended CDK project compiles against the published @aws/agentcore-cdk
|
|
32
|
+
// schema type, which may lag the CLI's own AgentCoreProjectSpec (e.g. payments,
|
|
33
|
+
// harnesses, gateway fields). Cast once so those fields are reachable.
|
|
35
34
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
35
|
const specAny = spec as any;
|
|
36
|
+
|
|
37
|
+
// Extract MCP configuration from project spec.
|
|
38
|
+
// Gateway fields are stored in agentcore.json but may not yet be on the
|
|
37
39
|
const mcpSpec = specAny.agentCoreGateways?.length
|
|
38
40
|
? {
|
|
39
41
|
agentCoreGateways: specAny.agentCoreGateways,
|
|
@@ -54,38 +56,61 @@ async function main() {
|
|
|
54
56
|
throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
// Read harness configs
|
|
59
|
+
// Read harness configs: the full validated spec drives the CFN resource; the
|
|
60
|
+
// role-scoped fields drive the IAM role + container build.
|
|
58
61
|
const projectRoot = path.resolve(configRoot, '..');
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
|
|
63
|
+
// Read non-S3 KB connector-config files and pass their parsed contents to the
|
|
64
|
+
// L3 verbatim. The L3 does not read files; it expects the parsed
|
|
65
|
+
// connectorParameters keyed by the data source's connectorConfigFile path.
|
|
66
|
+
const connectorParametersByFile: Record<string, Record<string, unknown>> = {};
|
|
67
|
+
for (const kb of specAny.knowledgeBases ?? []) {
|
|
68
|
+
for (const ds of kb.dataSources ?? []) {
|
|
69
|
+
if (ds.type !== 'S3' && ds.connectorConfigFile) {
|
|
70
|
+
const abs = path.resolve(projectRoot, ds.connectorConfigFile);
|
|
71
|
+
try {
|
|
72
|
+
connectorParametersByFile[ds.connectorConfigFile] = JSON.parse(fs.readFileSync(abs, 'utf-8'));
|
|
73
|
+
} catch (err) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Could not read connector config '${ds.connectorConfigFile}' for knowledge base '${kb.name}' at ${abs}: ${err instanceof Error ? err.message : err}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Harness is preview-gated. The CLI bundle bakes the preview flag at build time and
|
|
83
|
+
// forwards it to this child process via AGENTCORE_PREVIEW (see toolkit-lib/wrapper.ts).
|
|
84
|
+
// This app is built separately and cannot see that build-time define, so it gates on the
|
|
85
|
+
// env var. Absent/anything-but-'1' defaults to off so a stale harnesses[] entry in a
|
|
86
|
+
// non-preview build never synthesizes an AWS::BedrockAgentCore::Harness resource.
|
|
87
|
+
const previewEnabled = process.env.AGENTCORE_PREVIEW === '1';
|
|
88
|
+
|
|
89
|
+
const harnessConfigs: HarnessConfig[] = [];
|
|
90
|
+
for (const entry of previewEnabled ? (specAny.harnesses ?? []) : []) {
|
|
73
91
|
const harnessDir = path.resolve(projectRoot, entry.path);
|
|
74
92
|
const harnessPath = path.resolve(harnessDir, 'harness.json');
|
|
75
93
|
try {
|
|
76
|
-
const harnessSpec = JSON.parse(fs.readFileSync(harnessPath, 'utf-8'));
|
|
94
|
+
const harnessSpec = HarnessSpecSchema.parse(JSON.parse(fs.readFileSync(harnessPath, 'utf-8')));
|
|
77
95
|
harnessConfigs.push({
|
|
78
96
|
name: entry.name,
|
|
79
97
|
executionRoleArn: harnessSpec.executionRoleArn,
|
|
80
|
-
|
|
98
|
+
// Only an `existing` memory ref carries a name to wire IAM against; managed memory is
|
|
99
|
+
// owned by the harness (no sibling) and disabled has none — both resolve to undefined.
|
|
100
|
+
memoryName: harnessSpec.memory?.mode === 'existing' ? harnessSpec.memory.name : undefined,
|
|
81
101
|
containerUri: harnessSpec.containerUri,
|
|
82
102
|
hasDockerfile: !!harnessSpec.dockerfile,
|
|
83
103
|
dockerfile: harnessSpec.dockerfile,
|
|
84
104
|
codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
|
|
85
105
|
tools: harnessSpec.tools,
|
|
106
|
+
skills: harnessSpec.skills,
|
|
86
107
|
apiKeyArn: harnessSpec.model?.apiKeyArn,
|
|
87
108
|
efsAccessPoints: harnessSpec.efsAccessPoints,
|
|
88
109
|
s3AccessPoints: harnessSpec.s3AccessPoints,
|
|
110
|
+
apiFormat: harnessSpec.model?.apiFormat,
|
|
111
|
+
// Full spec + dir drive the AWS::BedrockAgentCore::Harness CFN resource.
|
|
112
|
+
spec: harnessSpec,
|
|
113
|
+
harnessDir,
|
|
89
114
|
});
|
|
90
115
|
} catch (err) {
|
|
91
116
|
throw new Error(
|
|
@@ -109,11 +134,52 @@ async function main() {
|
|
|
109
134
|
| Record<string, { credentialProviderArn: string; clientSecretArn?: string }>
|
|
110
135
|
| undefined;
|
|
111
136
|
|
|
137
|
+
// Payment credential provider ARNs live in the same credentials map as identity credentials
|
|
138
|
+
const paymentCredentials = credentials;
|
|
139
|
+
|
|
140
|
+
const paymentSpec = specAny.payments?.length
|
|
141
|
+
? specAny.payments.map(
|
|
142
|
+
(p: {
|
|
143
|
+
name: string;
|
|
144
|
+
description?: string;
|
|
145
|
+
authorizerType: 'AWS_IAM' | 'CUSTOM_JWT';
|
|
146
|
+
authorizerConfiguration?: unknown;
|
|
147
|
+
autoPayment?: boolean;
|
|
148
|
+
paymentToolAllowlist?: string[];
|
|
149
|
+
networkPreferences?: string[];
|
|
150
|
+
connectors: { name: string; provider?: string; credentialName: string }[];
|
|
151
|
+
}) => ({
|
|
152
|
+
name: p.name,
|
|
153
|
+
description: p.description,
|
|
154
|
+
authorizerType: p.authorizerType,
|
|
155
|
+
authorizerConfiguration: p.authorizerConfiguration,
|
|
156
|
+
autoPayment: p.autoPayment,
|
|
157
|
+
paymentToolAllowlist: p.paymentToolAllowlist,
|
|
158
|
+
networkPreferences: p.networkPreferences,
|
|
159
|
+
connectors: p.connectors.map(c => {
|
|
160
|
+
const credentialProviderArn = paymentCredentials?.[c.credentialName]?.credentialProviderArn;
|
|
161
|
+
if (!credentialProviderArn) {
|
|
162
|
+
// Fail fast with an actionable message rather than passing an empty
|
|
163
|
+
// ARN that fails opaquely server-side at CreatePaymentConnector.
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Payment connector "${c.name}" on manager "${p.name}" references credential ` +
|
|
166
|
+
`"${c.credentialName}", but no deployed credential provider was found for it. ` +
|
|
167
|
+
`Run \`agentcore deploy\` so the credential provider is created first.`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
return { name: c.name, provider: c.provider, credentialProviderArn };
|
|
171
|
+
}),
|
|
172
|
+
})
|
|
173
|
+
)
|
|
174
|
+
: undefined;
|
|
175
|
+
|
|
112
176
|
new AgentCoreStack(app, stackName, {
|
|
113
177
|
spec,
|
|
114
178
|
mcpSpec,
|
|
115
179
|
credentials,
|
|
180
|
+
connectorParametersByFile,
|
|
116
181
|
harnesses: harnessConfigs.length > 0 ? harnessConfigs : undefined,
|
|
182
|
+
paymentSpec,
|
|
117
183
|
env,
|
|
118
184
|
description: `AgentCore stack for ${spec.name} deployed to ${target.name} (${target.region})`,
|
|
119
185
|
tags: {
|
|
@@ -128,5 +194,5 @@ async function main() {
|
|
|
128
194
|
|
|
129
195
|
main().catch((error: unknown) => {
|
|
130
196
|
console.error('AgentCore CDK synthesis failed:', error instanceof Error ? error.message : error);
|
|
131
|
-
process.
|
|
197
|
+
process.exit(1);
|
|
132
198
|
});
|
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentCoreApplication,
|
|
3
3
|
AgentCoreMcp,
|
|
4
|
+
AgentCorePaymentManager,
|
|
5
|
+
AgentCorePaymentConnector,
|
|
4
6
|
type AgentCoreProjectSpec,
|
|
5
7
|
type AgentCoreMcpSpec,
|
|
8
|
+
type CustomJWTAuthorizerConfig,
|
|
9
|
+
type HarnessDeploymentConfig,
|
|
6
10
|
} from '@aws/agentcore-cdk';
|
|
7
11
|
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
|
|
12
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
8
13
|
import { Construct } from 'constructs';
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Harness deployment config: role-scoped fields (for IAM role + container build)
|
|
17
|
+
* plus the full validated spec + its config directory so the L3 construct can
|
|
18
|
+
* synthesize the AWS::BedrockAgentCore::Harness resource.
|
|
19
|
+
*/
|
|
20
|
+
export type HarnessConfig = HarnessDeploymentConfig;
|
|
21
|
+
|
|
22
|
+
export interface PaymentConnectorSpec {
|
|
23
|
+
name: string;
|
|
24
|
+
provider: 'CoinbaseCDP' | 'StripePrivy';
|
|
25
|
+
credentialProviderArn: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface PaymentSpec {
|
|
11
29
|
name: string;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
apiKeyArn?: string;
|
|
20
|
-
efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
21
|
-
s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
|
|
30
|
+
description?: string;
|
|
31
|
+
authorizerType: 'AWS_IAM' | 'CUSTOM_JWT';
|
|
32
|
+
authorizerConfiguration?: { customJWTAuthorizer: CustomJWTAuthorizerConfig };
|
|
33
|
+
autoPayment?: boolean;
|
|
34
|
+
paymentToolAllowlist?: string[];
|
|
35
|
+
networkPreferences?: string[];
|
|
36
|
+
connectors: PaymentConnectorSpec[];
|
|
22
37
|
}
|
|
23
38
|
|
|
24
39
|
export interface AgentCoreStackProps extends StackProps {
|
|
@@ -38,6 +53,35 @@ export interface AgentCoreStackProps extends StackProps {
|
|
|
38
53
|
* Harness role configurations.
|
|
39
54
|
*/
|
|
40
55
|
harnesses?: HarnessConfig[];
|
|
56
|
+
/**
|
|
57
|
+
* Parsed connectorParameters for non-S3 KB data sources, keyed by
|
|
58
|
+
* connectorConfigFile path. Forwarded to AgentCoreApplication.
|
|
59
|
+
*/
|
|
60
|
+
connectorParametersByFile?: Record<string, Record<string, unknown>>;
|
|
61
|
+
/**
|
|
62
|
+
* Payment specifications with resolved credential provider ARNs.
|
|
63
|
+
*/
|
|
64
|
+
paymentSpec?: PaymentSpec[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function toCdkId(name: string): string {
|
|
68
|
+
return name.replace(/_/g, '');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Decide whether a deployed runtime should receive payment env vars + IAM grants.
|
|
73
|
+
* Payments today only ships a runtime shim for Python HTTP runtimes; injecting
|
|
74
|
+
* AGENTCORE_PAYMENT_* env vars into TypeScript / MCP / A2A / AGUI runtimes
|
|
75
|
+
* would surface env vars they cannot consume and would dilute least-privilege
|
|
76
|
+
* IAM grants for runtimes that never call ProcessPayment.
|
|
77
|
+
*/
|
|
78
|
+
function isPaymentEligibleAgent(agent: { entrypoint?: string; protocol?: string }): boolean {
|
|
79
|
+
if (agent.protocol && agent.protocol !== 'HTTP') {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const entrypoint = typeof agent.entrypoint === 'string' ? agent.entrypoint : '';
|
|
83
|
+
const entrypointFile = entrypoint.split(':')[0] ?? '';
|
|
84
|
+
return entrypointFile.endsWith('.py');
|
|
41
85
|
}
|
|
42
86
|
|
|
43
87
|
/**
|
|
@@ -53,7 +97,7 @@ export class AgentCoreStack extends Stack {
|
|
|
53
97
|
constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
|
|
54
98
|
super(scope, id, props);
|
|
55
99
|
|
|
56
|
-
const { spec, mcpSpec, credentials, harnesses } = props;
|
|
100
|
+
const { spec, mcpSpec, credentials, harnesses, connectorParametersByFile, paymentSpec } = props;
|
|
57
101
|
|
|
58
102
|
// Create AgentCoreApplication with all agents and harness roles
|
|
59
103
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -61,6 +105,12 @@ export class AgentCoreStack extends Stack {
|
|
|
61
105
|
if (harnesses?.length) {
|
|
62
106
|
appProps.harnesses = harnesses;
|
|
63
107
|
}
|
|
108
|
+
if (connectorParametersByFile && Object.keys(connectorParametersByFile).length > 0) {
|
|
109
|
+
appProps.connectorParametersByFile = connectorParametersByFile;
|
|
110
|
+
}
|
|
111
|
+
if (credentials) {
|
|
112
|
+
appProps.credentials = credentials;
|
|
113
|
+
}
|
|
64
114
|
this.application = new AgentCoreApplication(this, 'Application', appProps as any);
|
|
65
115
|
|
|
66
116
|
// Create AgentCoreMcp if there are gateways configured
|
|
@@ -74,6 +124,122 @@ export class AgentCoreStack extends Stack {
|
|
|
74
124
|
});
|
|
75
125
|
}
|
|
76
126
|
|
|
127
|
+
// Create payment infrastructure via CFN constructs
|
|
128
|
+
if (paymentSpec && paymentSpec.length > 0) {
|
|
129
|
+
for (const payment of paymentSpec) {
|
|
130
|
+
const mgrId = toCdkId(payment.name);
|
|
131
|
+
const manager = new AgentCorePaymentManager(this, `Payment${mgrId}`, {
|
|
132
|
+
projectName: spec.name,
|
|
133
|
+
name: payment.name,
|
|
134
|
+
authorizerType: payment.authorizerType,
|
|
135
|
+
description: payment.description,
|
|
136
|
+
authorizerConfiguration: payment.authorizerConfiguration,
|
|
137
|
+
tags: spec.tags,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const prefix = `AGENTCORE_PAYMENT_${payment.name.toUpperCase().replace(/-/g, '_')}`;
|
|
141
|
+
|
|
142
|
+
// Wire env vars from construct output tokens into eligible agent environments only.
|
|
143
|
+
// See isPaymentEligibleAgent — non-Python or non-HTTP runtimes have no shim that
|
|
144
|
+
// can consume these env vars, and giving them sts:AssumeRole on the
|
|
145
|
+
// ProcessPaymentRole would broaden the privilege surface unnecessarily.
|
|
146
|
+
for (const env of this.application.environments.values()) {
|
|
147
|
+
if (!isPaymentEligibleAgent(env.agent)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
env.runtime.addEnvironmentVariable(`${prefix}_MANAGER_ARN`, manager.paymentManagerArn);
|
|
151
|
+
env.runtime.addEnvironmentVariable(`${prefix}_PROCESS_PAYMENT_ROLE_ARN`, manager.processPaymentRoleArn);
|
|
152
|
+
|
|
153
|
+
// Grant runtime execution role permission to assume the ProcessPaymentRole.
|
|
154
|
+
// The ProcessPaymentRole's trust policy allows AccountRootPrincipal, but the
|
|
155
|
+
// caller still needs sts:AssumeRole on its own role to perform the assumption.
|
|
156
|
+
env.runtime.role.addToPrincipalPolicy(
|
|
157
|
+
new iam.PolicyStatement({
|
|
158
|
+
actions: ['sts:AssumeRole'],
|
|
159
|
+
resources: [manager.processPaymentRoleArn],
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Grant payment data-plane actions directly to the runtime role.
|
|
164
|
+
//
|
|
165
|
+
// NOTE: This deviates from the canonical role model in the AgentCore Payments
|
|
166
|
+
// beta guide, which assigns Get/List/Create instrument+session actions to a
|
|
167
|
+
// separate ManagementRole and limits the agent's role to ProcessPayment only.
|
|
168
|
+
// The current SDK plugin (AgentCorePaymentsPlugin.generate_payment_header)
|
|
169
|
+
// calls GetPaymentInstrument internally during the 402 auto-pay path, so the
|
|
170
|
+
// runtime role needs read access. CreatePaymentSession is included so
|
|
171
|
+
// `agentcore invoke --auto-session` works without a separate ManagementRole
|
|
172
|
+
// call. Tighten this if the SDK is updated to accept pre-fetched instrument
|
|
173
|
+
// details and split create-session into a backend-only flow.
|
|
174
|
+
env.runtime.role.addToPrincipalPolicy(
|
|
175
|
+
new iam.PolicyStatement({
|
|
176
|
+
actions: [
|
|
177
|
+
'bedrock-agentcore:GetPaymentInstrument',
|
|
178
|
+
'bedrock-agentcore:ListPaymentInstruments',
|
|
179
|
+
'bedrock-agentcore:GetPaymentInstrumentBalance',
|
|
180
|
+
'bedrock-agentcore:GetPaymentSession',
|
|
181
|
+
'bedrock-agentcore:ListPaymentSessions',
|
|
182
|
+
'bedrock-agentcore:CreatePaymentSession',
|
|
183
|
+
'bedrock-agentcore:ProcessPayment',
|
|
184
|
+
],
|
|
185
|
+
resources: [manager.paymentManagerArn, `${manager.paymentManagerArn}/*`],
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (payment.autoPayment !== undefined) {
|
|
190
|
+
env.runtime.addEnvironmentVariable(`${prefix}_AUTO_PAYMENT`, String(payment.autoPayment));
|
|
191
|
+
}
|
|
192
|
+
if (payment.paymentToolAllowlist) {
|
|
193
|
+
env.runtime.addEnvironmentVariable(`${prefix}_TOOL_ALLOWLIST`, payment.paymentToolAllowlist.join(','));
|
|
194
|
+
}
|
|
195
|
+
if (payment.networkPreferences) {
|
|
196
|
+
env.runtime.addEnvironmentVariable(`${prefix}_NETWORK_PREFERENCES`, payment.networkPreferences.join(','));
|
|
197
|
+
}
|
|
198
|
+
if (payment.authorizerType === 'CUSTOM_JWT') {
|
|
199
|
+
env.runtime.addEnvironmentVariable(`${prefix}_AUTH_MODE`, 'bearer');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Create connectors for this manager
|
|
204
|
+
for (const connector of payment.connectors) {
|
|
205
|
+
const connId = toCdkId(connector.name);
|
|
206
|
+
const conn = new AgentCorePaymentConnector(this, `Payment${mgrId}${connId}`, {
|
|
207
|
+
projectName: spec.name,
|
|
208
|
+
paymentManager: manager,
|
|
209
|
+
connectorName: connector.name,
|
|
210
|
+
connectorType: connector.provider,
|
|
211
|
+
credentialProviderArn: connector.credentialProviderArn,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Wire first connector's ID as env var (eligible agents only)
|
|
215
|
+
if (connector === payment.connectors[0]) {
|
|
216
|
+
for (const env of this.application.environments.values()) {
|
|
217
|
+
if (!isPaymentEligibleAgent(env.agent)) continue;
|
|
218
|
+
env.runtime.addEnvironmentVariable(`${prefix}_CONNECTOR_ID`, conn.paymentConnectorId);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
new CfnOutput(this, `Payment${mgrId}${connId}ConnectorId`, {
|
|
223
|
+
value: conn.paymentConnectorId,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// CFN Outputs for post-deploy state parsing
|
|
228
|
+
new CfnOutput(this, `Payment${mgrId}ManagerArn`, {
|
|
229
|
+
value: manager.paymentManagerArn,
|
|
230
|
+
});
|
|
231
|
+
new CfnOutput(this, `Payment${mgrId}ManagerId`, {
|
|
232
|
+
value: manager.paymentManagerId,
|
|
233
|
+
});
|
|
234
|
+
new CfnOutput(this, `Payment${mgrId}ProcessPaymentRoleArn`, {
|
|
235
|
+
value: manager.processPaymentRoleArn,
|
|
236
|
+
});
|
|
237
|
+
new CfnOutput(this, `Payment${mgrId}ResourceRetrievalRoleArn`, {
|
|
238
|
+
value: manager.resourceRetrievalRoleArn,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
77
243
|
// Stack-level output
|
|
78
244
|
new CfnOutput(this, 'StackNameOutput', {
|
|
79
245
|
description: 'Name of the CloudFormation Stack',
|
|
@@ -14,11 +14,14 @@ test('AgentCoreStack synthesizes with empty spec', () => {
|
|
|
14
14
|
credentials: [],
|
|
15
15
|
evaluators: [],
|
|
16
16
|
onlineEvalConfigs: [],
|
|
17
|
+
configBundles: [],
|
|
17
18
|
policyEngines: [],
|
|
19
|
+
payments: [],
|
|
18
20
|
agentCoreGateways: [],
|
|
19
21
|
mcpRuntimeTools: [],
|
|
20
22
|
unassignedTargets: [],
|
|
21
23
|
datasets: [],
|
|
24
|
+
knowledgeBases: [],
|
|
22
25
|
},
|
|
23
26
|
});
|
|
24
27
|
const template = Template.fromStack(stack);
|
|
@@ -17,7 +17,7 @@ dependencies = [
|
|
|
17
17
|
{{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
|
|
18
18
|
{{/if}}"aws-opentelemetry-distro",
|
|
19
19
|
"opentelemetry-instrumentation-langchain >= 0.59.0",
|
|
20
|
-
"bedrock-agentcore[a2a] >= 1.0
|
|
20
|
+
"bedrock-agentcore[a2a] >= 1.8.0",
|
|
21
21
|
"botocore[crt] >= 1.35.0",
|
|
22
22
|
"langgraph >= 0.2.0",
|
|
23
23
|
]
|
|
@@ -24,8 +24,11 @@ def get_memory_session_manager(session_id: Optional[str], actor_id: str) -> Opti
|
|
|
24
24
|
{{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}}
|
|
25
25
|
f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5),
|
|
26
26
|
{{/if}}
|
|
27
|
+
{{#if (includes memoryProviders.[0].strategies "EPISODIC")}}
|
|
28
|
+
f"/episodes/{actor_id}/{session_id}": RetrievalConfig(top_k=5, relevance_score=0.5),
|
|
29
|
+
{{/if}}
|
|
27
30
|
{{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}}
|
|
28
|
-
f"/summaries/{actor_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
|
|
31
|
+
f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
|
|
29
32
|
{{/if}}
|
|
30
33
|
}
|
|
31
34
|
{{/if}}
|
|
@@ -11,7 +11,7 @@ requires-python = ">=3.10"
|
|
|
11
11
|
dependencies = [
|
|
12
12
|
"ag-ui-adk >= 0.6.0",
|
|
13
13
|
"ag-ui-protocol >= 0.1.10",
|
|
14
|
-
"bedrock-agentcore >= 1.0
|
|
14
|
+
"bedrock-agentcore >= 1.8.0",
|
|
15
15
|
"fastapi >= 0.115.12",
|
|
16
16
|
"google-adk >= 1.16.0, < 2.0.0",
|
|
17
17
|
"google-genai >= 1.0.0, < 2.0.0",
|
|
@@ -18,7 +18,7 @@ dependencies = [
|
|
|
18
18
|
{{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
|
|
19
19
|
{{/if}}"aws-opentelemetry-distro",
|
|
20
20
|
"opentelemetry-instrumentation-langchain >= 0.59.0",
|
|
21
|
-
"bedrock-agentcore >= 1.0
|
|
21
|
+
"bedrock-agentcore >= 1.8.0",
|
|
22
22
|
"botocore[crt] >= 1.35.0",
|
|
23
23
|
"langgraph >= 0.3.25",
|
|
24
24
|
"langchain >= 0.3.0",
|
|
@@ -24,8 +24,11 @@ def get_memory_session_manager(session_id: Optional[str], actor_id: str) -> Opti
|
|
|
24
24
|
{{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}}
|
|
25
25
|
f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5),
|
|
26
26
|
{{/if}}
|
|
27
|
+
{{#if (includes memoryProviders.[0].strategies "EPISODIC")}}
|
|
28
|
+
f"/episodes/{actor_id}/{session_id}": RetrievalConfig(top_k=5, relevance_score=0.5),
|
|
29
|
+
{{/if}}
|
|
27
30
|
{{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}}
|
|
28
|
-
f"/summaries/{actor_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
|
|
31
|
+
f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
|
|
29
32
|
{{/if}}
|
|
30
33
|
}
|
|
31
34
|
{{/if}}
|
|
@@ -13,7 +13,7 @@ dependencies = [
|
|
|
13
13
|
"autogen-ext[mcp] >= 0.7.5",
|
|
14
14
|
"opentelemetry-distro",
|
|
15
15
|
"opentelemetry-exporter-otlp",
|
|
16
|
-
"bedrock-agentcore >= 1.0
|
|
16
|
+
"bedrock-agentcore >= 1.8.0",
|
|
17
17
|
"botocore[crt] >= 1.35.0",
|
|
18
18
|
"tiktoken",
|
|
19
19
|
{{#if (eq modelProvider "Bedrock")}}
|
|
@@ -34,20 +34,20 @@ def get_all_gateway_mcp_toolsets() -> list[MCPToolset]:
|
|
|
34
34
|
{{#each gatewayProviders}}
|
|
35
35
|
url = os.environ.get("{{envVarName}}")
|
|
36
36
|
if url:
|
|
37
|
-
|
|
37
|
+
{{#if (eq authType "AWS_IAM")}}
|
|
38
38
|
session = create_aws_session()
|
|
39
39
|
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
|
|
40
|
-
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(
|
|
40
|
+
toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(
|
|
41
41
|
url=url,
|
|
42
42
|
httpx_client_factory=lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)
|
|
43
43
|
)))
|
|
44
|
-
|
|
44
|
+
{{else if (eq authType "CUSTOM_JWT")}}
|
|
45
45
|
token = _get_bearer_token_{{snakeCase name}}()
|
|
46
46
|
headers = {"Authorization": f"Bearer {token}"} if token else None
|
|
47
|
-
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url, headers=headers)))
|
|
48
|
-
|
|
49
|
-
toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url)))
|
|
50
|
-
|
|
47
|
+
toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(url=url, headers=headers)))
|
|
48
|
+
{{else}}
|
|
49
|
+
toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(url=url)))
|
|
50
|
+
{{/if}}
|
|
51
51
|
else:
|
|
52
52
|
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
|
|
53
53
|
{{/each}}
|
|
@@ -11,7 +11,7 @@ requires-python = ">=3.10"
|
|
|
11
11
|
dependencies = [
|
|
12
12
|
"opentelemetry-distro",
|
|
13
13
|
"opentelemetry-exporter-otlp",
|
|
14
|
-
"google-adk >= 1.
|
|
14
|
+
"google-adk >= 1.35.0, < 2.0.0",
|
|
15
15
|
"google-genai >= 1.0.0, < 2.0.0",
|
|
16
16
|
"bedrock-agentcore >= 1.0.3",
|
|
17
17
|
"botocore[crt] >= 1.35.0",
|
|
@@ -32,23 +32,25 @@ def get_all_gateway_mcp_client() -> MultiServerMCPClient | None:
|
|
|
32
32
|
{{#each gatewayProviders}}
|
|
33
33
|
url = os.environ.get("{{envVarName}}")
|
|
34
34
|
if url:
|
|
35
|
-
|
|
35
|
+
{{#if (eq authType "AWS_IAM")}}
|
|
36
36
|
session = create_aws_session()
|
|
37
37
|
auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
|
|
38
|
-
servers["{{name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
|
|
39
|
-
|
|
38
|
+
servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
|
|
39
|
+
{{else if (eq authType "CUSTOM_JWT")}}
|
|
40
40
|
token = _get_bearer_token_{{snakeCase name}}()
|
|
41
41
|
headers = {"Authorization": f"Bearer {token}"} if token else None
|
|
42
|
-
servers["{{name}}"] = {"transport": "streamable_http", "url": url, "headers": headers}
|
|
43
|
-
|
|
44
|
-
servers["{{name}}"] = {"transport": "streamable_http", "url": url}
|
|
45
|
-
|
|
42
|
+
servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url, "headers": headers}
|
|
43
|
+
{{else}}
|
|
44
|
+
servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url}
|
|
45
|
+
{{/if}}
|
|
46
46
|
else:
|
|
47
47
|
logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
|
|
48
48
|
{{/each}}
|
|
49
49
|
if not servers:
|
|
50
50
|
return None
|
|
51
|
-
|
|
51
|
+
# tool_name_prefix namespaces each gateway's tools by server key so multiple
|
|
52
|
+
# gateways exposing the same tool (e.g. x_amz_bedrock_agentcore_search) don't collide.
|
|
53
|
+
return MultiServerMCPClient(servers, tool_name_prefix=True)
|
|
52
54
|
{{else}}
|
|
53
55
|
{{#if isVpc}}
|
|
54
56
|
# VPC mode: external MCP endpoints are not reachable without a NAT gateway.
|
|
@@ -13,9 +13,9 @@ dependencies = [
|
|
|
13
13
|
"opentelemetry-instrumentation-langchain >= 0.59.0",
|
|
14
14
|
"langgraph >= 1.0.2",
|
|
15
15
|
"mcp >= 1.19.0",
|
|
16
|
-
"langchain-mcp-adapters >= 0.
|
|
16
|
+
"langchain-mcp-adapters >= 0.2.0",
|
|
17
17
|
"langchain >= 1.0.3",
|
|
18
|
-
"bedrock-agentcore >= 1.0
|
|
18
|
+
"bedrock-agentcore >= 1.8.0",
|
|
19
19
|
"botocore[crt] >= 1.35.0",
|
|
20
20
|
{{#if (eq modelProvider "Bedrock")}}
|
|
21
21
|
"langchain-aws >= 1.0.0",
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{{#if needsOs}}
|
|
2
2
|
import os
|
|
3
3
|
{{/if}}
|
|
4
|
+
{{#if hasGateway}}
|
|
5
|
+
from contextlib import AsyncExitStack
|
|
6
|
+
{{/if}}
|
|
4
7
|
from agents import Agent, Runner, function_tool
|
|
5
8
|
from bedrock_agentcore.runtime import BedrockAgentCoreApp
|
|
6
9
|
from model.load import load_model
|
|
@@ -111,15 +114,22 @@ async def main(query):
|
|
|
111
114
|
try:
|
|
112
115
|
{{#if hasGateway}}
|
|
113
116
|
if mcp_servers:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
mcp_servers
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
# Connect every gateway server before the run; include_server_in_tool_names
|
|
118
|
+
# namespaces each server's tools so multiple gateways exposing the same tool
|
|
119
|
+
# (e.g. x_amz_bedrock_agentcore_search) don't collide.
|
|
120
|
+
async with AsyncExitStack() as stack:
|
|
121
|
+
for server in mcp_servers:
|
|
122
|
+
await stack.enter_async_context(server)
|
|
123
|
+
agent = Agent(
|
|
124
|
+
name="{{ name }}",
|
|
125
|
+
model="gpt-4.1",
|
|
126
|
+
instructions=INSTRUCTIONS,
|
|
127
|
+
mcp_servers=mcp_servers,
|
|
128
|
+
tools=tools,
|
|
129
|
+
mcp_config={"include_server_in_tool_names": True},
|
|
130
|
+
)
|
|
131
|
+
result = await Runner.run(agent, query)
|
|
132
|
+
return result
|
|
123
133
|
else:
|
|
124
134
|
agent = Agent(
|
|
125
135
|
name="{{ name }}",
|