@aws/nx-plugin 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +1 -0
  2. package/generators.json +8 -0
  3. package/migrations.json +6 -1
  4. package/package.json +1 -1
  5. package/src/internal/test-matrix/generator.js +6 -1
  6. package/src/internal/test-matrix/generator.js.map +1 -1
  7. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/metadata.json +3 -0
  8. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/migration.d.ts +6 -0
  9. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/migration.js +118 -0
  10. package/src/migrations/latest/ts-agent-guardrails-terraform-version-retention/migration.js.map +1 -0
  11. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -0
  12. package/src/py/agent/guardrails/__snapshots__/generator.spec.ts.snap +3813 -0
  13. package/src/py/agent/guardrails/files/langchain/guardrail.py.template +135 -0
  14. package/src/py/agent/guardrails/files/strands/guardrail.py.template +93 -0
  15. package/src/py/agent/guardrails/generator.d.ts +10 -0
  16. package/src/py/agent/guardrails/generator.js +175 -0
  17. package/src/py/agent/guardrails/generator.js.map +1 -0
  18. package/src/py/agent/guardrails/runtime-check/run_checks.py +250 -0
  19. package/src/py/agent/guardrails/schema.d.js +6 -0
  20. package/src/py/agent/guardrails/schema.d.js.map +1 -0
  21. package/src/py/agent/guardrails/schema.d.ts +9 -0
  22. package/src/py/agent/guardrails/schema.json +25 -0
  23. package/src/sdk/py.d.ts +2 -0
  24. package/src/sdk/py.js +1 -0
  25. package/src/sdk/py.js.map +1 -1
  26. package/src/ts/agent/guardrails/__snapshots__/generator.spec.ts.snap +54 -3
  27. package/src/ts/agent/guardrails/generator.js +2 -1
  28. package/src/ts/agent/guardrails/generator.js.map +1 -1
  29. package/src/utils/guardrail-constructs/files/terraform/app/guardrails/__nameKebabCase__/__nameKebabCase__-guardrail.tf.template +18 -1
  30. package/src/utils/guardrail-constructs/guardrail-constructs.d.ts +5 -0
  31. package/src/utils/guardrail-constructs/guardrail-constructs.js +8 -0
  32. package/src/utils/guardrail-constructs/guardrail-constructs.js.map +1 -1
  33. package/src/utils/guardrail-constructs/guardrail-wiring.d.ts +7 -0
  34. package/src/utils/guardrail-constructs/guardrail-wiring.js +6 -5
  35. package/src/utils/guardrail-constructs/guardrail-wiring.js.map +1 -1
  36. package/src/utils/test/fake-aws/fake_aws.py +205 -0
  37. package/src/utils/test/python-dependencies.d.ts +6 -0
  38. package/src/utils/test/python-dependencies.js +19 -0
  39. package/src/utils/test/python-dependencies.js.map +1 -1
  40. package/src/utils/test/warm-python-cache.js +5 -1
  41. package/src/utils/test/warm-python-cache.js.map +1 -1
  42. /package/src/{ts/agent/guardrails/files/agent → utils/guardrail-constructs/files/policy}/guardrail.json.template +0 -0
