@aws/nx-plugin 1.0.0-rc.58 → 1.0.0-rc.59
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/generators.json +17 -1
- package/migrations.json +12 -7
- package/package.json +1 -1
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +273 -0
- package/src/agentcore-gateway/agent-connection/generator.d.ts +19 -0
- package/src/agentcore-gateway/agent-connection/generator.js +90 -0
- package/src/agentcore-gateway/agent-connection/generator.js.map +1 -0
- package/src/agentcore-gateway/agent-connection/schema.d.js +6 -0
- package/src/agentcore-gateway/agent-connection/schema.d.js.map +1 -0
- package/src/agentcore-gateway/agent-connection/schema.d.ts +13 -0
- package/src/agentcore-gateway/agent-connection/schema.json +31 -0
- package/src/agentcore-gateway/attach-upstream.d.ts +16 -0
- package/src/agentcore-gateway/attach-upstream.js +32 -11
- package/src/agentcore-gateway/attach-upstream.js.map +1 -1
- package/src/agentcore-gateway/files/project/http/local-dev.ts.template +77 -0
- package/src/agentcore-gateway/generator.d.ts +1 -0
- package/src/agentcore-gateway/generator.js +22 -10
- package/src/agentcore-gateway/generator.js.map +1 -1
- package/src/agentcore-gateway/react-connection/__snapshots__/generator.spec.ts.snap +68 -0
- package/src/agentcore-gateway/react-connection/generator.d.ts +19 -0
- package/src/agentcore-gateway/react-connection/generator.js +119 -0
- package/src/agentcore-gateway/react-connection/generator.js.map +1 -0
- package/src/agentcore-gateway/react-connection/schema.d.js +6 -0
- package/src/agentcore-gateway/react-connection/schema.d.js.map +1 -0
- package/src/agentcore-gateway/react-connection/schema.d.ts +13 -0
- package/src/agentcore-gateway/react-connection/schema.json +31 -0
- package/src/agentcore-gateway/schema.d.js.map +1 -1
- package/src/agentcore-gateway/schema.d.ts +1 -1
- package/src/agentcore-gateway/schema.json +2 -2
- package/src/connection/agent-local-dev.d.ts +16 -0
- package/src/connection/agent-local-dev.js +44 -2
- package/src/connection/agent-local-dev.js.map +1 -1
- package/src/connection/gateway-runtime-config.d.ts +19 -0
- package/src/connection/gateway-runtime-config.js +47 -0
- package/src/connection/gateway-runtime-config.js.map +1 -0
- package/src/connection/generator.js +5 -0
- package/src/connection/generator.js.map +1 -1
- package/src/connection/scaffold-catalog.d.ts +107 -0
- package/src/connection/scaffold-catalog.js +140 -0
- package/src/connection/scaffold-catalog.js.map +1 -1
- package/src/connection/supported-connections.d.ts +9 -0
- package/src/connection/supported-connections.js +12 -0
- package/src/connection/supported-connections.js.map +1 -1
- package/src/internal/test-matrix/generator.js +39 -1
- package/src/internal/test-matrix/generator.js.map +1 -1
- package/src/migrations/latest/gateway-agent-targets/__snapshots__/migration.spec.ts.snap +223 -0
- package/src/migrations/latest/gateway-agent-targets/metadata.json +3 -0
- package/src/migrations/latest/gateway-agent-targets/migration.d.ts +6 -0
- package/src/migrations/latest/gateway-agent-targets/migration.js +217 -0
- package/src/migrations/latest/gateway-agent-targets/migration.js.map +1 -0
- package/src/migrations/latest/smithy-ssdk-bundle-pins/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.50/modernize-function-props-cast/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.50/restrict-cors-to-custom-domains/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.50/terraform-bootstrap-adopt-existing-bucket/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.52/user-identity-waf-allow-localhost-callback/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.54/order-access-log-delivery-after-bucket-policy/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.55/backfill-generator-metadata/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.56/dynamodb-local-remove-optimize-flag/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.57/ts-agent-session-management-support/metadata.json +3 -0
- package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +2 -0
- package/src/py/agent/react-connection/generator.d.ts +4 -1
- package/src/py/agent/react-connection/generator.js +35 -14
- package/src/py/agent/react-connection/generator.js.map +1 -1
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/agent/react-connection/generator.d.ts +16 -1
- package/src/ts/agent/react-connection/generator.js +21 -8
- package/src/ts/agent/react-connection/generator.js.map +1 -1
- package/src/ts/nx-migration/generator.js +40 -27
- package/src/ts/nx-migration/generator.js.map +1 -1
- package/src/ts/react-website/agui/files/common/src/hooks/useAgui__agentNameClassName__.tsx.template +16 -0
- package/src/ts/react-website/agui/generator.d.ts +11 -0
- package/src/ts/react-website/agui/generator.js +11 -7
- package/src/ts/react-website/agui/generator.js.map +1 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +5 -0
- package/src/utils/agent-core-constructs/agent-core-constructs.js +2 -0
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +3 -0
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +6 -4
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +119 -3
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +17 -0
- package/src/utils/config/utils.d.ts +5 -0
- package/src/utils/config/utils.js +7 -1
- package/src/utils/config/utils.js.map +1 -1
- package/src/utils/connection/open-api/files/components/__apiNameClassName__Provider.tsx.template +13 -2
- package/src/utils/connection/open-api/react.d.ts +10 -1
- package/src/utils/connection/open-api/react.js +3 -2
- package/src/utils/connection/open-api/react.js.map +1 -1
- package/src/utils/migration-manifest.d.ts +58 -0
- package/src/utils/migration-manifest.js +76 -0
- package/src/utils/migration-manifest.js.map +1 -0
- package/src/utils/migration-versions.d.ts +2 -0
- package/src/utils/migration-versions.js.map +1 -1
- package/src/utils/version-upgrade-migration/register.d.ts +4 -2
- package/src/utils/version-upgrade-migration/register.js +13 -13
- package/src/utils/version-upgrade-migration/register.js.map +1 -1
- /package/src/agentcore-gateway/files/project/{local-dev.ts.template → mcp/local-dev.ts.template} +0 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`gateway-agent-targets migration > should add the agentName member to vended agent constructs 1`] = `
|
|
4
|
+
"import {
|
|
5
|
+
AgentRuntimeArtifact,
|
|
6
|
+
ProtocolType,
|
|
7
|
+
Runtime,
|
|
8
|
+
} from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
9
|
+
import { Construct } from 'constructs';
|
|
10
|
+
|
|
11
|
+
export class MyAgent extends Construct {
|
|
12
|
+
public readonly dockerImage: AgentRuntimeArtifact;
|
|
13
|
+
public readonly agentCoreRuntime: Runtime;
|
|
14
|
+
/** Default Gateway target name for this agent. */
|
|
15
|
+
public readonly agentName = 'my-agent';
|
|
16
|
+
|
|
17
|
+
constructor(scope: Construct, id: string) {
|
|
18
|
+
super(scope, id);
|
|
19
|
+
this.agentCoreRuntime = undefined as any;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
"
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
exports[`gateway-agent-targets migration > should add the protocol prop and agent target methods to the vended gateway construct 1`] = `
|
|
26
|
+
"import * as cdk from 'aws-cdk-lib';
|
|
27
|
+
import * as agentcore from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
28
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
29
|
+
import * as triggers from 'aws-cdk-lib/triggers';
|
|
30
|
+
import * as wafv2 from 'aws-cdk-lib/aws-wafv2';
|
|
31
|
+
import { Construct } from 'constructs';
|
|
32
|
+
|
|
33
|
+
export interface AgentCoreGatewayProps {
|
|
34
|
+
readonly cedarPolicyPath?: string;
|
|
35
|
+
readonly cedarPolicyVariables?: Record<string, string>;
|
|
36
|
+
readonly enableWaf?: boolean;
|
|
37
|
+
readonly authorizer?: agentcore.IGatewayAuthorizerConfig;
|
|
38
|
+
/**
|
|
39
|
+
* The gateway's protocol. An \`mcp\` gateway aggregates MCP server targets
|
|
40
|
+
* into a single MCP endpoint. An \`http\` gateway has no protocol type and
|
|
41
|
+
* proxies requests to AgentCore Runtime targets via path-based routing
|
|
42
|
+
* (\`/<targetName>/invocations\`) — the target type AgentCore only allows on
|
|
43
|
+
* gateways without a protocol type.
|
|
44
|
+
*
|
|
45
|
+
* @default 'mcp'
|
|
46
|
+
*/
|
|
47
|
+
readonly protocol?: 'mcp' | 'http';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class AgentCoreGateway extends Construct implements iam.IGrantable {
|
|
51
|
+
public readonly gateway: agentcore.Gateway;
|
|
52
|
+
public readonly policyEngine?: agentcore.CfnPolicyEngine;
|
|
53
|
+
public readonly webAcl?: wafv2.CfnWebACL;
|
|
54
|
+
private readonly policies: agentcore.CfnPolicy[] = [];
|
|
55
|
+
private targetReadinessProbe?: triggers.TriggerFunction;
|
|
56
|
+
private readonly targetRuntimeArns: string[] = [];
|
|
57
|
+
private readonly protocol: 'mcp' | 'http';
|
|
58
|
+
|
|
59
|
+
constructor(scope: Construct, id: string, props?: AgentCoreGatewayProps) {
|
|
60
|
+
super(scope, id);
|
|
61
|
+
|
|
62
|
+
this.protocol = props?.protocol ?? 'mcp';
|
|
63
|
+
|
|
64
|
+
this.gateway = new agentcore.Gateway(this, 'Gateway', {
|
|
65
|
+
gatewayName: cdk.Names.uniqueResourceName(this, { maxLength: 39 }),
|
|
66
|
+
protocolConfiguration: new agentcore.McpProtocolConfiguration({
|
|
67
|
+
searchType: agentcore.McpGatewaySearchType.SEMANTIC,
|
|
68
|
+
supportedVersions: [agentcore.MCPProtocolVersion.MCP_2025_03_26],
|
|
69
|
+
}),
|
|
70
|
+
authorizerConfiguration:
|
|
71
|
+
props?.authorizer ?? agentcore.GatewayAuthorizer.usingAwsIam(),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (this.protocol === 'http') {
|
|
75
|
+
// AgentCore Runtime targets require a gateway without a protocol type,
|
|
76
|
+
// which the Gateway L2 cannot express — it always renders MCP — so
|
|
77
|
+
// remove the protocol from the underlying CloudFormation resource.
|
|
78
|
+
const cfnGateway = this.gateway.node.defaultChild as agentcore.CfnGateway;
|
|
79
|
+
cfnGateway.addPropertyDeletionOverride('ProtocolType');
|
|
80
|
+
cfnGateway.addPropertyDeletionOverride('ProtocolConfiguration');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public get grantPrincipal(): iam.IPrincipal {
|
|
85
|
+
return this.gateway.role.grantPrincipal;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public addGatewayTarget(props: {
|
|
89
|
+
gatewayTargetName: string;
|
|
90
|
+
gatewayUrl: string;
|
|
91
|
+
gatewayArn: string;
|
|
92
|
+
}): agentcore.CfnGatewayTarget {
|
|
93
|
+
const target = this.addTarget(props.gatewayTargetName, props.gatewayUrl);
|
|
94
|
+
|
|
95
|
+
const grant = this.gateway.role.addToPrincipalPolicy(
|
|
96
|
+
new iam.PolicyStatement({
|
|
97
|
+
actions: ['bedrock-agentcore:InvokeGateway'],
|
|
98
|
+
resources: [props.gatewayArn],
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
if (grant.policyDependable) {
|
|
102
|
+
target.node.addDependency(grant.policyDependable);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return target;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Add an agent runtime construct as a target of this Gateway. Requires the
|
|
110
|
+
* \`http\` protocol — the gateway proxies requests for the agent under
|
|
111
|
+
* \`<gatewayUrl>/<targetName>/invocations\`, without protocol translation.
|
|
112
|
+
*
|
|
113
|
+
* The target name defaults to the agent construct's \`agentName\` (its
|
|
114
|
+
* project's class name in kebab-case, e.g. \`MyAgent\` -> \`my-agent\`). It
|
|
115
|
+
* forms the target's invocation path, so renaming it later is a breaking
|
|
116
|
+
* change for consumers.
|
|
117
|
+
*/
|
|
118
|
+
public addAgent(
|
|
119
|
+
agent: Construct & {
|
|
120
|
+
readonly agentCoreRuntime: agentcore.Runtime;
|
|
121
|
+
readonly agentName: string;
|
|
122
|
+
},
|
|
123
|
+
props?: {
|
|
124
|
+
gatewayTargetName?: string;
|
|
125
|
+
},
|
|
126
|
+
): agentcore.CfnGatewayTarget {
|
|
127
|
+
return this.addAgentTarget({
|
|
128
|
+
gatewayTargetName: props?.gatewayTargetName ?? agent.agentName,
|
|
129
|
+
agentRuntimeArn: agent.agentCoreRuntime.agentRuntimeArn,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Register an agent runtime ARN as a Gateway target. Prefer
|
|
135
|
+
* {@link addAgent} when the construct is in scope.
|
|
136
|
+
*/
|
|
137
|
+
public addAgentTarget(props: {
|
|
138
|
+
gatewayTargetName: string;
|
|
139
|
+
agentRuntimeArn: string;
|
|
140
|
+
}): agentcore.CfnGatewayTarget {
|
|
141
|
+
if (this.protocol !== 'http') {
|
|
142
|
+
throw new Error(
|
|
143
|
+
\`Agent runtime targets require an http-protocol gateway, but this gateway uses '\${this.protocol}'.\`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// The construct id is derived from the target name so the two change
|
|
148
|
+
// together — target names are unique per gateway, and replacing a target
|
|
149
|
+
// under an unchanged name fails with AlreadyExists.
|
|
150
|
+
const target = new agentcore.CfnGatewayTarget(
|
|
151
|
+
this,
|
|
152
|
+
\`Target-\${props.gatewayTargetName}\`,
|
|
153
|
+
{
|
|
154
|
+
gatewayIdentifier: this.gateway.gatewayId,
|
|
155
|
+
name: props.gatewayTargetName,
|
|
156
|
+
targetConfiguration: {
|
|
157
|
+
http: {
|
|
158
|
+
agentcoreRuntime: {
|
|
159
|
+
arn: props.agentRuntimeArn,
|
|
160
|
+
qualifier: 'DEFAULT',
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
// The bare gateway IAM role credential: runtime targets reject the
|
|
165
|
+
// iamCredentialProvider detail MCP targets carry.
|
|
166
|
+
credentialProviderConfigurations: [
|
|
167
|
+
{
|
|
168
|
+
credentialProviderType: 'GATEWAY_IAM_ROLE',
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Grant the gateway role invoke access to the target runtime before the
|
|
175
|
+
// target is created — AgentCore validates access to the runtime during
|
|
176
|
+
// target creation.
|
|
177
|
+
const grant = this.gateway.role.addToPrincipalPolicy(
|
|
178
|
+
new iam.PolicyStatement({
|
|
179
|
+
actions: [
|
|
180
|
+
'bedrock-agentcore:InvokeAgentRuntime',
|
|
181
|
+
'bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream',
|
|
182
|
+
// A2A targets additionally serve their agent card via the gateway.
|
|
183
|
+
'bedrock-agentcore:GetAgentCard',
|
|
184
|
+
],
|
|
185
|
+
resources: [props.agentRuntimeArn, \`\${props.agentRuntimeArn}/*\`],
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
if (grant.policyDependable) {
|
|
189
|
+
target.node.addDependency(grant.policyDependable);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return target;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private addTarget(
|
|
196
|
+
gatewayTargetName: string,
|
|
197
|
+
endpoint: string,
|
|
198
|
+
): agentcore.CfnGatewayTarget {
|
|
199
|
+
const target = new agentcore.CfnGatewayTarget(
|
|
200
|
+
this,
|
|
201
|
+
\`Target-\${gatewayTargetName}\`,
|
|
202
|
+
{
|
|
203
|
+
gatewayIdentifier: this.gateway.gatewayId,
|
|
204
|
+
name: gatewayTargetName,
|
|
205
|
+
targetConfiguration: {
|
|
206
|
+
mcp: {
|
|
207
|
+
mcpServer: {
|
|
208
|
+
endpoint,
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
for (const policy of this.policies) {
|
|
216
|
+
policy.node.addDependency(target);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return target;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
"
|
|
223
|
+
`;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { applyGritQL, GRIT_INSERT_PLACEHOLDER, insertViaGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
5
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
6
|
+
import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR } from "../../../utils/shared-constructs-constants.js";
|
|
7
|
+
/**
|
|
8
|
+
* Bring existing workspaces up to the generators' current gateway-target
|
|
9
|
+
* support, so agents can be attached to an http-protocol AgentCore Gateway:
|
|
10
|
+
*
|
|
11
|
+
* - The vended `AgentCoreGateway` core construct gains the `protocol` prop
|
|
12
|
+
* (http gateways have no protocol type, which AgentCore Runtime targets
|
|
13
|
+
* require) and the `addAgent` / `addAgentTarget` methods.
|
|
14
|
+
* - Vended agent constructs gain the `agentName` member `addAgent` reads as
|
|
15
|
+
* the default gateway target name.
|
|
16
|
+
*
|
|
17
|
+
* Both files are generated with `KeepExisting`, so without this an upgraded
|
|
18
|
+
* workspace pairs new app-level constructs with stale core ones.
|
|
19
|
+
*/ const GATEWAY_CONSTRUCT_FILE = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/core/agentcore-gateway/agentcore-gateway.ts`;
|
|
20
|
+
const AGENTS_DIR = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/app/agents`;
|
|
21
|
+
const PROTOCOL_PROP = `/**
|
|
22
|
+
* The gateway's protocol. An \`mcp\` gateway aggregates MCP server targets
|
|
23
|
+
* into a single MCP endpoint. An \`http\` gateway has no protocol type and
|
|
24
|
+
* proxies requests to AgentCore Runtime targets via path-based routing
|
|
25
|
+
* (\`/<targetName>/invocations\`) — the target type AgentCore only allows on
|
|
26
|
+
* gateways without a protocol type.
|
|
27
|
+
*
|
|
28
|
+
* @default 'mcp'
|
|
29
|
+
*/
|
|
30
|
+
readonly protocol?: 'mcp' | 'http';`;
|
|
31
|
+
const PROTOCOL_CONSTRUCTOR_STATEMENTS = `this.protocol = props?.protocol ?? 'mcp';
|
|
32
|
+
`;
|
|
33
|
+
const PROTOCOL_TYPE_REMOVAL = `
|
|
34
|
+
if (this.protocol === 'http') {
|
|
35
|
+
// AgentCore Runtime targets require a gateway without a protocol type,
|
|
36
|
+
// which the Gateway L2 cannot express — it always renders MCP — so
|
|
37
|
+
// remove the protocol from the underlying CloudFormation resource.
|
|
38
|
+
const cfnGateway = this.gateway.node.defaultChild as agentcore.CfnGateway;
|
|
39
|
+
cfnGateway.addPropertyDeletionOverride('ProtocolType');
|
|
40
|
+
cfnGateway.addPropertyDeletionOverride('ProtocolConfiguration');
|
|
41
|
+
}`;
|
|
42
|
+
const AGENT_TARGET_METHODS = `
|
|
43
|
+
/**
|
|
44
|
+
* Add an agent runtime construct as a target of this Gateway. Requires the
|
|
45
|
+
* \`http\` protocol — the gateway proxies requests for the agent under
|
|
46
|
+
* \`<gatewayUrl>/<targetName>/invocations\`, without protocol translation.
|
|
47
|
+
*
|
|
48
|
+
* The target name defaults to the agent construct's \`agentName\` (its
|
|
49
|
+
* project's class name in kebab-case, e.g. \`MyAgent\` -> \`my-agent\`). It
|
|
50
|
+
* forms the target's invocation path, so renaming it later is a breaking
|
|
51
|
+
* change for consumers.
|
|
52
|
+
*/
|
|
53
|
+
public addAgent(
|
|
54
|
+
agent: Construct & {
|
|
55
|
+
readonly agentCoreRuntime: agentcore.Runtime;
|
|
56
|
+
readonly agentName: string;
|
|
57
|
+
},
|
|
58
|
+
props?: {
|
|
59
|
+
gatewayTargetName?: string;
|
|
60
|
+
},
|
|
61
|
+
): agentcore.CfnGatewayTarget {
|
|
62
|
+
return this.addAgentTarget({
|
|
63
|
+
gatewayTargetName: props?.gatewayTargetName ?? agent.agentName,
|
|
64
|
+
agentRuntimeArn: agent.agentCoreRuntime.agentRuntimeArn,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Register an agent runtime ARN as a Gateway target. Prefer
|
|
70
|
+
* {@link addAgent} when the construct is in scope.
|
|
71
|
+
*/
|
|
72
|
+
public addAgentTarget(props: {
|
|
73
|
+
gatewayTargetName: string;
|
|
74
|
+
agentRuntimeArn: string;
|
|
75
|
+
}): agentcore.CfnGatewayTarget {
|
|
76
|
+
if (this.protocol !== 'http') {
|
|
77
|
+
throw new Error(
|
|
78
|
+
\`Agent runtime targets require an http-protocol gateway, but this gateway uses '\${this.protocol}'.\`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The construct id is derived from the target name so the two change
|
|
83
|
+
// together — target names are unique per gateway, and replacing a target
|
|
84
|
+
// under an unchanged name fails with AlreadyExists.
|
|
85
|
+
const target = new agentcore.CfnGatewayTarget(
|
|
86
|
+
this,
|
|
87
|
+
\`Target-\${props.gatewayTargetName}\`,
|
|
88
|
+
{
|
|
89
|
+
gatewayIdentifier: this.gateway.gatewayId,
|
|
90
|
+
name: props.gatewayTargetName,
|
|
91
|
+
targetConfiguration: {
|
|
92
|
+
http: {
|
|
93
|
+
agentcoreRuntime: {
|
|
94
|
+
arn: props.agentRuntimeArn,
|
|
95
|
+
qualifier: 'DEFAULT',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
// The bare gateway IAM role credential: runtime targets reject the
|
|
100
|
+
// iamCredentialProvider detail MCP targets carry.
|
|
101
|
+
credentialProviderConfigurations: [
|
|
102
|
+
{
|
|
103
|
+
credentialProviderType: 'GATEWAY_IAM_ROLE',
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Grant the gateway role invoke access to the target runtime before the
|
|
110
|
+
// target is created — AgentCore validates access to the runtime during
|
|
111
|
+
// target creation.
|
|
112
|
+
const grant = this.gateway.role.addToPrincipalPolicy(
|
|
113
|
+
new iam.PolicyStatement({
|
|
114
|
+
actions: [
|
|
115
|
+
'bedrock-agentcore:InvokeAgentRuntime',
|
|
116
|
+
'bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream',
|
|
117
|
+
// A2A targets additionally serve their agent card via the gateway.
|
|
118
|
+
'bedrock-agentcore:GetAgentCard',
|
|
119
|
+
],
|
|
120
|
+
resources: [props.agentRuntimeArn, \`\${props.agentRuntimeArn}/*\`],
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
if (grant.policyDependable) {
|
|
124
|
+
target.node.addDependency(grant.policyDependable);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return target;
|
|
128
|
+
}`;
|
|
129
|
+
/**
|
|
130
|
+
* Add the `protocol` prop, its constructor handling and the agent-target
|
|
131
|
+
* methods to the vended `AgentCoreGateway` core construct.
|
|
132
|
+
*/ const migrateGatewayConstruct = async (tree, nextSteps)=>{
|
|
133
|
+
if (!tree.exists(GATEWAY_CONSTRUCT_FILE)) {
|
|
134
|
+
// No vended gateway construct in this workspace - nothing to migrate.
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if ((tree.read(GATEWAY_CONSTRUCT_FILE, 'utf-8') ?? '').includes('addAgentTarget')) {
|
|
138
|
+
// Already migrated.
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const divergedMessage = `${GATEWAY_CONSTRUCT_FILE}: the AgentCoreGateway construct has diverged from the generated shape - left untouched. Re-run the agentcore-gateway generator in a fresh workspace to see the current construct, which supports agent runtime targets via a 'protocol' prop and addAgent()/addAgentTarget() methods.`;
|
|
142
|
+
// Anchored on the shapes every vended version of the construct carries: the
|
|
143
|
+
// props interface, the class field the protocol field is inserted after,
|
|
144
|
+
// and the Gateway creation in the constructor.
|
|
145
|
+
const hasVendedShape = await matchGritQL(tree, GATEWAY_CONSTRUCT_FILE, '`export interface AgentCoreGatewayProps { $_ }`') && await matchGritQL(tree, GATEWAY_CONSTRUCT_FILE, '`private readonly targetRuntimeArns: string[] = []`') && await matchGritQL(tree, GATEWAY_CONSTRUCT_FILE, "`this.gateway = new agentcore.Gateway(this, 'Gateway', $_)`");
|
|
146
|
+
if (!hasVendedShape) {
|
|
147
|
+
nextSteps.push(divergedMessage);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
// 1. The protocol prop on AgentCoreGatewayProps. The placeholder keeps the
|
|
151
|
+
// prop's doc comment (with its backticks) out of the GritQL pattern.
|
|
152
|
+
await insertViaGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`export interface AgentCoreGatewayProps { $members }\` where {
|
|
153
|
+
$members <: not contains \`protocol\`
|
|
154
|
+
} => \`export interface AgentCoreGatewayProps { $members
|
|
155
|
+
${GRIT_INSERT_PLACEHOLDER}
|
|
156
|
+
}\``, PROTOCOL_PROP);
|
|
157
|
+
// 2. The protocol class field. Matched without the trailing semicolon —
|
|
158
|
+
// GritQL parses the snippet standalone, where the semicolon is not part
|
|
159
|
+
// of the field's AST node.
|
|
160
|
+
await applyGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`private readonly targetRuntimeArns: string[] = []\` as $field where {
|
|
161
|
+
$program <: not contains \`private readonly protocol\`
|
|
162
|
+
} => \`$field;
|
|
163
|
+
private readonly protocol: 'mcp' | 'http'\``);
|
|
164
|
+
// 3. Assign the field and remove the protocol type for http gateways.
|
|
165
|
+
await insertViaGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`this.gateway = new agentcore.Gateway($args);\` as $stmt where {
|
|
166
|
+
$program <: not contains \`this.protocol = props\`
|
|
167
|
+
} => \`${GRIT_INSERT_PLACEHOLDER}
|
|
168
|
+
$stmt\``, PROTOCOL_CONSTRUCTOR_STATEMENTS);
|
|
169
|
+
await insertViaGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`this.gateway = new agentcore.Gateway($args);\` as $stmt where {
|
|
170
|
+
$program <: not contains \`addPropertyDeletionOverride\`
|
|
171
|
+
} => \`$stmt
|
|
172
|
+
${GRIT_INSERT_PLACEHOLDER}\``, PROTOCOL_TYPE_REMOVAL);
|
|
173
|
+
// 4. The agent-target methods, inserted after addGatewayTarget (present in
|
|
174
|
+
// every vended version that also has the readiness probe field).
|
|
175
|
+
const addedMethods = await insertViaGritQL(tree, GATEWAY_CONSTRUCT_FILE, `\`public addGatewayTarget($params): agentcore.CfnGatewayTarget { $body }\` as $method where {
|
|
176
|
+
$program <: not contains \`addAgentTarget\`
|
|
177
|
+
} => \`$method
|
|
178
|
+
${GRIT_INSERT_PLACEHOLDER}\``, AGENT_TARGET_METHODS);
|
|
179
|
+
if (!addedMethods) {
|
|
180
|
+
nextSteps.push(divergedMessage);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Add the `agentName` member to each vended agent construct, which
|
|
186
|
+
* `AgentCoreGateway.addAgent` reads as the default gateway target name.
|
|
187
|
+
*/ const migrateAgentConstructs = async (tree, nextSteps)=>{
|
|
188
|
+
if (!tree.exists(AGENTS_DIR)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
for (const dir of tree.children(AGENTS_DIR)){
|
|
192
|
+
const constructFile = `${AGENTS_DIR}/${dir}/${dir}.ts`;
|
|
193
|
+
if (!tree.exists(constructFile)) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if ((tree.read(constructFile, 'utf-8') ?? '').includes('agentName')) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const added = await insertViaGritQL(tree, constructFile, `\`public readonly agentCoreRuntime: Runtime\` as $field => \`$field;
|
|
200
|
+
${GRIT_INSERT_PLACEHOLDER}\``, `/** Default Gateway target name for this agent. */
|
|
201
|
+
public readonly agentName = '${dir}'`);
|
|
202
|
+
if (!added) {
|
|
203
|
+
nextSteps.push(`${constructFile}: the agent construct has diverged from the generated shape - left untouched. To attach this agent to a gateway with addAgent(), add a \`public readonly agentName = '${dir}';\` member (or use addAgentTarget() with an explicit target name).`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
export default async function migration(tree) {
|
|
208
|
+
const nextSteps = [];
|
|
209
|
+
await migrateGatewayConstruct(tree, nextSteps);
|
|
210
|
+
await migrateAgentConstructs(tree, nextSteps);
|
|
211
|
+
await formatFilesInSubtree(tree);
|
|
212
|
+
return {
|
|
213
|
+
nextSteps
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/gateway-agent-targets/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { MigrationReturnObject, Tree } from '@nx/devkit';\nimport {\n applyGritQL,\n GRIT_INSERT_PLACEHOLDER,\n insertViaGritQL,\n matchGritQL,\n} from '../../../utils/ast';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n} from '../../../utils/shared-constructs-constants';\n\n/**\n * Bring existing workspaces up to the generators' current gateway-target\n * support, so agents can be attached to an http-protocol AgentCore Gateway:\n *\n * - The vended `AgentCoreGateway` core construct gains the `protocol` prop\n * (http gateways have no protocol type, which AgentCore Runtime targets\n * require) and the `addAgent` / `addAgentTarget` methods.\n * - Vended agent constructs gain the `agentName` member `addAgent` reads as\n * the default gateway target name.\n *\n * Both files are generated with `KeepExisting`, so without this an upgraded\n * workspace pairs new app-level constructs with stale core ones.\n */\n\nconst GATEWAY_CONSTRUCT_FILE = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/core/agentcore-gateway/agentcore-gateway.ts`;\n\nconst AGENTS_DIR = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/app/agents`;\n\nconst PROTOCOL_PROP = `/**\n * The gateway's protocol. An \\`mcp\\` gateway aggregates MCP server targets\n * into a single MCP endpoint. An \\`http\\` gateway has no protocol type and\n * proxies requests to AgentCore Runtime targets via path-based routing\n * (\\`/<targetName>/invocations\\`) — the target type AgentCore only allows on\n * gateways without a protocol type.\n *\n * @default 'mcp'\n */\n readonly protocol?: 'mcp' | 'http';`;\n\nconst PROTOCOL_CONSTRUCTOR_STATEMENTS = `this.protocol = props?.protocol ?? 'mcp';\n`;\n\nconst PROTOCOL_TYPE_REMOVAL = `\n if (this.protocol === 'http') {\n // AgentCore Runtime targets require a gateway without a protocol type,\n // which the Gateway L2 cannot express — it always renders MCP — so\n // remove the protocol from the underlying CloudFormation resource.\n const cfnGateway = this.gateway.node.defaultChild as agentcore.CfnGateway;\n cfnGateway.addPropertyDeletionOverride('ProtocolType');\n cfnGateway.addPropertyDeletionOverride('ProtocolConfiguration');\n }`;\n\nconst AGENT_TARGET_METHODS = `\n /**\n * Add an agent runtime construct as a target of this Gateway. Requires the\n * \\`http\\` protocol — the gateway proxies requests for the agent under\n * \\`<gatewayUrl>/<targetName>/invocations\\`, without protocol translation.\n *\n * The target name defaults to the agent construct's \\`agentName\\` (its\n * project's class name in kebab-case, e.g. \\`MyAgent\\` -> \\`my-agent\\`). It\n * forms the target's invocation path, so renaming it later is a breaking\n * change for consumers.\n */\n public addAgent(\n agent: Construct & {\n readonly agentCoreRuntime: agentcore.Runtime;\n readonly agentName: string;\n },\n props?: {\n gatewayTargetName?: string;\n },\n ): agentcore.CfnGatewayTarget {\n return this.addAgentTarget({\n gatewayTargetName: props?.gatewayTargetName ?? agent.agentName,\n agentRuntimeArn: agent.agentCoreRuntime.agentRuntimeArn,\n });\n }\n\n /**\n * Register an agent runtime ARN as a Gateway target. Prefer\n * {@link addAgent} when the construct is in scope.\n */\n public addAgentTarget(props: {\n gatewayTargetName: string;\n agentRuntimeArn: string;\n }): agentcore.CfnGatewayTarget {\n if (this.protocol !== 'http') {\n throw new Error(\n \\`Agent runtime targets require an http-protocol gateway, but this gateway uses '\\${this.protocol}'.\\`,\n );\n }\n\n // The construct id is derived from the target name so the two change\n // together — target names are unique per gateway, and replacing a target\n // under an unchanged name fails with AlreadyExists.\n const target = new agentcore.CfnGatewayTarget(\n this,\n \\`Target-\\${props.gatewayTargetName}\\`,\n {\n gatewayIdentifier: this.gateway.gatewayId,\n name: props.gatewayTargetName,\n targetConfiguration: {\n http: {\n agentcoreRuntime: {\n arn: props.agentRuntimeArn,\n qualifier: 'DEFAULT',\n },\n },\n },\n // The bare gateway IAM role credential: runtime targets reject the\n // iamCredentialProvider detail MCP targets carry.\n credentialProviderConfigurations: [\n {\n credentialProviderType: 'GATEWAY_IAM_ROLE',\n },\n ],\n },\n );\n\n // Grant the gateway role invoke access to the target runtime before the\n // target is created — AgentCore validates access to the runtime during\n // target creation.\n const grant = this.gateway.role.addToPrincipalPolicy(\n new iam.PolicyStatement({\n actions: [\n 'bedrock-agentcore:InvokeAgentRuntime',\n 'bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream',\n // A2A targets additionally serve their agent card via the gateway.\n 'bedrock-agentcore:GetAgentCard',\n ],\n resources: [props.agentRuntimeArn, \\`\\${props.agentRuntimeArn}/*\\`],\n }),\n );\n if (grant.policyDependable) {\n target.node.addDependency(grant.policyDependable);\n }\n\n return target;\n }`;\n\n/**\n * Add the `protocol` prop, its constructor handling and the agent-target\n * methods to the vended `AgentCoreGateway` core construct.\n */\nconst migrateGatewayConstruct = async (\n tree: Tree,\n nextSteps: string[],\n): Promise<void> => {\n if (!tree.exists(GATEWAY_CONSTRUCT_FILE)) {\n // No vended gateway construct in this workspace - nothing to migrate.\n return;\n }\n\n if (\n (tree.read(GATEWAY_CONSTRUCT_FILE, 'utf-8') ?? '').includes(\n 'addAgentTarget',\n )\n ) {\n // Already migrated.\n return;\n }\n\n const divergedMessage = `${GATEWAY_CONSTRUCT_FILE}: the AgentCoreGateway construct has diverged from the generated shape - left untouched. Re-run the agentcore-gateway generator in a fresh workspace to see the current construct, which supports agent runtime targets via a 'protocol' prop and addAgent()/addAgentTarget() methods.`;\n\n // Anchored on the shapes every vended version of the construct carries: the\n // props interface, the class field the protocol field is inserted after,\n // and the Gateway creation in the constructor.\n const hasVendedShape =\n (await matchGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n '`export interface AgentCoreGatewayProps { $_ }`',\n )) &&\n (await matchGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n '`private readonly targetRuntimeArns: string[] = []`',\n )) &&\n (await matchGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n \"`this.gateway = new agentcore.Gateway(this, 'Gateway', $_)`\",\n ));\n\n if (!hasVendedShape) {\n nextSteps.push(divergedMessage);\n return;\n }\n\n // 1. The protocol prop on AgentCoreGatewayProps. The placeholder keeps the\n // prop's doc comment (with its backticks) out of the GritQL pattern.\n await insertViaGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`export interface AgentCoreGatewayProps { $members }\\` where {\n $members <: not contains \\`protocol\\`\n} => \\`export interface AgentCoreGatewayProps { $members\n ${GRIT_INSERT_PLACEHOLDER}\n}\\``,\n PROTOCOL_PROP,\n );\n\n // 2. The protocol class field. Matched without the trailing semicolon —\n // GritQL parses the snippet standalone, where the semicolon is not part\n // of the field's AST node.\n await applyGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`private readonly targetRuntimeArns: string[] = []\\` as $field where {\n $program <: not contains \\`private readonly protocol\\`\n} => \\`$field;\n private readonly protocol: 'mcp' | 'http'\\``,\n );\n\n // 3. Assign the field and remove the protocol type for http gateways.\n await insertViaGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`this.gateway = new agentcore.Gateway($args);\\` as $stmt where {\n $program <: not contains \\`this.protocol = props\\`\n} => \\`${GRIT_INSERT_PLACEHOLDER}\n $stmt\\``,\n PROTOCOL_CONSTRUCTOR_STATEMENTS,\n );\n await insertViaGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`this.gateway = new agentcore.Gateway($args);\\` as $stmt where {\n $program <: not contains \\`addPropertyDeletionOverride\\`\n} => \\`$stmt\n${GRIT_INSERT_PLACEHOLDER}\\``,\n PROTOCOL_TYPE_REMOVAL,\n );\n\n // 4. The agent-target methods, inserted after addGatewayTarget (present in\n // every vended version that also has the readiness probe field).\n const addedMethods = await insertViaGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`public addGatewayTarget($params): agentcore.CfnGatewayTarget { $body }\\` as $method where {\n $program <: not contains \\`addAgentTarget\\`\n} => \\`$method\n${GRIT_INSERT_PLACEHOLDER}\\``,\n AGENT_TARGET_METHODS,\n );\n\n if (!addedMethods) {\n nextSteps.push(divergedMessage);\n return;\n }\n};\n\n/**\n * Add the `agentName` member to each vended agent construct, which\n * `AgentCoreGateway.addAgent` reads as the default gateway target name.\n */\nconst migrateAgentConstructs = async (\n tree: Tree,\n nextSteps: string[],\n): Promise<void> => {\n if (!tree.exists(AGENTS_DIR)) {\n return;\n }\n for (const dir of tree.children(AGENTS_DIR)) {\n const constructFile = `${AGENTS_DIR}/${dir}/${dir}.ts`;\n if (!tree.exists(constructFile)) {\n continue;\n }\n if ((tree.read(constructFile, 'utf-8') ?? '').includes('agentName')) {\n // Already migrated (or user-added).\n continue;\n }\n const added = await insertViaGritQL(\n tree,\n constructFile,\n `\\`public readonly agentCoreRuntime: Runtime\\` as $field => \\`$field;\n ${GRIT_INSERT_PLACEHOLDER}\\``,\n `/** Default Gateway target name for this agent. */\n public readonly agentName = '${dir}'`,\n );\n if (!added) {\n nextSteps.push(\n `${constructFile}: the agent construct has diverged from the generated shape - left untouched. To attach this agent to a gateway with addAgent(), add a \\`public readonly agentName = '${dir}';\\` member (or use addAgentTarget() with an explicit target name).`,\n );\n }\n }\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n await migrateGatewayConstruct(tree, nextSteps);\n await migrateAgentConstructs(tree, nextSteps);\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["applyGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","GATEWAY_CONSTRUCT_FILE","AGENTS_DIR","PROTOCOL_PROP","PROTOCOL_CONSTRUCTOR_STATEMENTS","PROTOCOL_TYPE_REMOVAL","AGENT_TARGET_METHODS","migrateGatewayConstruct","tree","nextSteps","exists","read","includes","divergedMessage","hasVendedShape","push","addedMethods","migrateAgentConstructs","dir","children","constructFile","added","migration"],"mappings":"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"}
|
|
@@ -55,6 +55,8 @@ export class SnapshotBedrockAgent
|
|
|
55
55
|
{
|
|
56
56
|
public readonly dockerImage: AgentRuntimeArtifact;
|
|
57
57
|
public readonly agentCoreRuntime: Runtime;
|
|
58
|
+
/** Default Gateway target name for this agent. */
|
|
59
|
+
public readonly agentName = 'snapshot-bedrock-agent';
|
|
58
60
|
|
|
59
61
|
constructor(scope: Construct, id: string, props?: SnapshotBedrockAgentProps) {
|
|
60
62
|
super(scope, id);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { type Tree } from '@nx/devkit';
|
|
6
6
|
import type { ResolvedConnectionOptions } from '../../../connection/generator';
|
|
7
|
+
import type { AgentGatewayRoute } from '../../../ts/agent/react-connection/generator';
|
|
7
8
|
import { type NxGeneratorInfo } from '../../../utils/nx';
|
|
8
9
|
/** The metadata this generator records, which its predicates read. */
|
|
9
10
|
export interface PyAgentReactConnectionMetadata {
|
|
@@ -152,5 +153,7 @@ export declare const DEPENDENCIES: import("../../../utils/declared-dependencies"
|
|
|
152
153
|
when: (m: PyAgentReactConnectionMetadata) => boolean;
|
|
153
154
|
}], readonly import("../../../utils/declared-dependencies").DeclaredPyDependency<"a2a-sdk" | "ag-ui-langgraph" | "ag-ui-protocol" | "ag-ui-strands" | "aws-lambda-powertools" | "aws-lambda-powertools[tracer]" | "aws-lambda-powertools[parser]" | "aws-opentelemetry-distro" | "bedrock-agentcore" | "boto3" | "checkov" | "fastapi" | "fastapi[standard]" | "httpx" | "langchain" | "langchain-aws" | "langchain-mcp-adapters" | "langgraph" | "mcp" | "pip-check-updates" | "pip-licenses" | "ruff" | "strands-agents" | "strands-agents[a2a]" | "strands-agents-tools" | "ty" | "pynamodb" | "uvicorn" | "sqlmodel" | "alembic" | "aiomysql" | "asyncpg" | "greenlet", PyAgentReactConnectionMetadata>[]>;
|
|
154
155
|
export declare const PY_AGENT_REACT_CONNECTION_GENERATOR_INFO: NxGeneratorInfo;
|
|
155
|
-
export declare const pyAgentReactConnectionGenerator: (tree: Tree, options: ResolvedConnectionOptions
|
|
156
|
+
export declare const pyAgentReactConnectionGenerator: (tree: Tree, options: ResolvedConnectionOptions & {
|
|
157
|
+
gatewayRoute?: AgentGatewayRoute;
|
|
158
|
+
}) => Promise<() => Promise<void>>;
|
|
156
159
|
export default pyAgentReactConnectionGenerator;
|
|
@@ -10,7 +10,7 @@ import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
|
10
10
|
import { installDependencies } from "../../../utils/install.js";
|
|
11
11
|
import { addGeneratorMetricsIfApplicable } from "../../../utils/metrics.js";
|
|
12
12
|
import { kebabCase, toClassName, toSnakeCase } from "../../../utils/names.js";
|
|
13
|
-
import { addComponentGeneratorMetadata, getGeneratorInfo, readProjectConfigurationUnqualified } from "../../../utils/nx.js";
|
|
13
|
+
import { addComponentGeneratorMetadata, addDependencyToTargetIfNotPresent, getGeneratorInfo, readProjectConfigurationUnqualified } from "../../../utils/nx.js";
|
|
14
14
|
import { sortObjectKeys } from "../../../utils/object.js";
|
|
15
15
|
import { toProjectRelativePath } from "../../../utils/paths.js";
|
|
16
16
|
import { addPyAgentTargetToLocalDev, openApiClientLocalDevDeps } from "./local-dev.js";
|
|
@@ -36,7 +36,8 @@ export const pyAgentReactConnectionGenerator = async (tree, options)=>{
|
|
|
36
36
|
const agentName = targetComponent?.name ?? 'agent';
|
|
37
37
|
const agentNameClassName = targetComponent?.rc ?? toClassName(agentName);
|
|
38
38
|
const agentPort = targetComponent?.port ?? metadata?.ports?.[0] ?? 8081;
|
|
39
|
-
|
|
39
|
+
// Behind a gateway the browser authenticates with the gateway, not the agent.
|
|
40
|
+
const auth = (options.gatewayRoute?.gatewayAuth ?? targetComponent?.auth ?? metadata?.auth ?? 'iam').toLowerCase();
|
|
40
41
|
const protocol = (targetComponent?.protocol ?? 'http').toLowerCase();
|
|
41
42
|
// Recorded below and read by the declaration's predicates, so the packages
|
|
42
43
|
// added here are exactly the ones the version sync will own.
|
|
@@ -54,7 +55,8 @@ export const pyAgentReactConnectionGenerator = async (tree, options)=>{
|
|
|
54
55
|
frontendProjectConfig,
|
|
55
56
|
agentName,
|
|
56
57
|
agentNameClassName,
|
|
57
|
-
auth: auth
|
|
58
|
+
auth: auth,
|
|
59
|
+
gatewayRoute: options.gatewayRoute
|
|
58
60
|
});
|
|
59
61
|
} else {
|
|
60
62
|
const moduleName = getModuleName(agentProjectConfig);
|
|
@@ -101,25 +103,44 @@ export const pyAgentReactConnectionGenerator = async (tree, options)=>{
|
|
|
101
103
|
auth,
|
|
102
104
|
port: agentPort,
|
|
103
105
|
isAgentRuntime: true,
|
|
106
|
+
gatewayRoute: options.gatewayRoute,
|
|
104
107
|
skipLocalDev: true
|
|
105
108
|
}, DEPENDENCIES);
|
|
106
109
|
additionalLocalDevDeps = openApiClientLocalDevDeps(agentNameClassName);
|
|
107
110
|
// HTTP only — the AG-UI branch handles this inside addAgUiReactConnection.
|
|
108
111
|
// Agent constructs publish their runtime ARN to the 'agentcore' namespace
|
|
109
112
|
// by default, which isn't exposed to the website; patch them to also
|
|
110
|
-
// publish under 'connection' so the browser can read it.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
// publish under 'connection' so the browser can read it. When routing via
|
|
114
|
+
// a gateway, the gateway publishes its own URL instead.
|
|
115
|
+
if (!options.gatewayRoute) {
|
|
116
|
+
await addAgentRuntimeToConnectionNamespace(tree, {
|
|
117
|
+
agentNameKebabCase: kebabCase(agentNameClassName),
|
|
118
|
+
agentNameClassName
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (options.gatewayRoute) {
|
|
123
|
+
// The gateway react-connection wires the website's dev target to the
|
|
124
|
+
// local gateway (which proxies to the agent); only the OpenAPI client
|
|
125
|
+
// generation targets are still needed here.
|
|
126
|
+
if (additionalLocalDevDeps.length > 0) {
|
|
127
|
+
const websiteConfig = readProjectConfigurationUnqualified(tree, frontendProjectConfig.name);
|
|
128
|
+
if (websiteConfig.targets?.['dev']) {
|
|
129
|
+
for (const additional of additionalLocalDevDeps){
|
|
130
|
+
addDependencyToTargetIfNotPresent(websiteConfig, 'dev', additional);
|
|
131
|
+
}
|
|
132
|
+
updateProjectConfiguration(tree, websiteConfig.name, websiteConfig);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
await addPyAgentTargetToLocalDev(tree, frontendProjectConfig.name, agentProjectConfig.name, {
|
|
137
|
+
agentName,
|
|
138
|
+
agentNameClassName,
|
|
139
|
+
port: agentPort,
|
|
140
|
+
targetComponent,
|
|
141
|
+
additionalDependencyTargets: additionalLocalDevDeps
|
|
114
142
|
});
|
|
115
143
|
}
|
|
116
|
-
await addPyAgentTargetToLocalDev(tree, frontendProjectConfig.name, agentProjectConfig.name, {
|
|
117
|
-
agentName,
|
|
118
|
-
agentNameClassName,
|
|
119
|
-
port: agentPort,
|
|
120
|
-
targetComponent,
|
|
121
|
-
additionalDependencyTargets: additionalLocalDevDeps
|
|
122
|
-
});
|
|
123
144
|
// Recorded so the version sync knows this connection's dependencies are ours.
|
|
124
145
|
addComponentGeneratorMetadata(tree, frontendProjectConfig.name, PY_AGENT_REACT_CONNECTION_GENERATOR_INFO, toProjectRelativePath(frontendProjectConfig, protocol === 'ag-ui' ? joinPathFragments(frontendProjectConfig.sourceRoot, 'hooks', `useAgui${agentNameClassName}`) : joinPathFragments(frontendProjectConfig.sourceRoot, 'components', `${agentNameClassName}Provider`)), agentNameClassName, connectionMetadata);
|
|
125
146
|
await addGeneratorMetricsIfApplicable(tree, [
|