@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
@@ -4,6 +4,7 @@
4
4
  */ import { snakeCase } from "../names.js";
5
5
  import { SHARED_CONSTRUCTS_NAME } from "../shared-constructs-constants.js";
6
6
  /** The ts#agent guide section that shows how to deploy the agent's Terraform module. */ export const TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL = 'https://awslabs.github.io/nx-plugin-for-aws/en/guides/ts-agent/#infrastructure-as-code';
7
+ /** The py#agent guide section that shows how to deploy the agent's Terraform module. */ export const PY_AGENT_TERRAFORM_DEPLOY_GUIDE_URL = 'https://awslabs.github.io/nx-plugin-for-aws/en/guides/py-agent/#infrastructure-as-code';
7
8
  /**
8
9
  * The code a user adds to their CDK stack to guard the agent.
9
10
  * The guide shows the same code for `my-agent` in scope `my-scope`, which
@@ -39,11 +40,11 @@ module "runtime_config_appconfig_deployment" {
39
40
  }`;
40
41
  };
41
42
  /**
42
- * How to add the printed Terraform code. `ts#agent` does not add the agent to
43
- * the root module, so its `module` block may not exist yet.
44
- */ const terraformSteps = (nameKebabCase)=>{
43
+ * How to add the printed Terraform code. The agent generators do not add the
44
+ * agent to the root module, so its `module` block may not exist yet.
45
+ */ const terraformSteps = (nameKebabCase, deployGuideUrl = TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL)=>{
45
46
  const agentModule = snakeCase(nameKebabCase);
46
- return `Add the module "${agentModule}_guardrail" block as printed below. Add its additional_iam_policy_statements line to your existing module "${agentModule}" block, and add module.${agentModule}_guardrail to the depends_on list of your runtime_config_appconfig_deployment module. If your root module does not deploy the agent yet, add the agent's module first, as described in ${TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL}.`;
47
+ return `Add the module "${agentModule}_guardrail" block as printed below. Add its additional_iam_policy_statements line to your existing module "${agentModule}" block, and add module.${agentModule}_guardrail to the depends_on list of your runtime_config_appconfig_deployment module. If your root module does not deploy the agent yet, add the agent's module first, as described in ${deployGuideUrl}.`;
47
48
  };
48
49
  /**
49
50
  * The message the generator prints after it adds the guardrail
@@ -53,7 +54,7 @@ module "runtime_config_appconfig_deployment" {
53
54
  const missing = `Until you add it, the deployed agent fails on its first request, because runtime config has no guardrail at agentcore.guardrails.${options.nameClassName}.`;
54
55
  return options.iac === 'cdk' ? `Add the guardrail to your agent in your stack, for example packages/infra/src/stacks/application-stack.ts. ${missing}
55
56
 
56
- ${cdkGuardrailWiring(options)}` : `Add the guardrail to your agent in the root Terraform module where you deploy the agent, for example packages/infra/src/main.tf. ${missing} ${terraformSteps(options.nameKebabCase)}
57
+ ${cdkGuardrailWiring(options)}` : `Add the guardrail to your agent in the root Terraform module where you deploy the agent, for example packages/infra/src/main.tf. ${missing} ${terraformSteps(options.nameKebabCase, options.deployGuideUrl)}
57
58
 
58
59
  ${terraformGuardrailWiring(options)}`;
59
60
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/guardrail-constructs/guardrail-wiring.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { Iac } from '../iac.js';\nimport { snakeCase } from '../names.js';\nimport { SHARED_CONSTRUCTS_NAME } from '../shared-constructs-constants.js';\n\nexport interface GuardrailWiringOptions {\n iac: Iac;\n /** Class name of the guarded agent, eg `MyAgent`. */\n nameClassName: string;\n /** Kebab-case name of the guarded agent, eg `my-agent`. */\n nameKebabCase: string;\n /** npm scope of the workspace without the `@`, eg `my-scope`. */\n npmScope: string;\n}\n\n/** The ts#agent guide section that shows how to deploy the agent's Terraform module. */\nexport const TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL =\n 'https://awslabs.github.io/nx-plugin-for-aws/en/guides/ts-agent/#infrastructure-as-code';\n\n/**\n * The code a user adds to their CDK stack to guard the agent.\n * The guide shows the same code for `my-agent` in scope `my-scope`, which\n * generator.spec.ts checks.\n */\nexport const cdkGuardrailWiring = ({\n nameClassName,\n npmScope,\n}: Pick<GuardrailWiringOptions, 'nameClassName' | 'npmScope'>): string =>\n `import { ${nameClassName}, ${nameClassName}Guardrail } from '@${npmScope}/${SHARED_CONSTRUCTS_NAME}';\n\nconst agent = new ${nameClassName}(this, '${nameClassName}');\nnew ${nameClassName}Guardrail(this, '${nameClassName}Guardrail', { agent });`;\n\n/**\n * The code a user adds to their root Terraform module to grant the agent the\n * guardrail and deploy its runtime-config entry, relative to\n * `packages/infra/src`. The guide shows the same code for `my-agent`, which\n * generator.spec.ts checks.\n */\nexport const terraformGuardrailWiring = ({\n nameKebabCase,\n}: Pick<GuardrailWiringOptions, 'nameKebabCase'>): string => {\n const agentModule = snakeCase(nameKebabCase);\n const guardrailModule = `${agentModule}_guardrail`;\n return `module \"${guardrailModule}\" {\n source = \"../../common/terraform/src/app/guardrails/${nameKebabCase}\"\n}\n\nmodule \"${agentModule}\" {\n source = \"../../common/terraform/src/app/agents/${nameKebabCase}\"\n # ...existing arguments...\n additional_iam_policy_statements = module.${guardrailModule}.iam_policy_statements\n}\n\nmodule \"runtime_config_appconfig_deployment\" {\n # ...existing arguments...\n depends_on = [\n # ...existing modules...\n module.${guardrailModule},\n ]\n}`;\n};\n\n/**\n * How to add the printed Terraform code. `ts#agent` does not add the agent to\n * the root module, so its `module` block may not exist yet.\n */\nconst terraformSteps = (nameKebabCase: string): string => {\n const agentModule = snakeCase(nameKebabCase);\n return `Add the module \"${agentModule}_guardrail\" block as printed below. Add its additional_iam_policy_statements line to your existing module \"${agentModule}\" block, and add module.${agentModule}_guardrail to the depends_on list of your runtime_config_appconfig_deployment module. If your root module does not deploy the agent yet, add the agent's module first, as described in ${TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL}.`;\n};\n\n/**\n * The message the generator prints after it adds the guardrail\n * infrastructure. The generator does not edit the user's stack or root\n * module, so this tells the user what to add there.\n */\nexport const guardrailWiringMessage = (\n options: GuardrailWiringOptions,\n): string => {\n const missing = `Until you add it, the deployed agent fails on its first request, because runtime config has no guardrail at agentcore.guardrails.${options.nameClassName}.`;\n return options.iac === 'cdk'\n ? `Add the guardrail to your agent in your stack, for example packages/infra/src/stacks/application-stack.ts. ${missing}\n\n${cdkGuardrailWiring(options)}`\n : `Add the guardrail to your agent in the root Terraform module where you deploy the agent, for example packages/infra/src/main.tf. ${missing} ${terraformSteps(options.nameKebabCase)}\n\n${terraformGuardrailWiring(options)}`;\n};\n"],"names":["snakeCase","SHARED_CONSTRUCTS_NAME","TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL","cdkGuardrailWiring","nameClassName","npmScope","terraformGuardrailWiring","nameKebabCase","agentModule","guardrailModule","terraformSteps","guardrailWiringMessage","options","missing","iac"],"mappings":"AAAA;;;CAGC,GAED,SAASA,SAAS,QAAQ,cAAc;AACxC,SAASC,sBAAsB,QAAQ,oCAAoC;AAY3E,sFAAsF,GACtF,OAAO,MAAMC,sCACX,yFAAyF;AAE3F;;;;CAIC,GACD,OAAO,MAAMC,qBAAqB,CAAC,EACjCC,aAAa,EACbC,QAAQ,EACmD,GAC3D,CAAC,SAAS,EAAED,cAAc,EAAE,EAAEA,cAAc,mBAAmB,EAAEC,SAAS,CAAC,EAAEJ,uBAAuB;;kBAEpF,EAAEG,cAAc,QAAQ,EAAEA,cAAc;IACtD,EAAEA,cAAc,iBAAiB,EAAEA,cAAc,uBAAuB,CAAC,CAAC;AAE9E;;;;;CAKC,GACD,OAAO,MAAME,2BAA2B,CAAC,EACvCC,aAAa,EACiC;IAC9C,MAAMC,cAAcR,UAAUO;IAC9B,MAAME,kBAAkB,GAAGD,YAAY,UAAU,CAAC;IAClD,OAAO,CAAC,QAAQ,EAAEC,gBAAgB;sDACkB,EAAEF,cAAc;;;QAG9D,EAAEC,YAAY;kDAC4B,EAAED,cAAc;;4CAEtB,EAAEE,gBAAgB;;;;;;;WAOnD,EAAEA,gBAAgB;;CAE5B,CAAC;AACF,EAAE;AAEF;;;CAGC,GACD,MAAMC,iBAAiB,CAACH;IACtB,MAAMC,cAAcR,UAAUO;IAC9B,OAAO,CAAC,gBAAgB,EAAEC,YAAY,2GAA2G,EAAEA,YAAY,wBAAwB,EAAEA,YAAY,uLAAuL,EAAEN,oCAAoC,CAAC,CAAC;AACta;AAEA;;;;CAIC,GACD,OAAO,MAAMS,yBAAyB,CACpCC;IAEA,MAAMC,UAAU,CAAC,iIAAiI,EAAED,QAAQR,aAAa,CAAC,CAAC,CAAC;IAC5K,OAAOQ,QAAQE,GAAG,KAAK,QACnB,CAAC,2GAA2G,EAAED,QAAQ;;AAE5H,EAAEV,mBAAmBS,UAAU,GACzB,CAAC,iIAAiI,EAAEC,QAAQ,CAAC,EAAEH,eAAeE,QAAQL,aAAa,EAAE;;AAE3L,EAAED,yBAAyBM,UAAU;AACrC,EAAE"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/guardrail-constructs/guardrail-wiring.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { Iac } from '../iac.js';\nimport { snakeCase } from '../names.js';\nimport { SHARED_CONSTRUCTS_NAME } from '../shared-constructs-constants.js';\n\nexport interface GuardrailWiringOptions {\n iac: Iac;\n /** Class name of the guarded agent, eg `MyAgent`. */\n nameClassName: string;\n /** Kebab-case name of the guarded agent, eg `my-agent`. */\n nameKebabCase: string;\n /** npm scope of the workspace without the `@`, eg `my-scope`. */\n npmScope: string;\n /**\n * The agent guide section that shows how to deploy the agent's Terraform\n * module. Defaults to the ts#agent guide.\n */\n deployGuideUrl?: string;\n}\n\n/** The ts#agent guide section that shows how to deploy the agent's Terraform module. */\nexport const TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL =\n 'https://awslabs.github.io/nx-plugin-for-aws/en/guides/ts-agent/#infrastructure-as-code';\n\n/** The py#agent guide section that shows how to deploy the agent's Terraform module. */\nexport const PY_AGENT_TERRAFORM_DEPLOY_GUIDE_URL =\n 'https://awslabs.github.io/nx-plugin-for-aws/en/guides/py-agent/#infrastructure-as-code';\n\n/**\n * The code a user adds to their CDK stack to guard the agent.\n * The guide shows the same code for `my-agent` in scope `my-scope`, which\n * generator.spec.ts checks.\n */\nexport const cdkGuardrailWiring = ({\n nameClassName,\n npmScope,\n}: Pick<GuardrailWiringOptions, 'nameClassName' | 'npmScope'>): string =>\n `import { ${nameClassName}, ${nameClassName}Guardrail } from '@${npmScope}/${SHARED_CONSTRUCTS_NAME}';\n\nconst agent = new ${nameClassName}(this, '${nameClassName}');\nnew ${nameClassName}Guardrail(this, '${nameClassName}Guardrail', { agent });`;\n\n/**\n * The code a user adds to their root Terraform module to grant the agent the\n * guardrail and deploy its runtime-config entry, relative to\n * `packages/infra/src`. The guide shows the same code for `my-agent`, which\n * generator.spec.ts checks.\n */\nexport const terraformGuardrailWiring = ({\n nameKebabCase,\n}: Pick<GuardrailWiringOptions, 'nameKebabCase'>): string => {\n const agentModule = snakeCase(nameKebabCase);\n const guardrailModule = `${agentModule}_guardrail`;\n return `module \"${guardrailModule}\" {\n source = \"../../common/terraform/src/app/guardrails/${nameKebabCase}\"\n}\n\nmodule \"${agentModule}\" {\n source = \"../../common/terraform/src/app/agents/${nameKebabCase}\"\n # ...existing arguments...\n additional_iam_policy_statements = module.${guardrailModule}.iam_policy_statements\n}\n\nmodule \"runtime_config_appconfig_deployment\" {\n # ...existing arguments...\n depends_on = [\n # ...existing modules...\n module.${guardrailModule},\n ]\n}`;\n};\n\n/**\n * How to add the printed Terraform code. The agent generators do not add the\n * agent to the root module, so its `module` block may not exist yet.\n */\nconst terraformSteps = (\n nameKebabCase: string,\n deployGuideUrl = TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL,\n): string => {\n const agentModule = snakeCase(nameKebabCase);\n return `Add the module \"${agentModule}_guardrail\" block as printed below. Add its additional_iam_policy_statements line to your existing module \"${agentModule}\" block, and add module.${agentModule}_guardrail to the depends_on list of your runtime_config_appconfig_deployment module. If your root module does not deploy the agent yet, add the agent's module first, as described in ${deployGuideUrl}.`;\n};\n\n/**\n * The message the generator prints after it adds the guardrail\n * infrastructure. The generator does not edit the user's stack or root\n * module, so this tells the user what to add there.\n */\nexport const guardrailWiringMessage = (\n options: GuardrailWiringOptions,\n): string => {\n const missing = `Until you add it, the deployed agent fails on its first request, because runtime config has no guardrail at agentcore.guardrails.${options.nameClassName}.`;\n return options.iac === 'cdk'\n ? `Add the guardrail to your agent in your stack, for example packages/infra/src/stacks/application-stack.ts. ${missing}\n\n${cdkGuardrailWiring(options)}`\n : `Add the guardrail to your agent in the root Terraform module where you deploy the agent, for example packages/infra/src/main.tf. ${missing} ${terraformSteps(options.nameKebabCase, options.deployGuideUrl)}\n\n${terraformGuardrailWiring(options)}`;\n};\n"],"names":["snakeCase","SHARED_CONSTRUCTS_NAME","TS_AGENT_TERRAFORM_DEPLOY_GUIDE_URL","PY_AGENT_TERRAFORM_DEPLOY_GUIDE_URL","cdkGuardrailWiring","nameClassName","npmScope","terraformGuardrailWiring","nameKebabCase","agentModule","guardrailModule","terraformSteps","deployGuideUrl","guardrailWiringMessage","options","missing","iac"],"mappings":"AAAA;;;CAGC,GAED,SAASA,SAAS,QAAQ,cAAc;AACxC,SAASC,sBAAsB,QAAQ,oCAAoC;AAiB3E,sFAAsF,GACtF,OAAO,MAAMC,sCACX,yFAAyF;AAE3F,sFAAsF,GACtF,OAAO,MAAMC,sCACX,yFAAyF;AAE3F;;;;CAIC,GACD,OAAO,MAAMC,qBAAqB,CAAC,EACjCC,aAAa,EACbC,QAAQ,EACmD,GAC3D,CAAC,SAAS,EAAED,cAAc,EAAE,EAAEA,cAAc,mBAAmB,EAAEC,SAAS,CAAC,EAAEL,uBAAuB;;kBAEpF,EAAEI,cAAc,QAAQ,EAAEA,cAAc;IACtD,EAAEA,cAAc,iBAAiB,EAAEA,cAAc,uBAAuB,CAAC,CAAC;AAE9E;;;;;CAKC,GACD,OAAO,MAAME,2BAA2B,CAAC,EACvCC,aAAa,EACiC;IAC9C,MAAMC,cAAcT,UAAUQ;IAC9B,MAAME,kBAAkB,GAAGD,YAAY,UAAU,CAAC;IAClD,OAAO,CAAC,QAAQ,EAAEC,gBAAgB;sDACkB,EAAEF,cAAc;;;QAG9D,EAAEC,YAAY;kDAC4B,EAAED,cAAc;;4CAEtB,EAAEE,gBAAgB;;;;;;;WAOnD,EAAEA,gBAAgB;;CAE5B,CAAC;AACF,EAAE;AAEF;;;CAGC,GACD,MAAMC,iBAAiB,CACrBH,eACAI,iBAAiBV,mCAAmC;IAEpD,MAAMO,cAAcT,UAAUQ;IAC9B,OAAO,CAAC,gBAAgB,EAAEC,YAAY,2GAA2G,EAAEA,YAAY,wBAAwB,EAAEA,YAAY,uLAAuL,EAAEG,eAAe,CAAC,CAAC;AACjZ;AAEA;;;;CAIC,GACD,OAAO,MAAMC,yBAAyB,CACpCC;IAEA,MAAMC,UAAU,CAAC,iIAAiI,EAAED,QAAQT,aAAa,CAAC,CAAC,CAAC;IAC5K,OAAOS,QAAQE,GAAG,KAAK,QACnB,CAAC,2GAA2G,EAAED,QAAQ;;AAE5H,EAAEX,mBAAmBU,UAAU,GACzB,CAAC,iIAAiI,EAAEC,QAAQ,CAAC,EAAEJ,eAAeG,QAAQN,aAAa,EAAEM,QAAQF,cAAc,EAAE;;AAEnN,EAAEL,yBAAyBO,UAAU;AACrC,EAAE"}
@@ -0,0 +1,205 @@
1
+ #
2
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ #
5
+ """Local stand-in for AppConfigData and Bedrock Runtime, so tests of generated
6
+ agent code send real SDK requests without AWS. Standard library only.
7
+
8
+ Usage: python fake_aws.py <config.json> <port> <requests.log>
9
+ or, in-process: start_server(config_file, log_file) returns (server, port).
10
+
11
+ - AppConfigData: POST /configurationsessions and GET /configuration serve the
12
+ JSON in <config.json>, re-read on every request, so editing the file changes
13
+ the value. A session whose ApplicationIdentifier is "broken" answers HTTP 400
14
+ BadRequestException, to simulate a read failure.
15
+ - Bedrock Runtime: POST /model/<id>/converse-stream (event stream) and
16
+ /model/<id>/converse (JSON) answer "4". A request with a guardrailConfig gets
17
+ BLOCKED_ANSWER with stop reason guardrail_intervened and a BLOCKED trace when
18
+ the text the guardrail checks contains DENIED_TERM. As in Bedrock, the
19
+ guardrail checks only the guardContent blocks if the messages hold any, and
20
+ every message otherwise.
21
+
22
+ Every request appends one JSON line to <requests.log>: AppConfigData requests
23
+ as {"path": "StartConfigurationSession" | "GetLatestConfiguration"}, model
24
+ requests as {"path", "modelId", "guardrailConfig", "userTexts", "intervened"}.
25
+ """
26
+
27
+ import binascii
28
+ import json
29
+ import struct
30
+ import sys
31
+ import threading
32
+ import urllib.parse
33
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
34
+
35
+ DENIED_TERM = "stocks"
36
+ BLOCKED_ANSWER = "Sorry, I can't help with that request."
37
+
38
+
39
+ def _header(name: str, value: str) -> bytes:
40
+ n, v = name.encode(), value.encode()
41
+ return struct.pack("B", len(n)) + n + b"\x07" + struct.pack(">H", len(v)) + v
42
+
43
+
44
+ def _event(event_type: str, payload: dict) -> bytes:
45
+ headers = (
46
+ _header(":event-type", event_type)
47
+ + _header(":content-type", "application/json")
48
+ + _header(":message-type", "event")
49
+ )
50
+ body = json.dumps(payload).encode()
51
+ total = 12 + len(headers) + len(body) + 4
52
+ prelude = struct.pack(">II", total, len(headers))
53
+ prelude += struct.pack(">I", binascii.crc32(prelude) & 0xFFFFFFFF)
54
+ message = prelude + headers + body
55
+ return message + struct.pack(">I", binascii.crc32(message) & 0xFFFFFFFF)
56
+
57
+
58
+ def _texts(blocks: list) -> list[str]:
59
+ texts = []
60
+ for block in blocks:
61
+ if "text" in block:
62
+ texts.append(block["text"])
63
+ elif "guardContent" in block:
64
+ texts.append(block["guardContent"].get("text", {}).get("text", ""))
65
+ elif "toolResult" in block:
66
+ texts.extend(_texts(block["toolResult"].get("content", [])))
67
+ return texts
68
+
69
+
70
+ def _intervenes(request: dict) -> bool:
71
+ """Whether the guardrail blocks the request's input, by Bedrock's rule for guardContent."""
72
+ if not request.get("guardrailConfig"):
73
+ return False
74
+ messages = request.get("messages", [])
75
+ guarded = [
76
+ block["guardContent"].get("text", {}).get("text", "")
77
+ for message in messages
78
+ for block in message.get("content", [])
79
+ if "guardContent" in block
80
+ ]
81
+ checked = guarded or [text for message in messages for text in _texts(message.get("content", []))]
82
+ return any(DENIED_TERM in text.lower() for text in checked)
83
+
84
+
85
+ _BLOCKED_TRACE = {
86
+ "guardrail": {
87
+ "inputAssessment": {
88
+ "grtest": {
89
+ "topicPolicy": {
90
+ "topics": [{"name": "Investment advice", "type": "DENY", "action": "BLOCKED", "detected": True}]
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+
98
+ def _handler(config_file: str, log_file: str) -> type[BaseHTTPRequestHandler]:
99
+ lock = threading.Lock()
100
+
101
+ def log(entry: dict) -> None:
102
+ with lock, open(log_file, "a") as f:
103
+ f.write(json.dumps(entry) + "\n")
104
+
105
+ class Handler(BaseHTTPRequestHandler):
106
+ protocol_version = "HTTP/1.1"
107
+
108
+ def log_message(self, *_args) -> None:
109
+ pass
110
+
111
+ def _send(self, status: int, body: bytes, content_type: str, extra=None) -> None:
112
+ self.send_response(status)
113
+ self.send_header("Content-Type", content_type)
114
+ self.send_header("Content-Length", str(len(body)))
115
+ for k, v in (extra or {}).items():
116
+ self.send_header(k, v)
117
+ self.end_headers()
118
+ self.wfile.write(body)
119
+
120
+ def do_GET(self) -> None:
121
+ if self.path.startswith("/configuration"):
122
+ log({"path": "GetLatestConfiguration"})
123
+ with open(config_file, "rb") as f:
124
+ body = f.read()
125
+ self._send(
126
+ 200,
127
+ body,
128
+ "application/json",
129
+ {"Next-Poll-Configuration-Token": "token", "Next-Poll-Interval-In-Seconds": "60"},
130
+ )
131
+ return
132
+ self._send(404, b"{}", "application/json")
133
+
134
+ def do_POST(self) -> None:
135
+ raw = self.rfile.read(int(self.headers.get("Content-Length", "0")))
136
+ if self.path.startswith("/configurationsessions"):
137
+ log({"path": "StartConfigurationSession"})
138
+ if json.loads(raw or b"{}").get("ApplicationIdentifier") == "broken":
139
+ self._send(
140
+ 400,
141
+ json.dumps({"Message": "Application broken does not exist."}).encode(),
142
+ "application/json",
143
+ {"x-amzn-ErrorType": "BadRequestException"},
144
+ )
145
+ return
146
+ self._send(201, json.dumps({"InitialConfigurationToken": "token"}).encode(), "application/json")
147
+ return
148
+ if self.path.startswith("/model/"):
149
+ request = json.loads(raw or b"{}")
150
+ model_id = urllib.parse.unquote(self.path.split("/")[2])
151
+ intervened = _intervenes(request)
152
+ log(
153
+ {
154
+ "path": self.path.split("/")[-1],
155
+ "modelId": model_id,
156
+ "guardrailConfig": request.get("guardrailConfig"),
157
+ "userTexts": [
158
+ text
159
+ for message in request.get("messages", [])
160
+ if message.get("role") == "user"
161
+ for text in _texts(message.get("content", []))
162
+ ],
163
+ "intervened": intervened,
164
+ }
165
+ )
166
+ text = BLOCKED_ANSWER if intervened else "4"
167
+ stop_reason = "guardrail_intervened" if intervened else "end_turn"
168
+ metadata = {
169
+ "usage": {"inputTokens": 1, "outputTokens": 1, "totalTokens": 2},
170
+ "metrics": {"latencyMs": 1},
171
+ **({"trace": _BLOCKED_TRACE} if intervened else {}),
172
+ }
173
+ if self.path.endswith("/converse-stream"):
174
+ body = b"".join(
175
+ [
176
+ _event("messageStart", {"role": "assistant"}),
177
+ _event("contentBlockDelta", {"contentBlockIndex": 0, "delta": {"text": text}}),
178
+ _event("contentBlockStop", {"contentBlockIndex": 0}),
179
+ _event("messageStop", {"stopReason": stop_reason}),
180
+ _event("metadata", metadata),
181
+ ]
182
+ )
183
+ self._send(200, body, "application/vnd.amazon.eventstream")
184
+ return
185
+ answer = {
186
+ "output": {"message": {"role": "assistant", "content": [{"text": text}]}},
187
+ "stopReason": stop_reason,
188
+ **metadata,
189
+ }
190
+ self._send(200, json.dumps(answer).encode(), "application/json")
191
+ return
192
+ self._send(404, b"{}", "application/json")
193
+
194
+ return Handler
195
+
196
+
197
+ def start_server(config_file: str, log_file: str, port: int = 0) -> tuple[ThreadingHTTPServer, int]:
198
+ """Serve on 127.0.0.1 in a daemon thread; port 0 picks a free port."""
199
+ server = ThreadingHTTPServer(("127.0.0.1", port), _handler(config_file, log_file))
200
+ threading.Thread(target=server.serve_forever, daemon=True).start()
201
+ return server, server.server_address[1]
202
+
203
+
204
+ if __name__ == "__main__":
205
+ ThreadingHTTPServer(("127.0.0.1", int(sys.argv[2])), _handler(sys.argv[1], sys.argv[3])).serve_forever()
@@ -12,3 +12,9 @@ export declare const PY_VERIFIER_TYPE_CHECKER: string;
12
12
  * they are included too.
13
13
  */
14
14
  export declare const PY_DYNAMODB_VERIFIER_DEPENDENCIES: string[];
15
+ /**
16
+ * The packages a Strands or LangChain agent generated by `py#agent` imports
17
+ * from agent.py and guardrail.py, at the versions the generator vends, plus
18
+ * the ruff the vended lint and format targets run.
19
+ */
20
+ export declare const PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES: string[];
@@ -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
  */ import { OPEN_API_PY_CLIENT_DEPENDENCIES } from "../../open-api/py-client/generator.js";
5
+ import { DEPENDENCIES as PY_AGENT_DEPENDENCIES } from "../../py/agent/generator.js";
5
6
  import { DEPENDENCIES as PY_DYNAMODB_DEPENDENCIES } from "../../py/dynamodb/generator.js";
6
7
  import { declaredNames } from "../declared-dependencies.js";
7
8
  import { PY_VERSIONS, withPyVersions } from "../versions.js";
@@ -19,5 +20,23 @@ import { PY_VERSIONS, withPyVersions } from "../versions.js";
19
20
  ...withPyVersions(PY_DYNAMODB_DEPENDENCIES, declaredNames(PY_DYNAMODB_DEPENDENCIES.py)),
20
21
  ...PY_CLIENT_VERIFIER_DEPENDENCIES
21
22
  ];
23
+ /**
24
+ * The packages a Strands or LangChain agent generated by `py#agent` imports
25
+ * from agent.py and guardrail.py, at the versions the generator vends, plus
26
+ * the ruff the vended lint and format targets run.
27
+ */ export const PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES = [
28
+ ...withPyVersions(PY_AGENT_DEPENDENCIES, [
29
+ 'aws-lambda-powertools',
30
+ 'boto3',
31
+ 'strands-agents',
32
+ 'strands-agents-tools',
33
+ 'langchain',
34
+ 'langchain-aws',
35
+ 'langgraph',
36
+ 'langgraph-checkpoint-sqlite',
37
+ 'aiosqlite'
38
+ ]),
39
+ `ruff${PY_VERSIONS.ruff}`
40
+ ];
22
41
 
23
42
  //# sourceMappingURL=python-dependencies.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/test/python-dependencies.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { OPEN_API_PY_CLIENT_DEPENDENCIES } from '../../open-api/py-client/generator.js';\nimport { DEPENDENCIES as PY_DYNAMODB_DEPENDENCIES } from '../../py/dynamodb/generator.js';\nimport { declaredNames } from '../declared-dependencies.js';\nimport { PY_VERSIONS, withPyVersions } from '../versions.js';\n\n/**\n * The packages a client generated by `open-api#py-client` imports, at the\n * versions the generator vends — so a worker runs the code under test against\n * exactly what a consumer gets.\n */\nexport const PY_CLIENT_VERIFIER_DEPENDENCIES: string[] = withPyVersions(\n OPEN_API_PY_CLIENT_DEPENDENCIES,\n declaredNames(OPEN_API_PY_CLIENT_DEPENDENCIES.py),\n);\n\n/** The type checker every Python worker installs alongside its dependencies. */\nexport const PY_VERIFIER_TYPE_CHECKER = `ty${PY_VERSIONS.ty}`;\n\n/**\n * The packages a project generated by `py#dynamodb` imports, at the versions\n * the generator vends. The worker itself imports the py-client packages, so\n * they are included too.\n */\nexport const PY_DYNAMODB_VERIFIER_DEPENDENCIES: string[] = [\n ...withPyVersions(\n PY_DYNAMODB_DEPENDENCIES,\n declaredNames(PY_DYNAMODB_DEPENDENCIES.py),\n ),\n ...PY_CLIENT_VERIFIER_DEPENDENCIES,\n];\n"],"names":["OPEN_API_PY_CLIENT_DEPENDENCIES","DEPENDENCIES","PY_DYNAMODB_DEPENDENCIES","declaredNames","PY_VERSIONS","withPyVersions","PY_CLIENT_VERIFIER_DEPENDENCIES","py","PY_VERIFIER_TYPE_CHECKER","ty","PY_DYNAMODB_VERIFIER_DEPENDENCIES"],"mappings":"AAAA;;;CAGC,GACD,SAASA,+BAA+B,QAAQ,wCAAwC;AACxF,SAASC,gBAAgBC,wBAAwB,QAAQ,iCAAiC;AAC1F,SAASC,aAAa,QAAQ,8BAA8B;AAC5D,SAASC,WAAW,EAAEC,cAAc,QAAQ,iBAAiB;AAE7D;;;;CAIC,GACD,OAAO,MAAMC,kCAA4CD,eACvDL,iCACAG,cAAcH,gCAAgCO,EAAE,GAChD;AAEF,8EAA8E,GAC9E,OAAO,MAAMC,2BAA2B,CAAC,EAAE,EAAEJ,YAAYK,EAAE,EAAE,CAAC;AAE9D;;;;CAIC,GACD,OAAO,MAAMC,oCAA8C;OACtDL,eACDH,0BACAC,cAAcD,yBAAyBK,EAAE;OAExCD;CACJ,CAAC"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/test/python-dependencies.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { OPEN_API_PY_CLIENT_DEPENDENCIES } from '../../open-api/py-client/generator.js';\nimport { DEPENDENCIES as PY_AGENT_DEPENDENCIES } from '../../py/agent/generator.js';\nimport { DEPENDENCIES as PY_DYNAMODB_DEPENDENCIES } from '../../py/dynamodb/generator.js';\nimport { declaredNames } from '../declared-dependencies.js';\nimport { PY_VERSIONS, withPyVersions } from '../versions.js';\n\n/**\n * The packages a client generated by `open-api#py-client` imports, at the\n * versions the generator vends — so a worker runs the code under test against\n * exactly what a consumer gets.\n */\nexport const PY_CLIENT_VERIFIER_DEPENDENCIES: string[] = withPyVersions(\n OPEN_API_PY_CLIENT_DEPENDENCIES,\n declaredNames(OPEN_API_PY_CLIENT_DEPENDENCIES.py),\n);\n\n/** The type checker every Python worker installs alongside its dependencies. */\nexport const PY_VERIFIER_TYPE_CHECKER = `ty${PY_VERSIONS.ty}`;\n\n/**\n * The packages a project generated by `py#dynamodb` imports, at the versions\n * the generator vends. The worker itself imports the py-client packages, so\n * they are included too.\n */\nexport const PY_DYNAMODB_VERIFIER_DEPENDENCIES: string[] = [\n ...withPyVersions(\n PY_DYNAMODB_DEPENDENCIES,\n declaredNames(PY_DYNAMODB_DEPENDENCIES.py),\n ),\n ...PY_CLIENT_VERIFIER_DEPENDENCIES,\n];\n\n/**\n * The packages a Strands or LangChain agent generated by `py#agent` imports\n * from agent.py and guardrail.py, at the versions the generator vends, plus\n * the ruff the vended lint and format targets run.\n */\nexport const PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES: string[] = [\n ...withPyVersions(PY_AGENT_DEPENDENCIES, [\n 'aws-lambda-powertools',\n 'boto3',\n 'strands-agents',\n 'strands-agents-tools',\n 'langchain',\n 'langchain-aws',\n 'langgraph',\n 'langgraph-checkpoint-sqlite',\n 'aiosqlite',\n ]),\n `ruff${PY_VERSIONS.ruff}`,\n];\n"],"names":["OPEN_API_PY_CLIENT_DEPENDENCIES","DEPENDENCIES","PY_AGENT_DEPENDENCIES","PY_DYNAMODB_DEPENDENCIES","declaredNames","PY_VERSIONS","withPyVersions","PY_CLIENT_VERIFIER_DEPENDENCIES","py","PY_VERIFIER_TYPE_CHECKER","ty","PY_DYNAMODB_VERIFIER_DEPENDENCIES","PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES","ruff"],"mappings":"AAAA;;;CAGC,GACD,SAASA,+BAA+B,QAAQ,wCAAwC;AACxF,SAASC,gBAAgBC,qBAAqB,QAAQ,8BAA8B;AACpF,SAASD,gBAAgBE,wBAAwB,QAAQ,iCAAiC;AAC1F,SAASC,aAAa,QAAQ,8BAA8B;AAC5D,SAASC,WAAW,EAAEC,cAAc,QAAQ,iBAAiB;AAE7D;;;;CAIC,GACD,OAAO,MAAMC,kCAA4CD,eACvDN,iCACAI,cAAcJ,gCAAgCQ,EAAE,GAChD;AAEF,8EAA8E,GAC9E,OAAO,MAAMC,2BAA2B,CAAC,EAAE,EAAEJ,YAAYK,EAAE,EAAE,CAAC;AAE9D;;;;CAIC,GACD,OAAO,MAAMC,oCAA8C;OACtDL,eACDH,0BACAC,cAAcD,yBAAyBK,EAAE;OAExCD;CACJ,CAAC;AAEF;;;;CAIC,GACD,OAAO,MAAMK,2CAAqD;OAC7DN,eAAeJ,uBAAuB;QACvC;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;KACD;IACD,CAAC,IAAI,EAAEG,YAAYQ,IAAI,EAAE;CAC1B,CAAC"}
@@ -3,7 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */ import { execFileSync } from "child_process";
5
5
  import { pyenvPythonVersion } from "../versions.js";
6
- import { PY_CLIENT_VERIFIER_DEPENDENCIES, PY_DYNAMODB_VERIFIER_DEPENDENCIES, PY_VERIFIER_TYPE_CHECKER } from "./python-dependencies.js";
6
+ import { PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES, PY_CLIENT_VERIFIER_DEPENDENCIES, PY_DYNAMODB_VERIFIER_DEPENDENCIES, PY_VERIFIER_TYPE_CHECKER } from "./python-dependencies.js";
7
7
  /**
8
8
  * Vitest globalSetup that warms uv's cache once before any worker spawns.
9
9
  *
@@ -31,6 +31,10 @@ import { PY_CLIENT_VERIFIER_DEPENDENCIES, PY_DYNAMODB_VERIFIER_DEPENDENCIES, PY_
31
31
  {
32
32
  dependencies: PY_DYNAMODB_VERIFIER_DEPENDENCIES,
33
33
  python: pyenvPythonVersion()
34
+ },
35
+ {
36
+ dependencies: PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES,
37
+ python: pyenvPythonVersion()
34
38
  }
35
39
  ];
36
40
  for (const { dependencies, python } of environments){
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/test/warm-python-cache.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { execFileSync } from 'child_process';\nimport { pyenvPythonVersion } from '../versions.js';\nimport {\n PY_CLIENT_VERIFIER_DEPENDENCIES,\n PY_DYNAMODB_VERIFIER_DEPENDENCIES,\n PY_VERIFIER_TYPE_CHECKER,\n} from './python-dependencies.js';\n\n/**\n * Vitest globalSetup that warms uv's cache once before any worker spawns.\n *\n * `PythonVerifier` starts a `uv run --with …` worker per spec file. On a cold\n * cache the first invocation takes an exclusive write lock while it downloads\n * and installs those packages; with many workers racing that lock, startup\n * stalls and a worker can be torn down before it answers. Installing them once\n * up front means every worker hits a warm cache, where uv only takes shared\n * locks.\n *\n * Mirrors the pre-warm this suite used for `ruff` before it moved in-process.\n *\n * A failure here is not fatal — a missing `uv` is reported by the verifier\n * itself, with a message naming the tool — but it is warned about rather than\n * swallowed: a broken cache otherwise degrades silently to every worker racing a\n * cold one, which is the startup failure this exists to prevent.\n */\nexport default function setup() {\n // The same sets the verifiers install, on the same interpreters, so the warm\n // cache is the one they hit. Wheels can be interpreter-specific, so each set\n // is warmed on the interpreter its verifier runs.\n const environments: { dependencies: string[]; python?: string }[] = [\n { dependencies: PY_CLIENT_VERIFIER_DEPENDENCIES },\n {\n dependencies: PY_DYNAMODB_VERIFIER_DEPENDENCIES,\n python: pyenvPythonVersion(),\n },\n ];\n for (const { dependencies, python } of environments) {\n const deps = [...dependencies, PY_VERIFIER_TYPE_CHECKER].flatMap((spec) => [\n '--with',\n spec,\n ]);\n const interpreter = python ? ['--python', python] : [];\n try {\n execFileSync('uv', ['run', ...interpreter, ...deps, 'python', '-c', ''], {\n stdio: 'ignore',\n });\n } catch (error) {\n console.warn(\n `Could not warm uv's cache, so each Python worker will install its own ` +\n `dependencies and may time out starting up: ${error}`,\n );\n }\n }\n}\n"],"names":["execFileSync","pyenvPythonVersion","PY_CLIENT_VERIFIER_DEPENDENCIES","PY_DYNAMODB_VERIFIER_DEPENDENCIES","PY_VERIFIER_TYPE_CHECKER","setup","environments","dependencies","python","deps","flatMap","spec","interpreter","stdio","error","console","warn"],"mappings":"AAAA;;;CAGC,GACD,SAASA,YAAY,QAAQ,gBAAgB;AAC7C,SAASC,kBAAkB,QAAQ,iBAAiB;AACpD,SACEC,+BAA+B,EAC/BC,iCAAiC,EACjCC,wBAAwB,QACnB,2BAA2B;AAElC;;;;;;;;;;;;;;;;CAgBC,GACD,eAAe,SAASC;IACtB,6EAA6E;IAC7E,6EAA6E;IAC7E,kDAAkD;IAClD,MAAMC,eAA8D;QAClE;YAAEC,cAAcL;QAAgC;QAChD;YACEK,cAAcJ;YACdK,QAAQP;QACV;KACD;IACD,KAAK,MAAM,EAAEM,YAAY,EAAEC,MAAM,EAAE,IAAIF,aAAc;QACnD,MAAMG,OAAO;eAAIF;YAAcH;SAAyB,CAACM,OAAO,CAAC,CAACC,OAAS;gBACzE;gBACAA;aACD;QACD,MAAMC,cAAcJ,SAAS;YAAC;YAAYA;SAAO,GAAG,EAAE;QACtD,IAAI;YACFR,aAAa,MAAM;gBAAC;mBAAUY;mBAAgBH;gBAAM;gBAAU;gBAAM;aAAG,EAAE;gBACvEI,OAAO;YACT;QACF,EAAE,OAAOC,OAAO;YACdC,QAAQC,IAAI,CACV,CAAC,sEAAsE,CAAC,GACtE,CAAC,2CAA2C,EAAEF,OAAO;QAE3D;IACF;AACF"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/test/warm-python-cache.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { execFileSync } from 'child_process';\nimport { pyenvPythonVersion } from '../versions.js';\nimport {\n PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES,\n PY_CLIENT_VERIFIER_DEPENDENCIES,\n PY_DYNAMODB_VERIFIER_DEPENDENCIES,\n PY_VERIFIER_TYPE_CHECKER,\n} from './python-dependencies.js';\n\n/**\n * Vitest globalSetup that warms uv's cache once before any worker spawns.\n *\n * `PythonVerifier` starts a `uv run --with …` worker per spec file. On a cold\n * cache the first invocation takes an exclusive write lock while it downloads\n * and installs those packages; with many workers racing that lock, startup\n * stalls and a worker can be torn down before it answers. Installing them once\n * up front means every worker hits a warm cache, where uv only takes shared\n * locks.\n *\n * Mirrors the pre-warm this suite used for `ruff` before it moved in-process.\n *\n * A failure here is not fatal — a missing `uv` is reported by the verifier\n * itself, with a message naming the tool — but it is warned about rather than\n * swallowed: a broken cache otherwise degrades silently to every worker racing a\n * cold one, which is the startup failure this exists to prevent.\n */\nexport default function setup() {\n // The same sets the verifiers install, on the same interpreters, so the warm\n // cache is the one they hit. Wheels can be interpreter-specific, so each set\n // is warmed on the interpreter its verifier runs.\n const environments: { dependencies: string[]; python?: string }[] = [\n { dependencies: PY_CLIENT_VERIFIER_DEPENDENCIES },\n {\n dependencies: PY_DYNAMODB_VERIFIER_DEPENDENCIES,\n python: pyenvPythonVersion(),\n },\n {\n dependencies: PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES,\n python: pyenvPythonVersion(),\n },\n ];\n for (const { dependencies, python } of environments) {\n const deps = [...dependencies, PY_VERIFIER_TYPE_CHECKER].flatMap((spec) => [\n '--with',\n spec,\n ]);\n const interpreter = python ? ['--python', python] : [];\n try {\n execFileSync('uv', ['run', ...interpreter, ...deps, 'python', '-c', ''], {\n stdio: 'ignore',\n });\n } catch (error) {\n console.warn(\n `Could not warm uv's cache, so each Python worker will install its own ` +\n `dependencies and may time out starting up: ${error}`,\n );\n }\n }\n}\n"],"names":["execFileSync","pyenvPythonVersion","PY_AGENT_GUARDRAIL_VERIFIER_DEPENDENCIES","PY_CLIENT_VERIFIER_DEPENDENCIES","PY_DYNAMODB_VERIFIER_DEPENDENCIES","PY_VERIFIER_TYPE_CHECKER","setup","environments","dependencies","python","deps","flatMap","spec","interpreter","stdio","error","console","warn"],"mappings":"AAAA;;;CAGC,GACD,SAASA,YAAY,QAAQ,gBAAgB;AAC7C,SAASC,kBAAkB,QAAQ,iBAAiB;AACpD,SACEC,wCAAwC,EACxCC,+BAA+B,EAC/BC,iCAAiC,EACjCC,wBAAwB,QACnB,2BAA2B;AAElC;;;;;;;;;;;;;;;;CAgBC,GACD,eAAe,SAASC;IACtB,6EAA6E;IAC7E,6EAA6E;IAC7E,kDAAkD;IAClD,MAAMC,eAA8D;QAClE;YAAEC,cAAcL;QAAgC;QAChD;YACEK,cAAcJ;YACdK,QAAQR;QACV;QACA;YACEO,cAAcN;YACdO,QAAQR;QACV;KACD;IACD,KAAK,MAAM,EAAEO,YAAY,EAAEC,MAAM,EAAE,IAAIF,aAAc;QACnD,MAAMG,OAAO;eAAIF;YAAcH;SAAyB,CAACM,OAAO,CAAC,CAACC,OAAS;gBACzE;gBACAA;aACD;QACD,MAAMC,cAAcJ,SAAS;YAAC;YAAYA;SAAO,GAAG,EAAE;QACtD,IAAI;YACFT,aAAa,MAAM;gBAAC;mBAAUa;mBAAgBH;gBAAM;gBAAU;gBAAM;aAAG,EAAE;gBACvEI,OAAO;YACT;QACF,EAAE,OAAOC,OAAO;YACdC,QAAQC,IAAI,CACV,CAAC,sEAAsE,CAAC,GACtE,CAAC,2CAA2C,EAAEF,OAAO;QAE3D;IACF;AACF"}