@@ -0,0 +1,250 @@
1
+ #
2
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ #
5
+ """Run a generated, guarded Python agent against fake_aws.py and report what
6
+ the real SDK sent. Used by guardrail-runtime.spec.ts.
7
+
8
+ Usage: python run_checks.py <project root> <connection root> <fake_aws.py> <framework>
9
+ <agent package> <agent-connection module> [<scenario>]
10
+
11
+ <project root> holds the agent project's module and pyproject.toml, and
12
+ <connection root> the agent-connection module, as in a workspace.
13
+ Without a scenario, every scenario runs in a fresh interpreter (so the
14
+ guardrail cache and warn-once state start clean), then the static checks, and
15
+ one line "RESULTS <json>" maps each name to its result.
16
+ """
17
+
18
+ import asyncio
19
+ import importlib
20
+ import importlib.util
21
+ import json
22
+ import logging
23
+ import os
24
+ import shutil
25
+ import subprocess
26
+ import sys
27
+ import tempfile
28
+ import time
29
+ from contextlib import contextmanager
30
+ from typing import Any
31
+
32
+ ROOT, CONNECTION_ROOT, FAKE_AWS, FRAMEWORK, AGENT_PACKAGE, CONNECTION_MODULE = sys.argv[1:7]
33
+
34
+ ENTRY = {"guardrailId": "grtest", "guardrailVersion": "1"}
35
+ # fake_aws.py blocks a guarded request whose checked text contains "stocks".
36
+ BLOCKED_PROMPT = "Which stocks should I buy this year?"
37
+
38
+ # scenario: (LOCAL_DEV, RUNTIME_CONFIG_APP_ID, guardrail entry or None, number of calls)
39
+ SCENARIOS: dict[str, tuple[bool, str | None, dict[str, str] | None, int]] = {
40
+ "guarded": (False, "fake-app", ENTRY, 1),
41
+ "missing": (False, "fake-app", None, 1),
42
+ "no-app-id": (False, None, ENTRY, 1),
43
+ "local-dev": (True, None, ENTRY, 2),
44
+ "local-dev-broken": (True, "broken", ENTRY, 2),
45
+ "local-dev-guarded": (True, "fake-app", ENTRY, 1),
46
+ "draft": (False, "fake-app", {**ENTRY, "guardrailVersion": "DRAFT"}, 1),
47
+ "draft-local": (True, "fake-app", {**ENTRY, "guardrailVersion": "DRAFT"}, 1),
48
+ "zero": (False, "fake-app", {**ENTRY, "guardrailVersion": "0"}, 1),
49
+ "zero-local": (True, "fake-app", {**ENTRY, "guardrailVersion": "0"}, 1),
50
+ "reread": (False, "fake-app", ENTRY, 0),
51
+ "concurrent": (False, "fake-app", ENTRY, 0),
52
+ "blocked-session": (False, "fake-app", ENTRY, 0),
53
+ "blocked-session-stream": (False, "fake-app", ENTRY, 0),
54
+ }
55
+
56
+
57
+ def write_config(path: str, entry: dict[str, str] | None, class_name: str) -> None:
58
+ data: dict[str, Any] = {"agentRuntimes": {}}
59
+ if entry is not None:
60
+ data["guardrails"] = {class_name: entry}
61
+ with open(path, "w") as f:
62
+ json.dump(data, f)
63
+
64
+
65
+ def read_log(path: str) -> list[dict[str, Any]]:
66
+ if not os.path.exists(path):
67
+ return []
68
+ with open(path) as f:
69
+ return [json.loads(line) for line in f if line.strip()]
70
+
71
+
72
+ class WarningRecorder(logging.Handler):
73
+ def __init__(self) -> None:
74
+ super().__init__(logging.WARNING)
75
+ self.messages: list[str] = []
76
+
77
+ def emit(self, record: logging.LogRecord) -> None:
78
+ if record.name.endswith(".guardrail"):
79
+ self.messages.append(record.getMessage())
80
+
81
+
82
+ def run_scenario(name: str) -> dict[str, Any]:
83
+ local_dev, app_id, entry, calls = SCENARIOS[name]
84
+ work = tempfile.mkdtemp(prefix=f"{name}-")
85
+ config_file, log_file = os.path.join(work, "config.json"), os.path.join(work, "requests.log")
86
+ # The vended local session storage is relative to the project root, two levels down.
87
+ cwd = os.path.join(work, "packages", "project")
88
+ os.makedirs(cwd)
89
+ os.chdir(cwd)
90
+
91
+ spec = importlib.util.spec_from_file_location("fake_aws", FAKE_AWS)
92
+ assert spec and spec.loader
93
+ fake_aws = importlib.util.module_from_spec(spec)
94
+ spec.loader.exec_module(fake_aws)
95
+ _server, port = fake_aws.start_server(config_file, log_file)
96
+ os.environ["AWS_ENDPOINT_URL_APPCONFIGDATA"] = f"http://127.0.0.1:{port}"
97
+ os.environ["AWS_ENDPOINT_URL_BEDROCK_RUNTIME"] = f"http://127.0.0.1:{port}"
98
+ os.environ.pop("LOCAL_DEV", None)
99
+ os.environ.pop("RUNTIME_CONFIG_APP_ID", None)
100
+ if local_dev:
101
+ os.environ["LOCAL_DEV"] = "true"
102
+ if app_id:
103
+ os.environ["RUNTIME_CONFIG_APP_ID"] = app_id
104
+
105
+ recorder = WarningRecorder()
106
+ logging.getLogger().addHandler(recorder)
107
+
108
+ sys.path[:0] = [ROOT, CONNECTION_ROOT]
109
+ agent_module = importlib.import_module(f"{AGENT_PACKAGE}.agent")
110
+ guardrail_module = importlib.import_module(f"{AGENT_PACKAGE}.guardrail")
111
+ class_name = guardrail_module.RUNTIME_CONFIG_KEY.split(".")[-1]
112
+ write_config(config_file, entry, class_name)
113
+
114
+ result: dict[str, Any] = {"calls": []}
115
+
116
+ def snapshot() -> dict[str, Any]:
117
+ log = read_log(log_file)
118
+ return {
119
+ "models": [r for r in log if "modelId" in r],
120
+ "appConfigCalls": len([r for r in log if "modelId" not in r]),
121
+ }
122
+
123
+ async def scenario() -> None:
124
+ if FRAMEWORK == "strands":
125
+ connection = importlib.import_module(CONNECTION_MODULE)
126
+
127
+ @contextmanager
128
+ def agent_scope():
129
+ with connection.session_id_context("s1"), agent_module.get_agent() as agent:
130
+ yield agent
131
+
132
+ async def call(agent: Any, prompt: str = "2+2?") -> None:
133
+ await agent.invoke_async(prompt)
134
+
135
+ if name == "concurrent":
136
+ from strands import Agent
137
+
138
+ shared = guardrail_module.get_guardrailed_model()
139
+ agents = [Agent(model=shared, callback_handler=None) for _ in range(10)]
140
+ await asyncio.gather(*[a.invoke_async("2+2?") for a in agents])
141
+ return
142
+ with agent_scope() as agent:
143
+ await run_calls(agent, call)
144
+ else:
145
+ graph = agent_module.get_agent()
146
+ counter = iter(range(1000))
147
+
148
+ async def call(agent: Any, prompt: str | None = None) -> None:
149
+ # A call with a prompt continues one session; without, each call is a new session.
150
+ if name == "blocked-session-stream":
151
+ await stream(agent, prompt)
152
+ return
153
+ thread = {"configurable": {"thread_id": "session" if prompt else f"t{next(counter)}"}}
154
+ await agent.ainvoke({"messages": [{"role": "user", "content": prompt or "2+2?"}]}, thread)
155
+
156
+ async def stream(agent: Any, prompt: str | None = None) -> None:
157
+ thread = {"configurable": {"thread_id": "session" if prompt else f"t{next(counter)}"}}
158
+ async for _ in agent.astream(
159
+ {"messages": [{"role": "user", "content": prompt or "2+2?"}]}, thread, stream_mode="messages"
160
+ ):
161
+ pass
162
+
163
+ if name == "concurrent":
164
+ await asyncio.gather(*[call(graph) for _ in range(10)])
165
+ return
166
+ await run_calls(graph, call)
167
+ if name == "guarded":
168
+ await stream(graph)
169
+ result["streamed"] = snapshot()["models"][-1:]
170
+
171
+ async def run_calls(agent: Any, call: Any) -> None:
172
+ if name.startswith("blocked-session"):
173
+ # A blocked message, then a normal one, in the same session.
174
+ for prompt in (BLOCKED_PROMPT, "2+2?"):
175
+ await call(agent, prompt)
176
+ result["calls"].append(snapshot())
177
+ return
178
+ if name == "reread":
179
+ await call(agent)
180
+ result["calls"].append(snapshot())
181
+ write_config(config_file, {**ENTRY, "guardrailVersion": "2"}, class_name)
182
+ await call(agent)
183
+ result["calls"].append(snapshot())
184
+ time.sleep(5.5)
185
+ await call(agent)
186
+ result["calls"].append(snapshot())
187
+ return
188
+ for _ in range(calls):
189
+ await call(agent)
190
+ result["calls"].append(snapshot())
191
+
192
+ try:
193
+ asyncio.run(scenario())
194
+ except Exception as e: # noqa: BLE001 - reported to the spec
195
+ result["error"] = {"type": type(e).__name__, "message": str(e)}
196
+ result.update(snapshot())
197
+ result["warnings"] = recorder.messages
198
+ shutil.rmtree(work, ignore_errors=True)
199
+ return result
200
+
201
+
202
+ def run_static() -> dict[str, Any]:
203
+ package_dir = os.path.join(ROOT, *AGENT_PACKAGE.split("."))
204
+ files = [os.path.join(package_dir, f) for f in ("guardrail.py", "agent.py")]
205
+ # uv's --with environment layers several site-packages directories, which
206
+ # ty does not discover from the interpreter alone.
207
+ search_paths = [CONNECTION_ROOT, *(p for p in sys.path if p.endswith("site-packages"))]
208
+ commands = {
209
+ "ty": [
210
+ "ty",
211
+ "check",
212
+ "--python",
213
+ sys.executable,
214
+ *(arg for path in search_paths for arg in ("--extra-search-path", path)),
215
+ "--no-progress",
216
+ *files,
217
+ ],
218
+ "ruffFormat": ["ruff", "format", "--check", *files],
219
+ "ruffCheck": ["ruff", "check", "--select", "E,F,UP,B,SIM,I", *files],
220
+ }
221
+ results = {}
222
+ for key, command in commands.items():
223
+ done = subprocess.run(command, cwd=ROOT, capture_output=True, text=True)
224
+ results[key] = {"code": done.returncode, "output": done.stdout + done.stderr}
225
+ return results
226
+
227
+
228
+ if __name__ == "__main__":
229
+ if len(sys.argv) > 7:
230
+ print("\nRESULT " + json.dumps(run_scenario(sys.argv[7])), flush=True)
231
+ # A failed LangChain call in local dev leaves the SQLite checkpointer's
232
+ # non-daemon thread running, which would keep the interpreter alive.
233
+ os._exit(0)
234
+ else:
235
+ results: dict[str, Any] = {}
236
+ for scenario_name in SCENARIOS:
237
+ done = subprocess.run(
238
+ [sys.executable, __file__, *sys.argv[1:7], scenario_name],
239
+ capture_output=True,
240
+ text=True,
241
+ timeout=180,
242
+ )
243
+ lines = [line for line in done.stdout.splitlines() if line.startswith("RESULT ")]
244
+ results[scenario_name] = (
245
+ json.loads(lines[-1][len("RESULT ") :])
246
+ if lines
247
+ else {"crashed": done.returncode, "stdout": done.stdout[-4000:], "stderr": done.stderr[-4000:]}
248
+ )
249
+ results["static"] = run_static()
250
+ print("RESULTS " + json.dumps(results), flush=True)
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ export { };
5
+
6
+ //# sourceMappingURL=schema.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/py/agent/guardrails/schema.d.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport interface PyAgentGuardrailsGeneratorSchema {\n project: string;\n agent?: string;\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GAED,WAGC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ export interface PyAgentGuardrailsGeneratorSchema {
7
+ project: string;
8
+ agent?: string;
9
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "py#agent#guardrails",
4
+ "title": "py#agent#guardrails",
5
+ "x-label": "Agent Guardrails",
6
+ "description": "Add an Amazon Bedrock Guardrail to a Python Agent",
7
+ "type": "object",
8
+ "properties": {
9
+ "project": {
10
+ "type": "string",
11
+ "description": "The project containing the Python Agent",
12
+ "$default": {
13
+ "$source": "argv",
14
+ "index": 0
15
+ },
16
+ "x-prompt": "Select the project containing the Python Agent to guard",
17
+ "x-dropdown": "projects"
18
+ },
19
+ "agent": {
20
+ "type": "string",
21
+ "description": "The name of the Agent component to guard. Required when the project contains more than one Python Agent."
22
+ }
23
+ },
24
+ "required": ["project"]
25
+ }
package/src/sdk/py.d.ts CHANGED
@@ -3,6 +3,8 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  export { pyAgentGenerator } from '../py/agent/generator.js';
6
+ export { pyAgentGuardrailsGenerator } from '../py/agent/guardrails/generator.js';
7
+ export type { PyAgentGuardrailsGeneratorSchema } from '../py/agent/guardrails/schema';
6
8
  export type { PyAgentGeneratorSchema } from '../py/agent/schema';
