@aws/nx-plugin 1.0.0-rc.16 → 1.0.0-rc.18
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 +9 -1
- package/package.json +1 -1
- package/src/agentcore-gateway/attach-upstream.d.ts +33 -0
- package/src/agentcore-gateway/attach-upstream.js +41 -0
- package/src/agentcore-gateway/attach-upstream.js.map +1 -0
- package/src/agentcore-gateway/files/project/serve-local.ts.template +3 -2
- package/src/agentcore-gateway/gateway-connection/generator.d.ts +21 -0
- package/src/agentcore-gateway/gateway-connection/generator.js +102 -0
- package/src/agentcore-gateway/gateway-connection/generator.js.map +1 -0
- package/src/agentcore-gateway/gateway-connection/schema.d.ts +12 -0
- package/src/agentcore-gateway/gateway-connection/schema.json +26 -0
- package/src/agentcore-gateway/mcp-connection/generator.js +8 -24
- package/src/agentcore-gateway/mcp-connection/generator.js.map +1 -1
- package/src/connection/generator.js +66 -63
- package/src/connection/generator.js.map +1 -1
- package/src/license/generator.js +8 -19
- package/src/license/generator.js.map +1 -1
- package/src/license/known-exceptions.d.ts +0 -1
- package/src/license/known-exceptions.js +1 -8
- package/src/license/known-exceptions.js.map +1 -1
- package/src/py/agent/generator.js +0 -5
- package/src/py/agent/generator.js.map +1 -1
- package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +122 -14
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +122 -14
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +3 -0
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +110 -28
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +90 -2
- package/src/utils/api-constructs/files/cdk/core/api/utils/utils.ts.template +61 -7
- package/src/utils/versions.d.ts +1 -1
- package/src/utils/versions.js +1 -1
|
@@ -1751,6 +1751,8 @@ export type ApiIntegrations<TOperation extends string, TBaseIntegration> =
|
|
|
1751
1751
|
* @template TDefaultIntegrationProps - Type for default integration properties
|
|
1752
1752
|
* @template TDefaultIntegration - Type for default integration implementation
|
|
1753
1753
|
* @template TPattern - The integration pattern ('shared' or 'isolated')
|
|
1754
|
+
* @template TOverridden - Union of operation names that have been overridden
|
|
1755
|
+
* @template TOperationOptioned - Union of operation names with per-operation options
|
|
1754
1756
|
*/
|
|
1755
1757
|
export class IntegrationBuilder<
|
|
1756
1758
|
TOperation extends string,
|
|
@@ -1759,6 +1761,8 @@ export class IntegrationBuilder<
|
|
|
1759
1761
|
TDefaultIntegrationProps extends object,
|
|
1760
1762
|
TDefaultIntegration extends TBaseIntegration,
|
|
1761
1763
|
TPattern extends 'shared' | 'isolated',
|
|
1764
|
+
TOverridden extends string = never,
|
|
1765
|
+
TOperationOptioned extends string = never,
|
|
1762
1766
|
> {
|
|
1763
1767
|
/** Options for the integration builder */
|
|
1764
1768
|
private options: IntegrationBuilderProps<
|
|
@@ -1771,6 +1775,11 @@ export class IntegrationBuilder<
|
|
|
1771
1775
|
/** Map of operation names to their custom integrations */
|
|
1772
1776
|
private integrations: Partial<TIntegrations> = {};
|
|
1773
1777
|
|
|
1778
|
+
/** Map of default integration keys to per-operation default option overrides */
|
|
1779
|
+
private perOperationOptions: Partial<
|
|
1780
|
+
Record<string, Partial<TDefaultIntegrationProps>>
|
|
1781
|
+
> = {};
|
|
1782
|
+
|
|
1774
1783
|
/**
|
|
1775
1784
|
* Create an Integration Builder for an HTTP API with a shared pattern
|
|
1776
1785
|
*/
|
|
@@ -1925,11 +1934,16 @@ export class IntegrationBuilder<
|
|
|
1925
1934
|
/**
|
|
1926
1935
|
* Overrides default integrations with custom implementations for specific operations.
|
|
1927
1936
|
*
|
|
1937
|
+
* Operations which have per-operation options set via withOperationOptions cannot be
|
|
1938
|
+
* overridden, since these still use the default integration.
|
|
1939
|
+
*
|
|
1928
1940
|
* @param overrides - Map of operation names to their custom integration implementations
|
|
1929
1941
|
* @returns The builder instance with updated type information reflecting the overrides
|
|
1930
1942
|
*/
|
|
1931
1943
|
public withOverrides<
|
|
1932
|
-
TOverrideIntegrations extends Partial<
|
|
1944
|
+
TOverrideIntegrations extends Partial<
|
|
1945
|
+
Record<Exclude<TOperation, TOperationOptioned>, TBaseIntegration>
|
|
1946
|
+
>,
|
|
1933
1947
|
>(overrides: TOverrideIntegrations) {
|
|
1934
1948
|
this.integrations = { ...this.integrations, ...overrides };
|
|
1935
1949
|
// Re-type to include the overridden integration types.
|
|
@@ -1945,7 +1959,9 @@ export class IntegrationBuilder<
|
|
|
1945
1959
|
MergedIntegrations,
|
|
1946
1960
|
TDefaultIntegrationProps,
|
|
1947
1961
|
TDefaultIntegration,
|
|
1948
|
-
TPattern
|
|
1962
|
+
TPattern,
|
|
1963
|
+
TOverridden | Extract<keyof TOverrideIntegrations, string>,
|
|
1964
|
+
TOperationOptioned
|
|
1949
1965
|
>;
|
|
1950
1966
|
}
|
|
1951
1967
|
|
|
@@ -1964,6 +1980,43 @@ export class IntegrationBuilder<
|
|
|
1964
1980
|
return this;
|
|
1965
1981
|
}
|
|
1966
1982
|
|
|
1983
|
+
/**
|
|
1984
|
+
* Updates the default integration options for specific operations, without
|
|
1985
|
+
* affecting the others. The given options are merged with the defaults (and
|
|
1986
|
+
* any options set via withDefaultOptions) when building each default integration.
|
|
1987
|
+
*
|
|
1988
|
+
* Operations which have been replaced via withOverrides cannot be targeted, since
|
|
1989
|
+
* they no longer use the default integration.
|
|
1990
|
+
*
|
|
1991
|
+
* @param options - Map of operation names to partial default integration options
|
|
1992
|
+
* @returns The builder instance
|
|
1993
|
+
*/
|
|
1994
|
+
public withOperationOptions<
|
|
1995
|
+
TOptions extends Partial<
|
|
1996
|
+
Record<
|
|
1997
|
+
Exclude<DefaultIntegrationKeys<TPattern, TOperation>, TOverridden>,
|
|
1998
|
+
Partial<TDefaultIntegrationProps>
|
|
1999
|
+
>
|
|
2000
|
+
>,
|
|
2001
|
+
>(options: TOptions) {
|
|
2002
|
+
Object.entries(options).forEach(([op, opOptions]) => {
|
|
2003
|
+
this.perOperationOptions[op] = {
|
|
2004
|
+
...this.perOperationOptions[op],
|
|
2005
|
+
...(opOptions as Partial<TDefaultIntegrationProps>),
|
|
2006
|
+
};
|
|
2007
|
+
});
|
|
2008
|
+
return this as unknown as IntegrationBuilder<
|
|
2009
|
+
TOperation,
|
|
2010
|
+
TBaseIntegration,
|
|
2011
|
+
TIntegrations,
|
|
2012
|
+
TDefaultIntegrationProps,
|
|
2013
|
+
TDefaultIntegration,
|
|
2014
|
+
TPattern,
|
|
2015
|
+
TOverridden,
|
|
2016
|
+
TOperationOptioned | Extract<keyof TOptions, string>
|
|
2017
|
+
>;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
1967
2020
|
/**
|
|
1968
2021
|
* Builds and returns the complete set of integrations.
|
|
1969
2022
|
*
|
|
@@ -1978,6 +2031,10 @@ export class IntegrationBuilder<
|
|
|
1978
2031
|
*/
|
|
1979
2032
|
public build(): TIntegrations {
|
|
1980
2033
|
const options = this.options;
|
|
2034
|
+
const buildOptionsFor = (op: string): TDefaultIntegrationProps => ({
|
|
2035
|
+
...options.defaultIntegrationOptions,
|
|
2036
|
+
...this.perOperationOptions[op],
|
|
2037
|
+
});
|
|
1981
2038
|
return {
|
|
1982
2039
|
...Object.fromEntries(
|
|
1983
2040
|
options.pattern === 'shared'
|
|
@@ -1986,7 +2043,7 @@ export class IntegrationBuilder<
|
|
|
1986
2043
|
'$router',
|
|
1987
2044
|
options.buildDefaultIntegration(
|
|
1988
2045
|
'$router',
|
|
1989
|
-
|
|
2046
|
+
buildOptionsFor('$router'),
|
|
1990
2047
|
),
|
|
1991
2048
|
],
|
|
1992
2049
|
]
|
|
@@ -1997,10 +2054,7 @@ export class IntegrationBuilder<
|
|
|
1997
2054
|
)
|
|
1998
2055
|
.map((op) => [
|
|
1999
2056
|
op,
|
|
2000
|
-
options.buildDefaultIntegration(
|
|
2001
|
-
op,
|
|
2002
|
-
options.defaultIntegrationOptions,
|
|
2003
|
-
),
|
|
2057
|
+
options.buildDefaultIntegration(op, buildOptionsFor(op)),
|
|
2004
2058
|
]),
|
|
2005
2059
|
),
|
|
2006
2060
|
...this.integrations,
|
|
@@ -2708,6 +2762,8 @@ export type ApiIntegrations<TOperation extends string, TBaseIntegration> =
|
|
|
2708
2762
|
* @template TDefaultIntegrationProps - Type for default integration properties
|
|
2709
2763
|
* @template TDefaultIntegration - Type for default integration implementation
|
|
2710
2764
|
* @template TPattern - The integration pattern ('shared' or 'isolated')
|
|
2765
|
+
* @template TOverridden - Union of operation names that have been overridden
|
|
2766
|
+
* @template TOperationOptioned - Union of operation names with per-operation options
|
|
2711
2767
|
*/
|
|
2712
2768
|
export class IntegrationBuilder<
|
|
2713
2769
|
TOperation extends string,
|
|
@@ -2716,6 +2772,8 @@ export class IntegrationBuilder<
|
|
|
2716
2772
|
TDefaultIntegrationProps extends object,
|
|
2717
2773
|
TDefaultIntegration extends TBaseIntegration,
|
|
2718
2774
|
TPattern extends 'shared' | 'isolated',
|
|
2775
|
+
TOverridden extends string = never,
|
|
2776
|
+
TOperationOptioned extends string = never,
|
|
2719
2777
|
> {
|
|
2720
2778
|
/** Options for the integration builder */
|
|
2721
2779
|
private options: IntegrationBuilderProps<
|
|
@@ -2728,6 +2786,11 @@ export class IntegrationBuilder<
|
|
|
2728
2786
|
/** Map of operation names to their custom integrations */
|
|
2729
2787
|
private integrations: Partial<TIntegrations> = {};
|
|
2730
2788
|
|
|
2789
|
+
/** Map of default integration keys to per-operation default option overrides */
|
|
2790
|
+
private perOperationOptions: Partial<
|
|
2791
|
+
Record<string, Partial<TDefaultIntegrationProps>>
|
|
2792
|
+
> = {};
|
|
2793
|
+
|
|
2731
2794
|
/**
|
|
2732
2795
|
* Create an Integration Builder for an HTTP API with a shared pattern
|
|
2733
2796
|
*/
|
|
@@ -2882,11 +2945,16 @@ export class IntegrationBuilder<
|
|
|
2882
2945
|
/**
|
|
2883
2946
|
* Overrides default integrations with custom implementations for specific operations.
|
|
2884
2947
|
*
|
|
2948
|
+
* Operations which have per-operation options set via withOperationOptions cannot be
|
|
2949
|
+
* overridden, since these still use the default integration.
|
|
2950
|
+
*
|
|
2885
2951
|
* @param overrides - Map of operation names to their custom integration implementations
|
|
2886
2952
|
* @returns The builder instance with updated type information reflecting the overrides
|
|
2887
2953
|
*/
|
|
2888
2954
|
public withOverrides<
|
|
2889
|
-
TOverrideIntegrations extends Partial<
|
|
2955
|
+
TOverrideIntegrations extends Partial<
|
|
2956
|
+
Record<Exclude<TOperation, TOperationOptioned>, TBaseIntegration>
|
|
2957
|
+
>,
|
|
2890
2958
|
>(overrides: TOverrideIntegrations) {
|
|
2891
2959
|
this.integrations = { ...this.integrations, ...overrides };
|
|
2892
2960
|
// Re-type to include the overridden integration types.
|
|
@@ -2902,7 +2970,9 @@ export class IntegrationBuilder<
|
|
|
2902
2970
|
MergedIntegrations,
|
|
2903
2971
|
TDefaultIntegrationProps,
|
|
2904
2972
|
TDefaultIntegration,
|
|
2905
|
-
TPattern
|
|
2973
|
+
TPattern,
|
|
2974
|
+
TOverridden | Extract<keyof TOverrideIntegrations, string>,
|
|
2975
|
+
TOperationOptioned
|
|
2906
2976
|
>;
|
|
2907
2977
|
}
|
|
2908
2978
|
|
|
@@ -2921,6 +2991,43 @@ export class IntegrationBuilder<
|
|
|
2921
2991
|
return this;
|
|
2922
2992
|
}
|
|
2923
2993
|
|
|
2994
|
+
/**
|
|
2995
|
+
* Updates the default integration options for specific operations, without
|
|
2996
|
+
* affecting the others. The given options are merged with the defaults (and
|
|
2997
|
+
* any options set via withDefaultOptions) when building each default integration.
|
|
2998
|
+
*
|
|
2999
|
+
* Operations which have been replaced via withOverrides cannot be targeted, since
|
|
3000
|
+
* they no longer use the default integration.
|
|
3001
|
+
*
|
|
3002
|
+
* @param options - Map of operation names to partial default integration options
|
|
3003
|
+
* @returns The builder instance
|
|
3004
|
+
*/
|
|
3005
|
+
public withOperationOptions<
|
|
3006
|
+
TOptions extends Partial<
|
|
3007
|
+
Record<
|
|
3008
|
+
Exclude<DefaultIntegrationKeys<TPattern, TOperation>, TOverridden>,
|
|
3009
|
+
Partial<TDefaultIntegrationProps>
|
|
3010
|
+
>
|
|
3011
|
+
>,
|
|
3012
|
+
>(options: TOptions) {
|
|
3013
|
+
Object.entries(options).forEach(([op, opOptions]) => {
|
|
3014
|
+
this.perOperationOptions[op] = {
|
|
3015
|
+
...this.perOperationOptions[op],
|
|
3016
|
+
...(opOptions as Partial<TDefaultIntegrationProps>),
|
|
3017
|
+
};
|
|
3018
|
+
});
|
|
3019
|
+
return this as unknown as IntegrationBuilder<
|
|
3020
|
+
TOperation,
|
|
3021
|
+
TBaseIntegration,
|
|
3022
|
+
TIntegrations,
|
|
3023
|
+
TDefaultIntegrationProps,
|
|
3024
|
+
TDefaultIntegration,
|
|
3025
|
+
TPattern,
|
|
3026
|
+
TOverridden,
|
|
3027
|
+
TOperationOptioned | Extract<keyof TOptions, string>
|
|
3028
|
+
>;
|
|
3029
|
+
}
|
|
3030
|
+
|
|
2924
3031
|
/**
|
|
2925
3032
|
* Builds and returns the complete set of integrations.
|
|
2926
3033
|
*
|
|
@@ -2935,6 +3042,10 @@ export class IntegrationBuilder<
|
|
|
2935
3042
|
*/
|
|
2936
3043
|
public build(): TIntegrations {
|
|
2937
3044
|
const options = this.options;
|
|
3045
|
+
const buildOptionsFor = (op: string): TDefaultIntegrationProps => ({
|
|
3046
|
+
...options.defaultIntegrationOptions,
|
|
3047
|
+
...this.perOperationOptions[op],
|
|
3048
|
+
});
|
|
2938
3049
|
return {
|
|
2939
3050
|
...Object.fromEntries(
|
|
2940
3051
|
options.pattern === 'shared'
|
|
@@ -2943,7 +3054,7 @@ export class IntegrationBuilder<
|
|
|
2943
3054
|
'$router',
|
|
2944
3055
|
options.buildDefaultIntegration(
|
|
2945
3056
|
'$router',
|
|
2946
|
-
|
|
3057
|
+
buildOptionsFor('$router'),
|
|
2947
3058
|
),
|
|
2948
3059
|
],
|
|
2949
3060
|
]
|
|
@@ -2954,10 +3065,7 @@ export class IntegrationBuilder<
|
|
|
2954
3065
|
)
|
|
2955
3066
|
.map((op) => [
|
|
2956
3067
|
op,
|
|
2957
|
-
options.buildDefaultIntegration(
|
|
2958
|
-
op,
|
|
2959
|
-
options.defaultIntegrationOptions,
|
|
2960
|
-
),
|
|
3068
|
+
options.buildDefaultIntegration(op, buildOptionsFor(op)),
|
|
2961
3069
|
]),
|
|
2962
3070
|
),
|
|
2963
3071
|
...this.integrations,
|
|
@@ -18,6 +18,9 @@ import { findWorkspaceRoot } from '../../../core/workspace.js';
|
|
|
18
18
|
<%_ } _%>
|
|
19
19
|
*/
|
|
20
20
|
export class <%- nameClassName %> extends AgentCoreGateway {
|
|
21
|
+
/** Default Gateway target name when added to another Gateway. */
|
|
22
|
+
public readonly gatewayName = '<%- nameKebabCase %>';
|
|
23
|
+
|
|
21
24
|
constructor(scope: Construct, id: string) {
|
|
22
25
|
super(scope, id, {
|
|
23
26
|
<%_ if (cedarPolicy) { _%>
|
|
@@ -187,34 +187,7 @@ export class AgentCoreGateway extends Construct implements iam.IGrantable {
|
|
|
187
187
|
cdk.Fn.split('/', cdk.Fn.join('%3A', cdk.Fn.split(':', arn))),
|
|
188
188
|
);
|
|
189
189
|
const endpoint = `https://bedrock-agentcore.${region}.amazonaws.com/runtimes/${encodedArn}/invocations?qualifier=DEFAULT`;
|
|
190
|
-
|
|
191
|
-
// together — target names are unique per gateway, and replacing a target
|
|
192
|
-
// under an unchanged name fails with AlreadyExists.
|
|
193
|
-
const target = new agentcore.CfnGatewayTarget(
|
|
194
|
-
this,
|
|
195
|
-
`Target-${props.gatewayTargetName}`,
|
|
196
|
-
{
|
|
197
|
-
gatewayIdentifier: this.gateway.gatewayId,
|
|
198
|
-
name: props.gatewayTargetName,
|
|
199
|
-
targetConfiguration: {
|
|
200
|
-
mcp: {
|
|
201
|
-
mcpServer: {
|
|
202
|
-
endpoint,
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
credentialProviderConfigurations: [
|
|
207
|
-
{
|
|
208
|
-
credentialProviderType: 'GATEWAY_IAM_ROLE',
|
|
209
|
-
credentialProvider: {
|
|
210
|
-
iamCredentialProvider: {
|
|
211
|
-
service: 'bedrock-agentcore',
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
],
|
|
216
|
-
},
|
|
217
|
-
);
|
|
190
|
+
const target = this.addTarget(props.gatewayTargetName, endpoint);
|
|
218
191
|
|
|
219
192
|
// Grant the gateway role invoke access to the target runtime before the
|
|
220
193
|
// target is created — AgentCore probes the target during creation, which
|
|
@@ -253,6 +226,115 @@ export class AgentCoreGateway extends Construct implements iam.IGrantable {
|
|
|
253
226
|
}
|
|
254
227
|
target.node.addDependency(probe.trigger);
|
|
255
228
|
|
|
229
|
+
return target;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Add another Gateway as a target of this Gateway, exposing its tools
|
|
234
|
+
* under `<targetName>___<innerTargetName>___<toolName>` names.
|
|
235
|
+
*
|
|
236
|
+
* The target name defaults to the gateway construct's `gatewayName`
|
|
237
|
+
* (its project's class name in kebab-case, e.g. `MyGateway` ->
|
|
238
|
+
* `my-gateway`). It prefixes Cedar action names and the gateway's tool
|
|
239
|
+
* names, so renaming it later is a breaking change for consumers.
|
|
240
|
+
*
|
|
241
|
+
* Both gateways evaluate their own Cedar policies: this gateway
|
|
242
|
+
* authorizes the prefixed action, then the target gateway authorizes the
|
|
243
|
+
* inner action for this gateway's role.
|
|
244
|
+
*/
|
|
245
|
+
public addGateway(
|
|
246
|
+
gateway: Construct & {
|
|
247
|
+
readonly gateway: agentcore.Gateway;
|
|
248
|
+
readonly gatewayName: string;
|
|
249
|
+
},
|
|
250
|
+
props?: {
|
|
251
|
+
gatewayTargetName?: string;
|
|
252
|
+
},
|
|
253
|
+
): agentcore.CfnGatewayTarget {
|
|
254
|
+
const target = this.addGatewayTarget({
|
|
255
|
+
gatewayTargetName: props?.gatewayTargetName ?? gateway.gatewayName,
|
|
256
|
+
// The Gateway L2 only populates gatewayUrl when created from its own
|
|
257
|
+
// props; fall back to the CloudFormation attribute otherwise.
|
|
258
|
+
gatewayUrl:
|
|
259
|
+
gateway.gateway.gatewayUrl ??
|
|
260
|
+
(gateway.gateway.node.defaultChild as agentcore.CfnGateway)
|
|
261
|
+
.attrGatewayUrl,
|
|
262
|
+
gatewayArn: gateway.gateway.gatewayArn,
|
|
263
|
+
});
|
|
264
|
+
// AgentCore fetches the target gateway's tools during target creation,
|
|
265
|
+
// so the target gateway and all of its own targets must exist first.
|
|
266
|
+
// Construct dependencies resolve at synth time, covering targets added
|
|
267
|
+
// to the target gateway after this call.
|
|
268
|
+
target.node.addDependency(gateway);
|
|
269
|
+
return target;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Register another Gateway's MCP endpoint as a target of this Gateway.
|
|
274
|
+
* Prefer {@link addGateway} when the construct is in scope — it also
|
|
275
|
+
* orders this gateway's target after the target gateway's own targets,
|
|
276
|
+
* so its tools are registered before they are fetched.
|
|
277
|
+
*/
|
|
278
|
+
public addGatewayTarget(props: {
|
|
279
|
+
gatewayTargetName: string;
|
|
280
|
+
gatewayUrl: string;
|
|
281
|
+
gatewayArn: string;
|
|
282
|
+
}): agentcore.CfnGatewayTarget {
|
|
283
|
+
const target = this.addTarget(props.gatewayTargetName, props.gatewayUrl);
|
|
284
|
+
|
|
285
|
+
// Grant the gateway role invoke access to the target gateway before the
|
|
286
|
+
// target is created — AgentCore fetches the target's tools during
|
|
287
|
+
// creation, which fails if the permission is not yet in place.
|
|
288
|
+
const grant = this.gateway.role.addToPrincipalPolicy(
|
|
289
|
+
new iam.PolicyStatement({
|
|
290
|
+
actions: ['bedrock-agentcore:InvokeGateway'],
|
|
291
|
+
resources: [props.gatewayArn],
|
|
292
|
+
}),
|
|
293
|
+
);
|
|
294
|
+
if (grant.policyDependable) {
|
|
295
|
+
target.node.addDependency(grant.policyDependable);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return target;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Create a Gateway target for an MCP endpoint, with outbound calls signed
|
|
303
|
+
* using this gateway's own execution role.
|
|
304
|
+
*/
|
|
305
|
+
private addTarget(
|
|
306
|
+
gatewayTargetName: string,
|
|
307
|
+
endpoint: string,
|
|
308
|
+
): agentcore.CfnGatewayTarget {
|
|
309
|
+
// The construct id is derived from the target name so the two change
|
|
310
|
+
// together — target names are unique per gateway, and replacing a target
|
|
311
|
+
// under an unchanged name fails with AlreadyExists.
|
|
312
|
+
const target = new agentcore.CfnGatewayTarget(
|
|
313
|
+
this,
|
|
314
|
+
`Target-${gatewayTargetName}`,
|
|
315
|
+
{
|
|
316
|
+
gatewayIdentifier: this.gateway.gatewayId,
|
|
317
|
+
name: gatewayTargetName,
|
|
318
|
+
targetConfiguration: {
|
|
319
|
+
mcp: {
|
|
320
|
+
mcpServer: {
|
|
321
|
+
endpoint,
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
credentialProviderConfigurations: [
|
|
326
|
+
{
|
|
327
|
+
credentialProviderType: 'GATEWAY_IAM_ROLE',
|
|
328
|
+
credentialProvider: {
|
|
329
|
+
iamCredentialProvider: {
|
|
330
|
+
service: 'bedrock-agentcore',
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
],
|
|
335
|
+
},
|
|
336
|
+
);
|
|
337
|
+
|
|
256
338
|
// Policies referencing this target's actions (e.g.
|
|
257
339
|
// AgentCore::Action::"<targetName>___<tool>") only validate once the
|
|
258
340
|
// target has registered them, so create policies after targets.
|
|
@@ -28,6 +28,12 @@ variable "additional_iam_policy_statements" {
|
|
|
28
28
|
}))
|
|
29
29
|
default = []
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
variable "tool_dependencies" {
|
|
33
|
+
description = "Target ids whose tools must be queryable before `gateway_url` is consumable. Set this to the gateway's own target ids (e.g. from agentcore-gateway#mcp-connection) when another gateway aggregates this one: the readiness probe waits until this gateway serves those tools, since a parent gateway fetches them at target creation."
|
|
34
|
+
type = list(string)
|
|
35
|
+
default = []
|
|
36
|
+
}
|
|
31
37
|
<%_ if (cedarPolicy) { _%>
|
|
32
38
|
|
|
33
39
|
variable "policy_dependencies" {
|
|
@@ -210,6 +216,86 @@ resource "aws_bedrockagentcore_policy" "policies" {
|
|
|
210
216
|
}
|
|
211
217
|
<%_ } _%>
|
|
212
218
|
|
|
219
|
+
# A parent gateway fetches this gateway's tools when it registers it as a
|
|
220
|
+
# target, so this gateway must already serve them — its own targets register
|
|
221
|
+
# their tools asynchronously after creation. Probe `tools/list` over SigV4
|
|
222
|
+
# until the configured `tool_dependencies` are served, and route `gateway_url`
|
|
223
|
+
# through this resource so a parent gateway target waits for readiness. Only
|
|
224
|
+
# runs when this gateway is aggregated by another (empty `tool_dependencies`).
|
|
225
|
+
resource "null_resource" "gateway_ready" {
|
|
226
|
+
count = length(var.tool_dependencies) > 0 ? 1 : 0
|
|
227
|
+
|
|
228
|
+
triggers = {
|
|
229
|
+
gateway_url = aws_bedrockagentcore_gateway.this.gateway_url
|
|
230
|
+
region = local.aws_region
|
|
231
|
+
tool_dependencies = join(",", var.tool_dependencies)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
provisioner "local-exec" {
|
|
235
|
+
command = <<-EOT
|
|
236
|
+
uv run --with boto3 --with httpx --with mcp python -c "
|
|
237
|
+
import asyncio
|
|
238
|
+
import time
|
|
239
|
+
|
|
240
|
+
import boto3
|
|
241
|
+
import httpx
|
|
242
|
+
from botocore.auth import SigV4Auth
|
|
243
|
+
from botocore.awsrequest import AWSRequest
|
|
244
|
+
from mcp import ClientSession
|
|
245
|
+
from mcp.client.streamable_http import streamablehttp_client
|
|
246
|
+
|
|
247
|
+
gateway_url = '${self.triggers.gateway_url}'
|
|
248
|
+
region = '${self.triggers.region}'
|
|
249
|
+
credentials = boto3.Session(region_name=region).get_credentials()
|
|
250
|
+
signer = SigV4Auth(credentials, 'bedrock-agentcore', region)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class SigV4Auth_(httpx.Auth):
|
|
254
|
+
requires_request_body = True
|
|
255
|
+
|
|
256
|
+
def auth_flow(self, request):
|
|
257
|
+
aws_request = AWSRequest(
|
|
258
|
+
method=request.method,
|
|
259
|
+
url=str(request.url),
|
|
260
|
+
data=request.content,
|
|
261
|
+
headers=dict(request.headers),
|
|
262
|
+
)
|
|
263
|
+
signer.add_auth(aws_request)
|
|
264
|
+
request.headers.update(dict(aws_request.headers))
|
|
265
|
+
yield request
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
async def list_tools():
|
|
269
|
+
async with streamablehttp_client(
|
|
270
|
+
gateway_url, auth=SigV4Auth_(), timeout=120
|
|
271
|
+
) as (read, write, _):
|
|
272
|
+
async with ClientSession(read, write) as session:
|
|
273
|
+
await session.initialize()
|
|
274
|
+
result = await session.list_tools()
|
|
275
|
+
return [t.name for t in result.tools]
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# The built-in semantic-search tool is always present, so require at least one
|
|
279
|
+
# more tool before declaring the gateway ready to serve its aggregated targets.
|
|
280
|
+
deadline = time.time() + 5 * 60
|
|
281
|
+
while True:
|
|
282
|
+
try:
|
|
283
|
+
tools = asyncio.run(list_tools())
|
|
284
|
+
if len([t for t in tools if t != 'x_amz_bedrock_agentcore_search']) > 0:
|
|
285
|
+
break
|
|
286
|
+
last = f'gateway serves no aggregated tools yet (got {tools})'
|
|
287
|
+
except Exception as e:
|
|
288
|
+
last = str(e)
|
|
289
|
+
if time.time() >= deadline:
|
|
290
|
+
raise SystemExit(f'Gateway {gateway_url} not ready: {last}')
|
|
291
|
+
time.sleep(5)
|
|
292
|
+
|
|
293
|
+
print(f'Gateway {gateway_url} is serving tools')
|
|
294
|
+
"
|
|
295
|
+
EOT
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
213
299
|
# Add gateway URL to runtime config
|
|
214
300
|
module "add_gateway_url_to_runtime_config" {
|
|
215
301
|
source = "../../../core/runtime-config/entry"
|
|
@@ -232,8 +318,10 @@ output "gateway_arn" {
|
|
|
232
318
|
}
|
|
233
319
|
|
|
234
320
|
output "gateway_url" {
|
|
235
|
-
description = "MCP endpoint URL of the Bedrock AgentCore Gateway"
|
|
236
|
-
value
|
|
321
|
+
description = "MCP endpoint URL of the Bedrock AgentCore Gateway. When `tool_dependencies` is set, this value flows through the readiness probe so consumers (e.g. a parent gateway target) wait until the gateway serves its aggregated tools."
|
|
322
|
+
value = length(var.tool_dependencies) > 0 ? (
|
|
323
|
+
null_resource.gateway_ready[0].triggers.gateway_url
|
|
324
|
+
) : aws_bedrockagentcore_gateway.this.gateway_url
|
|
237
325
|
}
|
|
238
326
|
|
|
239
327
|
output "gateway_role_arn" {
|
|
@@ -148,6 +148,8 @@ export type ApiIntegrations<TOperation extends string, TBaseIntegration> =
|
|
|
148
148
|
* @template TDefaultIntegrationProps - Type for default integration properties
|
|
149
149
|
* @template TDefaultIntegration - Type for default integration implementation
|
|
150
150
|
* @template TPattern - The integration pattern ('shared' or 'isolated')
|
|
151
|
+
* @template TOverridden - Union of operation names that have been overridden
|
|
152
|
+
* @template TOperationOptioned - Union of operation names with per-operation options
|
|
151
153
|
*/
|
|
152
154
|
export class IntegrationBuilder<
|
|
153
155
|
TOperation extends string,
|
|
@@ -156,6 +158,8 @@ export class IntegrationBuilder<
|
|
|
156
158
|
TDefaultIntegrationProps extends object,
|
|
157
159
|
TDefaultIntegration extends TBaseIntegration,
|
|
158
160
|
TPattern extends 'shared' | 'isolated',
|
|
161
|
+
TOverridden extends string = never,
|
|
162
|
+
TOperationOptioned extends string = never,
|
|
159
163
|
> {
|
|
160
164
|
/** Options for the integration builder */
|
|
161
165
|
private options: IntegrationBuilderProps<
|
|
@@ -168,6 +172,11 @@ export class IntegrationBuilder<
|
|
|
168
172
|
/** Map of operation names to their custom integrations */
|
|
169
173
|
private integrations: Partial<TIntegrations> = {};
|
|
170
174
|
|
|
175
|
+
/** Map of default integration keys to per-operation default option overrides */
|
|
176
|
+
private perOperationOptions: Partial<
|
|
177
|
+
Record<string, Partial<TDefaultIntegrationProps>>
|
|
178
|
+
> = {};
|
|
179
|
+
|
|
171
180
|
/**
|
|
172
181
|
* Create an Integration Builder for an HTTP API with a shared pattern
|
|
173
182
|
*/
|
|
@@ -322,11 +331,16 @@ export class IntegrationBuilder<
|
|
|
322
331
|
/**
|
|
323
332
|
* Overrides default integrations with custom implementations for specific operations.
|
|
324
333
|
*
|
|
334
|
+
* Operations which have per-operation options set via withOperationOptions cannot be
|
|
335
|
+
* overridden, since these still use the default integration.
|
|
336
|
+
*
|
|
325
337
|
* @param overrides - Map of operation names to their custom integration implementations
|
|
326
338
|
* @returns The builder instance with updated type information reflecting the overrides
|
|
327
339
|
*/
|
|
328
340
|
public withOverrides<
|
|
329
|
-
TOverrideIntegrations extends Partial<
|
|
341
|
+
TOverrideIntegrations extends Partial<
|
|
342
|
+
Record<Exclude<TOperation, TOperationOptioned>, TBaseIntegration>
|
|
343
|
+
>,
|
|
330
344
|
>(overrides: TOverrideIntegrations) {
|
|
331
345
|
this.integrations = { ...this.integrations, ...overrides };
|
|
332
346
|
// Re-type to include the overridden integration types.
|
|
@@ -342,7 +356,9 @@ export class IntegrationBuilder<
|
|
|
342
356
|
MergedIntegrations,
|
|
343
357
|
TDefaultIntegrationProps,
|
|
344
358
|
TDefaultIntegration,
|
|
345
|
-
TPattern
|
|
359
|
+
TPattern,
|
|
360
|
+
TOverridden | Extract<keyof TOverrideIntegrations, string>,
|
|
361
|
+
TOperationOptioned
|
|
346
362
|
>;
|
|
347
363
|
}
|
|
348
364
|
|
|
@@ -361,6 +377,43 @@ export class IntegrationBuilder<
|
|
|
361
377
|
return this;
|
|
362
378
|
}
|
|
363
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Updates the default integration options for specific operations, without
|
|
382
|
+
* affecting the others. The given options are merged with the defaults (and
|
|
383
|
+
* any options set via withDefaultOptions) when building each default integration.
|
|
384
|
+
*
|
|
385
|
+
* Operations which have been replaced via withOverrides cannot be targeted, since
|
|
386
|
+
* they no longer use the default integration.
|
|
387
|
+
*
|
|
388
|
+
* @param options - Map of operation names to partial default integration options
|
|
389
|
+
* @returns The builder instance
|
|
390
|
+
*/
|
|
391
|
+
public withOperationOptions<
|
|
392
|
+
TOptions extends Partial<
|
|
393
|
+
Record<
|
|
394
|
+
Exclude<DefaultIntegrationKeys<TPattern, TOperation>, TOverridden>,
|
|
395
|
+
Partial<TDefaultIntegrationProps>
|
|
396
|
+
>
|
|
397
|
+
>,
|
|
398
|
+
>(options: TOptions) {
|
|
399
|
+
Object.entries(options).forEach(([op, opOptions]) => {
|
|
400
|
+
this.perOperationOptions[op] = {
|
|
401
|
+
...this.perOperationOptions[op],
|
|
402
|
+
...(opOptions as Partial<TDefaultIntegrationProps>),
|
|
403
|
+
};
|
|
404
|
+
});
|
|
405
|
+
return this as unknown as IntegrationBuilder<
|
|
406
|
+
TOperation,
|
|
407
|
+
TBaseIntegration,
|
|
408
|
+
TIntegrations,
|
|
409
|
+
TDefaultIntegrationProps,
|
|
410
|
+
TDefaultIntegration,
|
|
411
|
+
TPattern,
|
|
412
|
+
TOverridden,
|
|
413
|
+
TOperationOptioned | Extract<keyof TOptions, string>
|
|
414
|
+
>;
|
|
415
|
+
}
|
|
416
|
+
|
|
364
417
|
/**
|
|
365
418
|
* Builds and returns the complete set of integrations.
|
|
366
419
|
*
|
|
@@ -375,6 +428,10 @@ export class IntegrationBuilder<
|
|
|
375
428
|
*/
|
|
376
429
|
public build(): TIntegrations {
|
|
377
430
|
const options = this.options;
|
|
431
|
+
const buildOptionsFor = (op: string): TDefaultIntegrationProps => ({
|
|
432
|
+
...options.defaultIntegrationOptions,
|
|
433
|
+
...this.perOperationOptions[op],
|
|
434
|
+
});
|
|
378
435
|
return {
|
|
379
436
|
...Object.fromEntries(
|
|
380
437
|
options.pattern === 'shared'
|
|
@@ -383,7 +440,7 @@ export class IntegrationBuilder<
|
|
|
383
440
|
'$router',
|
|
384
441
|
options.buildDefaultIntegration(
|
|
385
442
|
'$router',
|
|
386
|
-
|
|
443
|
+
buildOptionsFor('$router'),
|
|
387
444
|
),
|
|
388
445
|
],
|
|
389
446
|
]
|
|
@@ -394,10 +451,7 @@ export class IntegrationBuilder<
|
|
|
394
451
|
)
|
|
395
452
|
.map((op) => [
|
|
396
453
|
op,
|
|
397
|
-
options.buildDefaultIntegration(
|
|
398
|
-
op,
|
|
399
|
-
options.defaultIntegrationOptions,
|
|
400
|
-
),
|
|
454
|
+
options.buildDefaultIntegration(op, buildOptionsFor(op)),
|
|
401
455
|
]),
|
|
402
456
|
),
|
|
403
457
|
...this.integrations,
|
package/src/utils/versions.d.ts
CHANGED
|
@@ -135,7 +135,7 @@ export declare const withVersions: (deps: ITsDepVersion[]) => {
|
|
|
135
135
|
*/
|
|
136
136
|
export declare const PY_VERSIONS: {
|
|
137
137
|
readonly 'ag-ui-protocol': "==0.1.19";
|
|
138
|
-
readonly 'ag-ui-strands': "==0.1
|
|
138
|
+
readonly 'ag-ui-strands': "==0.2.1";
|
|
139
139
|
readonly 'aws-lambda-powertools': "==3.29.0";
|
|
140
140
|
readonly 'aws-lambda-powertools[tracer]': "==3.29.0";
|
|
141
141
|
readonly 'aws-lambda-powertools[parser]': "==3.29.0";
|
package/src/utils/versions.js
CHANGED
|
@@ -136,7 +136,7 @@ exports.withVersions = withVersions;
|
|
|
136
136
|
*/
|
|
137
137
|
exports.PY_VERSIONS = {
|
|
138
138
|
'ag-ui-protocol': '==0.1.19',
|
|
139
|
-
'ag-ui-strands': '==0.1
|
|
139
|
+
'ag-ui-strands': '==0.2.1',
|
|
140
140
|
'aws-lambda-powertools': '==3.29.0',
|
|
141
141
|
'aws-lambda-powertools[tracer]': '==3.29.0',
|
|
142
142
|
'aws-lambda-powertools[parser]': '==3.29.0',
|