7
9
  export { pyApiGenerator } from '../py/api/generator.js';
8
10
  export type { PyApiGeneratorSchema } from '../py/api/schema';
package/src/sdk/py.js CHANGED
@@ -2,6 +2,7 @@
2
2
  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */ export { pyAgentGenerator } from "../py/agent/generator.js";
5
+ export { pyAgentGuardrailsGenerator } from "../py/agent/guardrails/generator.js";
5
6
  export { pyApiGenerator } from "../py/api/generator.js";
6
7
  export { pyDynamoDBGenerator } from "../py/dynamodb/generator.js";
7
8
  export { pyLambdaFunctionGenerator } from "../py/lambda-function/generator.js";
package/src/sdk/py.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/sdk/py.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport { pyAgentGenerator } from '../py/agent/generator.js';\nexport type { PyAgentGeneratorSchema } from '../py/agent/schema';\n\nexport { pyApiGenerator } from '../py/api/generator.js';\nexport type { PyApiGeneratorSchema } from '../py/api/schema';\n\nexport { pyDynamoDBGenerator } from '../py/dynamodb/generator.js';\nexport type { PyDynamoDBGeneratorSchema } from '../py/dynamodb/schema';\n\nexport { pyLambdaFunctionGenerator } from '../py/lambda-function/generator.js';\nexport type { PyLambdaFunctionGeneratorSchema } from '../py/lambda-function/schema';\n\nexport { pyMcpServerGenerator } from '../py/mcp-server/generator.js';\nexport type { PyMcpServerGeneratorSchema } from '../py/mcp-server/schema';\nexport { pyProjectGenerator } from '../py/project/generator.js';\nexport type { PyProjectGeneratorSchema } from '../py/project/schema';\n\nexport { pyRdbGenerator } from '../py/rdb/generator.js';\nexport type { PyRdbGeneratorSchema } from '../py/rdb/schema';\n"],"names":["pyAgentGenerator","pyApiGenerator","pyDynamoDBGenerator","pyLambdaFunctionGenerator","pyMcpServerGenerator","pyProjectGenerator","pyRdbGenerator"],"mappings":"AAAA;;;CAGC,GAED,SAASA,gBAAgB,QAAQ,2BAA2B;AAG5D,SAASC,cAAc,QAAQ,yBAAyB;AAGxD,SAASC,mBAAmB,QAAQ,8BAA8B;AAGlE,SAASC,yBAAyB,QAAQ,qCAAqC;AAG/E,SAASC,oBAAoB,QAAQ,gCAAgC;AAErE,SAASC,kBAAkB,QAAQ,6BAA6B;AAGhE,SAASC,cAAc,QAAQ,yBAAyB"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/sdk/py.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport { pyAgentGenerator } from '../py/agent/generator.js';\nexport { pyAgentGuardrailsGenerator } from '../py/agent/guardrails/generator.js';\nexport type { PyAgentGuardrailsGeneratorSchema } from '../py/agent/guardrails/schema';\nexport type { PyAgentGeneratorSchema } from '../py/agent/schema';\n\nexport { pyApiGenerator } from '../py/api/generator.js';\nexport type { PyApiGeneratorSchema } from '../py/api/schema';\n\nexport { pyDynamoDBGenerator } from '../py/dynamodb/generator.js';\nexport type { PyDynamoDBGeneratorSchema } from '../py/dynamodb/schema';\n\nexport { pyLambdaFunctionGenerator } from '../py/lambda-function/generator.js';\nexport type { PyLambdaFunctionGeneratorSchema } from '../py/lambda-function/schema';\n\nexport { pyMcpServerGenerator } from '../py/mcp-server/generator.js';\nexport type { PyMcpServerGeneratorSchema } from '../py/mcp-server/schema';\nexport { pyProjectGenerator } from '../py/project/generator.js';\nexport type { PyProjectGeneratorSchema } from '../py/project/schema';\n\nexport { pyRdbGenerator } from '../py/rdb/generator.js';\nexport type { PyRdbGeneratorSchema } from '../py/rdb/schema';\n"],"names":["pyAgentGenerator","pyAgentGuardrailsGenerator","pyApiGenerator","pyDynamoDBGenerator","pyLambdaFunctionGenerator","pyMcpServerGenerator","pyProjectGenerator","pyRdbGenerator"],"mappings":"AAAA;;;CAGC,GAED,SAASA,gBAAgB,QAAQ,2BAA2B;AAC5D,SAASC,0BAA0B,QAAQ,sCAAsC;AAIjF,SAASC,cAAc,QAAQ,yBAAyB;AAGxD,SAASC,mBAAmB,QAAQ,8BAA8B;AAGlE,SAASC,yBAAyB,QAAQ,qCAAqC;AAG/E,SAASC,oBAAoB,QAAQ,gCAAgC;AAErE,SAASC,kBAAkB,QAAQ,6BAA6B;AAGhE,SAASC,cAAc,QAAQ,yBAAyB"}
@@ -445,6 +445,10 @@ exports[`ts#agent#guardrails generator > protocol a2a > should generate the guar
445
445
  source = "hashicorp/random"
446
446
  version = "3.9.1"
447
447
  }
448
+ time = {
449
+ source = "hashicorp/time"
450
+ version = "0.14.2"
451
+ }
448
452
  }
449
453
  }
450
454
 
@@ -509,12 +513,25 @@ resource "aws_bedrock_guardrail_version" "this" {
509
513
  }
510
514
  }
511
515
 
516
+ resource "time_sleep" "version_retention" {
517
+ destroy_duration = "15s"
518
+
519
+ triggers = {
520
+ guardrail_id = aws_bedrock_guardrail.this.guardrail_id
521
+ guardrail_version = aws_bedrock_guardrail_version.this.version
522
+ }
523
+
524
+ lifecycle {
525
+ create_before_destroy = true
526
+ }
527
+ }
528
+
512
529
  module "add_guardrail_to_runtime_config" {
513
530
  source = "../../../core/runtime-config/entry"
514
531
 
515
532
  namespace = "agentcore"
516
533
  key = "guardrails"
517
- value = { "TestProjectAgent" = { guardrailId = aws_bedrock_guardrail.this.guardrail_id, guardrailVersion = aws_bedrock_guardrail_version.this.version } }
534
+ value = { "TestProjectAgent" = { guardrailId = time_sleep.version_retention.triggers.guardrail_id, guardrailVersion = time_sleep.version_retention.triggers.guardrail_version } }
518
535
  }
519
536
 
520
537
  output "guardrail_id" {
@@ -977,6 +994,10 @@ exports[`ts#agent#guardrails generator > protocol ag-ui > should generate the gu
977
994
  source = "hashicorp/random"
978
995
  version = "3.9.1"
979
996
  }
997
+ time = {
998
+ source = "hashicorp/time"
999
+ version = "0.14.2"
1000
+ }
980
1001
  }
981
1002
  }
982
1003
 
@@ -1041,12 +1062,25 @@ resource "aws_bedrock_guardrail_version" "this" {
1041
1062
  }
1042
1063
  }
1043
1064
 
1065
+ resource "time_sleep" "version_retention" {
1066
+ destroy_duration = "15s"
1067
+
1068
+ triggers = {
1069
+ guardrail_id = aws_bedrock_guardrail.this.guardrail_id
1070
+ guardrail_version = aws_bedrock_guardrail_version.this.version
1071
+ }
1072
+
1073
+ lifecycle {
1074
+ create_before_destroy = true
1075
+ }
1076
+ }
1077
+
1044
1078
  module "add_guardrail_to_runtime_config" {
1045
1079
  source = "../../../core/runtime-config/entry"
1046
1080
 
1047
1081
  namespace = "agentcore"
1048
1082
  key = "guardrails"
1049
- value = { "TestProjectAgent" = { guardrailId = aws_bedrock_guardrail.this.guardrail_id, guardrailVersion = aws_bedrock_guardrail_version.this.version } }
1083
+ value = { "TestProjectAgent" = { guardrailId = time_sleep.version_retention.triggers.guardrail_id, guardrailVersion = time_sleep.version_retention.triggers.guardrail_version } }
1050
1084
  }
1051
1085
 
1052
1086
  output "guardrail_id" {
@@ -1523,6 +1557,10 @@ exports[`ts#agent#guardrails generator > protocol http > should generate the gua
1523
1557
  source = "hashicorp/random"
1524
1558
  version = "3.9.1"
1525
1559
  }
1560
+ time = {
1561
+ source = "hashicorp/time"
1562
+ version = "0.14.2"
1563
+ }
1526
1564
  }
1527
1565
  }
1528
1566
 
@@ -1587,12 +1625,25 @@ resource "aws_bedrock_guardrail_version" "this" {
1587
1625
  }
1588
1626
  }
1589
1627
 
1628
+ resource "time_sleep" "version_retention" {
1629
+ destroy_duration = "15s"
1630
+
1631
+ triggers = {
1632
+ guardrail_id = aws_bedrock_guardrail.this.guardrail_id
1633
+ guardrail_version = aws_bedrock_guardrail_version.this.version
1634
+ }
1635
+
1636
+ lifecycle {
1637
+ create_before_destroy = true
1638
+ }
1639
+ }
1640
+
1590
1641
  module "add_guardrail_to_runtime_config" {
1591
1642
  source = "../../../core/runtime-config/entry"
1592
1643
 
1593
1644
  namespace = "agentcore"
1594
1645
  key = "guardrails"
1595
- value = { "TestProjectAgent" = { guardrailId = aws_bedrock_guardrail.this.guardrail_id, guardrailVersion = aws_bedrock_guardrail_version.this.version } }
1646
+ value = { "TestProjectAgent" = { guardrailId = time_sleep.version_retention.triggers.guardrail_id, guardrailVersion = time_sleep.version_retention.triggers.guardrail_version } }
1596
1647
  }
1597
1648
 
1598
1649
  output "guardrail_id" {
@@ -4,7 +4,7 @@
4
4
  */ import { generateFiles, joinPathFragments, logger, OverwriteStrategy } from "@nx/devkit";
5
5
  import { addDestructuredImport, applyGritQL, matchGritQL } from "../../../utils/ast.js";
6
6
  import { formatFilesInSubtree } from "../../../utils/format.js";
7
- import { addGuardrailInfra } from "../../../utils/guardrail-constructs/guardrail-constructs.js";
7
+ import { addGuardrailInfra, addGuardrailPolicy } from "../../../utils/guardrail-constructs/guardrail-constructs.js";
8
8
  import { guardrailWiringMessage } from "../../../utils/guardrail-constructs/guardrail-wiring.js";
9
9
  import { addGeneratorMetricsIfApplicable } from "../../../utils/metrics.js";
10
10
  import { esmVars, isEsmWorkspace } from "../../../utils/module-format.js";
@@ -74,6 +74,7 @@ export const tsAgentGuardrailsGenerator = async (tree, options)=>{
74
74
  }, {
75
75
  overwriteStrategy: OverwriteStrategy.KeepExisting
76
76
  });
77
+ addGuardrailPolicy(tree, agentDir);
77
78
  await addGuardrailedModelToAgent(tree, joinPathFragments(agentDir, 'agent.ts'));
78
79
  const iac = agent.iac;
79
80
  let wiringMessage;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/ts/agent/guardrails/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n logger,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport {\n addDestructuredImport,\n applyGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { addGuardrailInfra } from '../../../utils/guardrail-constructs/guardrail-constructs.js';\nimport { guardrailWiringMessage } from '../../../utils/guardrail-constructs/guardrail-wiring.js';\nimport type { Iac } from '../../../utils/iac.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { esmVars, isEsmWorkspace } from '../../../utils/module-format.js';\nimport { kebabCase, toClassName } from '../../../utils/names.js';\nimport { getNpmScope } from '../../../utils/npm-scope.js';\nimport {\n addComponentGeneratorMetadata,\n type ComponentMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { TS_AGENT_GENERATOR_INFO } from '../generator.js';\nimport type { TsAgentGuardrailsGeneratorSchema } from './schema';\nimport { addGuardrailPolicySynthInputs } from './synth-inputs.js';\n\nexport const TS_AGENT_GUARDRAILS_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\n/**\n * Find the `ts#agent` component to guard, by name when given, otherwise the\n * project's only one.\n */\nconst resolveAgent = (\n projectName: string,\n components: ComponentMetadata[],\n agent?: string,\n): ComponentMetadata => {\n const agents = components.filter(\n (c) => c.generator === TS_AGENT_GENERATOR_INFO.id,\n );\n const available = agents.map((c) => c.name).join(', ') || 'none';\n if (agent) {\n const match = agents.find((c) => c.name === agent);\n if (!match) {\n throw new Error(\n `No TypeScript Agent named ${agent} in project ${projectName}. Available agents: ${available}`,\n );\n }\n return match;\n }\n if (agents.length !== 1) {\n throw new Error(\n agents.length === 0\n ? `Project ${projectName} has no TypeScript Agent. Add one with the ts#agent generator first.`\n : `Project ${projectName} has more than one TypeScript Agent. Specify which to guard with --agent. Available agents: ${available}`,\n );\n }\n return agents[0];\n};\n\n/**\n * Add `model: getGuardrailedModel()` to the `new Agent({...})` call in\n * agent.ts. An agent that already sets its own model is left unchanged, and\n * the lines to add by hand are logged instead.\n */\nconst addGuardrailedModelToAgent = async (\n tree: Tree,\n agentFile: string,\n): Promise<void> => {\n const guardrailImport = isEsmWorkspace(tree)\n ? './guardrail.js'\n : './guardrail';\n\n if (tree.exists(agentFile)) {\n if (await matchGritQL(tree, agentFile, '`getGuardrailedModel()`')) {\n return;\n }\n if (\n await applyGritQL(\n tree,\n agentFile,\n '`new Agent({ $props })` => `new Agent({ model: getGuardrailedModel(), $props })` where { $props <: not some or { `model: $_`, `model` } }',\n )\n ) {\n await addDestructuredImport(\n tree,\n agentFile,\n ['getGuardrailedModel'],\n './guardrail.js',\n );\n return;\n }\n }\n\n logger.warn(\n `Could not add the guardrail to ${agentFile}, because ${tree.exists(agentFile) ? 'its new Agent({...}) call already sets a model or is not an inline object' : 'the file does not exist'}. Set the model of your Agent to the guardrailed model by hand:\n\n model: getGuardrailedModel(),\n\nand import it:\n\n import { getGuardrailedModel } from '${guardrailImport}';`,\n );\n};\n\nexport const tsAgentGuardrailsGenerator = async (\n tree: Tree,\n options: TsAgentGuardrailsGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n const agent = resolveAgent(\n project.name,\n (project.metadata as any)?.components ?? [],\n options.agent,\n );\n\n const agentTargetPrefix = agent.name ?? 'agent';\n const agentNameClassName = agent.rc ?? toClassName(agentTargetPrefix);\n const nameKebabCase = kebabCase(agentNameClassName);\n const agentPath = agent.path ?? joinPathFragments('src', agentTargetPrefix);\n const agentDir = joinPathFragments(project.root, agentPath);\n\n // The policy is the user's to edit, so a re-run never touches these files.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'agent'),\n agentDir,\n {\n ...esmVars(tree),\n agentConnectionImport: `@${getNpmScope(tree)}/agent-connection`,\n agentNameClassName,\n nameKebabCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n await addGuardrailedModelToAgent(\n tree,\n joinPathFragments(agentDir, 'agent.ts'),\n );\n\n const iac = agent.iac as Iac | undefined;\n let wiringMessage: string | undefined;\n if (iac) {\n const policyPath = joinPathFragments(agentDir, 'guardrail.json');\n await addGuardrailInfra(tree, {\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n policyPath,\n });\n if (iac === 'cdk') {\n for (const message of addGuardrailPolicySynthInputs(tree, [policyPath])) {\n logger.warn(message);\n }\n }\n wiringMessage = guardrailWiringMessage({\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n npmScope: getNpmScope(tree),\n });\n } else {\n logger.warn(\n `Agent ${agentTargetPrefix} in project ${project.name} has no infrastructure, so no guardrail infrastructure was generated. Create the guardrail yourself and write its ID and version to runtime config at agentcore.guardrails.${agentNameClassName} as { guardrailId, guardrailVersion }.`,\n );\n }\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n agentPath,\n agentTargetPrefix,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n\n // Printed from the callback so it appears after Nx lists the changed\n // files, on every run, since the generator cannot tell whether the stack is\n // already wired.\n return () => {\n if (wiringMessage) {\n logger.info(wiringMessage);\n }\n };\n};\n\nexport default tsAgentGuardrailsGenerator;\n"],"names":["generateFiles","joinPathFragments","logger","OverwriteStrategy","addDestructuredImport","applyGritQL","matchGritQL","formatFilesInSubtree","addGuardrailInfra","guardrailWiringMessage","addGeneratorMetricsIfApplicable","esmVars","isEsmWorkspace","kebabCase","toClassName","getNpmScope","addComponentGeneratorMetadata","getGeneratorInfo","readProjectConfigurationUnqualified","TS_AGENT_GENERATOR_INFO","addGuardrailPolicySynthInputs","TS_AGENT_GUARDRAILS_GENERATOR_INFO","filename","resolveAgent","projectName","components","agent","agents","filter","c","generator","id","available","map","name","join","match","find","Error","length","addGuardrailedModelToAgent","tree","agentFile","guardrailImport","exists","warn","tsAgentGuardrailsGenerator","options","project","metadata","agentTargetPrefix","agentNameClassName","rc","nameKebabCase","agentPath","path","agentDir","root","dirname","agentConnectionImport","overwriteStrategy","KeepExisting","iac","wiringMessage","policyPath","nameClassName","message","npmScope","info"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/ts/agent/guardrails/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n logger,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport {\n addDestructuredImport,\n applyGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n addGuardrailInfra,\n addGuardrailPolicy,\n} from '../../../utils/guardrail-constructs/guardrail-constructs.js';\nimport { guardrailWiringMessage } from '../../../utils/guardrail-constructs/guardrail-wiring.js';\nimport type { Iac } from '../../../utils/iac.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { esmVars, isEsmWorkspace } from '../../../utils/module-format.js';\nimport { kebabCase, toClassName } from '../../../utils/names.js';\nimport { getNpmScope } from '../../../utils/npm-scope.js';\nimport {\n addComponentGeneratorMetadata,\n type ComponentMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { TS_AGENT_GENERATOR_INFO } from '../generator.js';\nimport type { TsAgentGuardrailsGeneratorSchema } from './schema';\nimport { addGuardrailPolicySynthInputs } from './synth-inputs.js';\n\nexport const TS_AGENT_GUARDRAILS_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\n/**\n * Find the `ts#agent` component to guard, by name when given, otherwise the\n * project's only one.\n */\nconst resolveAgent = (\n projectName: string,\n components: ComponentMetadata[],\n agent?: string,\n): ComponentMetadata => {\n const agents = components.filter(\n (c) => c.generator === TS_AGENT_GENERATOR_INFO.id,\n );\n const available = agents.map((c) => c.name).join(', ') || 'none';\n if (agent) {\n const match = agents.find((c) => c.name === agent);\n if (!match) {\n throw new Error(\n `No TypeScript Agent named ${agent} in project ${projectName}. Available agents: ${available}`,\n );\n }\n return match;\n }\n if (agents.length !== 1) {\n throw new Error(\n agents.length === 0\n ? `Project ${projectName} has no TypeScript Agent. Add one with the ts#agent generator first.`\n : `Project ${projectName} has more than one TypeScript Agent. Specify which to guard with --agent. Available agents: ${available}`,\n );\n }\n return agents[0];\n};\n\n/**\n * Add `model: getGuardrailedModel()` to the `new Agent({...})` call in\n * agent.ts. An agent that already sets its own model is left unchanged, and\n * the lines to add by hand are logged instead.\n */\nconst addGuardrailedModelToAgent = async (\n tree: Tree,\n agentFile: string,\n): Promise<void> => {\n const guardrailImport = isEsmWorkspace(tree)\n ? './guardrail.js'\n : './guardrail';\n\n if (tree.exists(agentFile)) {\n if (await matchGritQL(tree, agentFile, '`getGuardrailedModel()`')) {\n return;\n }\n if (\n await applyGritQL(\n tree,\n agentFile,\n '`new Agent({ $props })` => `new Agent({ model: getGuardrailedModel(), $props })` where { $props <: not some or { `model: $_`, `model` } }',\n )\n ) {\n await addDestructuredImport(\n tree,\n agentFile,\n ['getGuardrailedModel'],\n './guardrail.js',\n );\n return;\n }\n }\n\n logger.warn(\n `Could not add the guardrail to ${agentFile}, because ${tree.exists(agentFile) ? 'its new Agent({...}) call already sets a model or is not an inline object' : 'the file does not exist'}. Set the model of your Agent to the guardrailed model by hand:\n\n model: getGuardrailedModel(),\n\nand import it:\n\n import { getGuardrailedModel } from '${guardrailImport}';`,\n );\n};\n\nexport const tsAgentGuardrailsGenerator = async (\n tree: Tree,\n options: TsAgentGuardrailsGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n const agent = resolveAgent(\n project.name,\n (project.metadata as any)?.components ?? [],\n options.agent,\n );\n\n const agentTargetPrefix = agent.name ?? 'agent';\n const agentNameClassName = agent.rc ?? toClassName(agentTargetPrefix);\n const nameKebabCase = kebabCase(agentNameClassName);\n const agentPath = agent.path ?? joinPathFragments('src', agentTargetPrefix);\n const agentDir = joinPathFragments(project.root, agentPath);\n\n // The policy is the user's to edit, so a re-run never touches these files.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'agent'),\n agentDir,\n {\n ...esmVars(tree),\n agentConnectionImport: `@${getNpmScope(tree)}/agent-connection`,\n agentNameClassName,\n nameKebabCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n addGuardrailPolicy(tree, agentDir);\n\n await addGuardrailedModelToAgent(\n tree,\n joinPathFragments(agentDir, 'agent.ts'),\n );\n\n const iac = agent.iac as Iac | undefined;\n let wiringMessage: string | undefined;\n if (iac) {\n const policyPath = joinPathFragments(agentDir, 'guardrail.json');\n await addGuardrailInfra(tree, {\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n policyPath,\n });\n if (iac === 'cdk') {\n for (const message of addGuardrailPolicySynthInputs(tree, [policyPath])) {\n logger.warn(message);\n }\n }\n wiringMessage = guardrailWiringMessage({\n iac,\n nameClassName: agentNameClassName,\n nameKebabCase,\n npmScope: getNpmScope(tree),\n });\n } else {\n logger.warn(\n `Agent ${agentTargetPrefix} in project ${project.name} has no infrastructure, so no guardrail infrastructure was generated. Create the guardrail yourself and write its ID and version to runtime config at agentcore.guardrails.${agentNameClassName} as { guardrailId, guardrailVersion }.`,\n );\n }\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n agentPath,\n agentTargetPrefix,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n TS_AGENT_GUARDRAILS_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n\n // Printed from the callback so it appears after Nx lists the changed\n // files, on every run, since the generator cannot tell whether the stack is\n // already wired.\n return () => {\n if (wiringMessage) {\n logger.info(wiringMessage);\n }\n };\n};\n\nexport default tsAgentGuardrailsGenerator;\n"],"names":["generateFiles","joinPathFragments","logger","OverwriteStrategy","addDestructuredImport","applyGritQL","matchGritQL","formatFilesInSubtree","addGuardrailInfra","addGuardrailPolicy","guardrailWiringMessage","addGeneratorMetricsIfApplicable","esmVars","isEsmWorkspace","kebabCase","toClassName","getNpmScope","addComponentGeneratorMetadata","getGeneratorInfo","readProjectConfigurationUnqualified","TS_AGENT_GENERATOR_INFO","addGuardrailPolicySynthInputs","TS_AGENT_GUARDRAILS_GENERATOR_INFO","filename","resolveAgent","projectName","components","agent","agents","filter","c","generator","id","available","map","name","join","match","find","Error","length","addGuardrailedModelToAgent","tree","agentFile","guardrailImport","exists","warn","tsAgentGuardrailsGenerator","options","project","metadata","agentTargetPrefix","agentNameClassName","rc","nameKebabCase","agentPath","path","agentDir","root","dirname","agentConnectionImport","overwriteStrategy","KeepExisting","iac","wiringMessage","policyPath","nameClassName","message","npmScope","info"],"mappings":"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"}
@@ -8,6 +8,10 @@ terraform {
8
8
  source = "hashicorp/random"
9
9
  version = "<%- randomProviderVersion %>"
10
10
  }
11
+ time = {
12
+ source = "hashicorp/time"
13
+ version = "<%- timeProviderVersion %>"
14
+ }
11
15
  }
12
16
  }
13
17
 
@@ -72,12 +76,25 @@ resource "aws_bedrock_guardrail_version" "this" {
72
76
  }
73
77
  }
74
78
 
79
+ resource "time_sleep" "version_retention" {
80
+ destroy_duration = "15s"
81
+
82
+ triggers = {
83
+ guardrail_id = aws_bedrock_guardrail.this.guardrail_id
84
+ guardrail_version = aws_bedrock_guardrail_version.this.version
85
+ }
86
+
87
+ lifecycle {
88
+ create_before_destroy = true
89
+ }
90
+ }
91
+
75
92
  module "add_guardrail_to_runtime_config" {
76
93
  source = "../../../core/runtime-config/entry"
77
94
 
78
95
  namespace = "agentcore"
79
96
  key = "guardrails"
80
- value = { "<%= nameClassName %>" = { guardrailId = aws_bedrock_guardrail.this.guardrail_id, guardrailVersion = aws_bedrock_guardrail_version.this.version } }
97
+ value = { "<%= nameClassName %>" = { guardrailId = time_sleep.version_retention.triggers.guardrail_id, guardrailVersion = time_sleep.version_retention.triggers.guardrail_version } }
81
98
  }
82
99
 
83
100
  output "guardrail_id" {
@@ -16,6 +16,11 @@ export interface AddGuardrailInfraOptions {
16
16
  /** Workspace-root-relative path of the guardrail.json policy file. */
17
17
  policyPath: string;
18
18
  }
19
+ /**
20
+ * Write the guardrail.json policy next to the agent. The policy is the
21
+ * user's to edit, so a re-run never touches an existing file.
22
+ */
23
+ export declare const addGuardrailPolicy: (tree: Tree, agentDir: string) => void;
19
24
  /**
20
25
  * Add the Amazon Bedrock Guardrail infrastructure for the selected IaC
21
26
  * provider: a CDK construct in the shared constructs project, or a Terraform
@@ -6,6 +6,14 @@ import { addStarExport } from "../ast.js";
6
6
  import { esmVars } from "../module-format.js";
7
7
  import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
8
8
  import { terraformProviderVersions } from "../versions.js";
9
+ /**
10
+ * Write the guardrail.json policy next to the agent. The policy is the
11
+ * user's to edit, so a re-run never touches an existing file.
12
+ */ export const addGuardrailPolicy = (tree, agentDir)=>{
13
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'policy'), agentDir, {}, {
14
+ overwriteStrategy: OverwriteStrategy.KeepExisting
15
+ });
16
+ };
9
17
  /**
10
18
  * Add the Amazon Bedrock Guardrail infrastructure for the selected IaC
11
19
  * provider: a CDK construct in the shared constructs project, or a Terraform
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/guardrail-constructs/guardrail-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast.js';\nimport type { Iac } from '../iac.js';\nimport { esmVars } from '../module-format.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport { terraformProviderVersions } from '../versions.js';\n\nexport interface AddGuardrailInfraOptions {\n iac: Iac;\n /** Class name of the guarded agent, eg `MyAgent` gives `MyAgentGuardrail`. */\n nameClassName: string;\n /**\n * Kebab-case name of the guarded agent, used for the directory and, with a\n * `-guardrail` suffix, the file.\n */\n nameKebabCase: string;\n /** Workspace-root-relative path of the guardrail.json policy file. */\n policyPath: string;\n}\n\n/**\n * Add the Amazon Bedrock Guardrail infrastructure for the selected IaC\n * provider: a CDK construct in the shared constructs project, or a Terraform\n * module in the shared Terraform project. Both read the policy file at synth\n * or plan time.\n *\n * Files are written with `KeepExisting`, so a re-run leaves them unchanged.\n * No build dependency is added on the agent's project, since the\n * infrastructure reads a source file and imports none of the agent's code;\n * for CDK the generator lists that file as a `synth` input instead, so the\n * infrastructure's cached synth follows it.\n */\nexport const addGuardrailInfra = async (\n tree: Tree,\n options: AddGuardrailInfraOptions,\n): Promise<void> => {\n const templateContext = {\n nameClassName: options.nameClassName,\n nameKebabCase: options.nameKebabCase,\n policyPath: options.policyPath,\n };\n\n switch (options.iac) {\n case 'cdk': {\n const appDir = joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n );\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(appDir, 'guardrails'),\n { ...templateContext, ...esmVars(tree) },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'guardrails', 'index.ts'),\n `./${options.nameKebabCase}/${options.nameKebabCase}-guardrail.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'index.ts'),\n './guardrails/index.js',\n );\n break;\n }\n case 'terraform':\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'guardrails',\n ),\n {\n ...templateContext,\n // Guardrail names are at most 50 characters: the prefix, a hyphen\n // and the 8 hex characters of the random suffix.\n guardrailNamePrefix: `${options.nameKebabCase}-guardrail`.slice(\n 0,\n 41,\n ),\n ...terraformProviderVersions(),\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n break;\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","addStarExport","esmVars","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","terraformProviderVersions","addGuardrailInfra","tree","options","templateContext","nameClassName","nameKebabCase","policyPath","iac","appDir","dirname","overwriteStrategy","KeepExisting","guardrailNamePrefix","slice"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,QAEZ,aAAa;AACpB,SAASC,aAAa,QAAQ,YAAY;AAE1C,SAASC,OAAO,QAAQ,sBAAsB;AAC9C,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,oCAAoC;AAC3C,SAASC,yBAAyB,QAAQ,iBAAiB;AAe3D;;;;;;;;;;;CAWC,GACD,OAAO,MAAMC,oBAAoB,OAC/BC,MACAC;IAEA,MAAMC,kBAAkB;QACtBC,eAAeF,QAAQE,aAAa;QACpCC,eAAeH,QAAQG,aAAa;QACpCC,YAAYJ,QAAQI,UAAU;IAChC;IAEA,OAAQJ,QAAQK,GAAG;QACjB,KAAK;YAAO;gBACV,MAAMC,SAAShB,kBACbI,cACAC,uBACA,OACA;gBAEFN,cACEU,MACAT,kBACE,YAAYiB,OAAO,EACnB,SACA,OACA,OACA,eAEFjB,kBAAkBgB,QAAQ,eAC1B;oBAAE,GAAGL,eAAe;oBAAE,GAAGR,QAAQM,KAAK;gBAAC,GACvC;oBAAES,mBAAmBjB,kBAAkBkB,YAAY;gBAAC;gBAEtD,MAAMjB,cACJO,MACAT,kBAAkBgB,QAAQ,cAAc,aACxC,CAAC,EAAE,EAAEN,QAAQG,aAAa,CAAC,CAAC,EAAEH,QAAQG,aAAa,CAAC,aAAa,CAAC;gBAEpE,MAAMX,cACJO,MACAT,kBAAkBgB,QAAQ,aAC1B;gBAEF;YACF;QACA,KAAK;YACHjB,cACEU,MACAT,kBACE,YAAYiB,OAAO,EACnB,SACA,aACA,OACA,eAEFjB,kBACEI,cACAE,sBACA,OACA,OACA,eAEF;gBACE,GAAGK,eAAe;gBAClB,kEAAkE;gBAClE,iDAAiD;gBACjDS,qBAAqB,GAAGV,QAAQG,aAAa,CAAC,UAAU,CAAC,CAACQ,KAAK,CAC7D,GACA;gBAEF,GAAGd,2BAA2B;YAChC,GACA;gBAAEW,mBAAmBjB,kBAAkBkB,YAAY;YAAC;YAEtD;IACJ;AACF,EAAE"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/guardrail-constructs/guardrail-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast.js';\nimport type { Iac } from '../iac.js';\nimport { esmVars } from '../module-format.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport { terraformProviderVersions } from '../versions.js';\n\nexport interface AddGuardrailInfraOptions {\n iac: Iac;\n /** Class name of the guarded agent, eg `MyAgent` gives `MyAgentGuardrail`. */\n nameClassName: string;\n /**\n * Kebab-case name of the guarded agent, used for the directory and, with a\n * `-guardrail` suffix, the file.\n */\n nameKebabCase: string;\n /** Workspace-root-relative path of the guardrail.json policy file. */\n policyPath: string;\n}\n\n/**\n * Write the guardrail.json policy next to the agent. The policy is the\n * user's to edit, so a re-run never touches an existing file.\n */\nexport const addGuardrailPolicy = (tree: Tree, agentDir: string): void => {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'policy'),\n agentDir,\n {},\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n};\n\n/**\n * Add the Amazon Bedrock Guardrail infrastructure for the selected IaC\n * provider: a CDK construct in the shared constructs project, or a Terraform\n * module in the shared Terraform project. Both read the policy file at synth\n * or plan time.\n *\n * Files are written with `KeepExisting`, so a re-run leaves them unchanged.\n * No build dependency is added on the agent's project, since the\n * infrastructure reads a source file and imports none of the agent's code;\n * for CDK the generator lists that file as a `synth` input instead, so the\n * infrastructure's cached synth follows it.\n */\nexport const addGuardrailInfra = async (\n tree: Tree,\n options: AddGuardrailInfraOptions,\n): Promise<void> => {\n const templateContext = {\n nameClassName: options.nameClassName,\n nameKebabCase: options.nameKebabCase,\n policyPath: options.policyPath,\n };\n\n switch (options.iac) {\n case 'cdk': {\n const appDir = joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n );\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(appDir, 'guardrails'),\n { ...templateContext, ...esmVars(tree) },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'guardrails', 'index.ts'),\n `./${options.nameKebabCase}/${options.nameKebabCase}-guardrail.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(appDir, 'index.ts'),\n './guardrails/index.js',\n );\n break;\n }\n case 'terraform':\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'guardrails',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'guardrails',\n ),\n {\n ...templateContext,\n // Guardrail names are at most 50 characters: the prefix, a hyphen\n // and the 8 hex characters of the random suffix.\n guardrailNamePrefix: `${options.nameKebabCase}-guardrail`.slice(\n 0,\n 41,\n ),\n ...terraformProviderVersions(),\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n break;\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","addStarExport","esmVars","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","terraformProviderVersions","addGuardrailPolicy","tree","agentDir","dirname","overwriteStrategy","KeepExisting","addGuardrailInfra","options","templateContext","nameClassName","nameKebabCase","policyPath","iac","appDir","guardrailNamePrefix","slice"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,QAEZ,aAAa;AACpB,SAASC,aAAa,QAAQ,YAAY;AAE1C,SAASC,OAAO,QAAQ,sBAAsB;AAC9C,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,oCAAoC;AAC3C,SAASC,yBAAyB,QAAQ,iBAAiB;AAe3D;;;CAGC,GACD,OAAO,MAAMC,qBAAqB,CAACC,MAAYC;IAC7CX,cACEU,MACAT,kBAAkB,YAAYW,OAAO,EAAE,SAAS,WAChDD,UACA,CAAC,GACD;QAAEE,mBAAmBX,kBAAkBY,YAAY;IAAC;AAExD,EAAE;AAEF;;;;;;;;;;;CAWC,GACD,OAAO,MAAMC,oBAAoB,OAC/BL,MACAM;IAEA,MAAMC,kBAAkB;QACtBC,eAAeF,QAAQE,aAAa;QACpCC,eAAeH,QAAQG,aAAa;QACpCC,YAAYJ,QAAQI,UAAU;IAChC;IAEA,OAAQJ,QAAQK,GAAG;QACjB,KAAK;YAAO;gBACV,MAAMC,SAASrB,kBACbI,cACAC,uBACA,OACA;gBAEFN,cACEU,MACAT,kBACE,YAAYW,OAAO,EACnB,SACA,OACA,OACA,eAEFX,kBAAkBqB,QAAQ,eAC1B;oBAAE,GAAGL,eAAe;oBAAE,GAAGb,QAAQM,KAAK;gBAAC,GACvC;oBAAEG,mBAAmBX,kBAAkBY,YAAY;gBAAC;gBAEtD,MAAMX,cACJO,MACAT,kBAAkBqB,QAAQ,cAAc,aACxC,CAAC,EAAE,EAAEN,QAAQG,aAAa,CAAC,CAAC,EAAEH,QAAQG,aAAa,CAAC,aAAa,CAAC;gBAEpE,MAAMhB,cACJO,MACAT,kBAAkBqB,QAAQ,aAC1B;gBAEF;YACF;QACA,KAAK;YACHtB,cACEU,MACAT,kBACE,YAAYW,OAAO,EACnB,SACA,aACA,OACA,eAEFX,kBACEI,cACAE,sBACA,OACA,OACA,eAEF;gBACE,GAAGU,eAAe;gBAClB,kEAAkE;gBAClE,iDAAiD;gBACjDM,qBAAqB,GAAGP,QAAQG,aAAa,CAAC,UAAU,CAAC,CAACK,KAAK,CAC7D,GACA;gBAEF,GAAGhB,2BAA2B;YAChC,GACA;gBAAEK,mBAAmBX,kBAAkBY,YAAY;YAAC;YAEtD;IACJ;AACF,EAAE"}
@@ -11,9 +11,16 @@ export interface GuardrailWiringOptions {
11
11
  nameKebabCase: string;
12
12
  /** npm scope of the workspace without the `@`, eg `my-scope`. */
13
13
  npmScope: string;
14
+ /**
15
+ * The agent guide section that shows how to deploy the agent's Terraform
16
+ * module. Defaults to the ts#agent guide.
17
+ */
18
+ deployGuideUrl?: string;
14
19
  }
15
20
  /** The ts#agent guide section that shows how to deploy the agent's Terraform module. */
16
21
  export declare const TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL = "https://awslabs.github.io/nx-plugin-for-aws/en/guides/ts-agent/#infrastructure-as-code";
22
+ /** The py#agent guide section that shows how to deploy the agent's Terraform module. */
23
+ export declare const PY_AGENT_TERRAFORM_DEPLOY_GUIDE_URL = "https://awslabs.github.io/nx-plugin-for-aws/en/guides/py-agent/#infrastructure-as-code";
17
24
  /**
18
25
  * The code a user adds to their CDK stack to guard the agent.
19
26
  * The guide shows the same code for `my-agent` in scope `my-scope`, which