@aws/nx-plugin 1.0.0-rc.91 → 1.0.0-rc.92

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 (79) hide show
  1. package/migrations.json +6 -1
  2. package/package.json +1 -1
  3. package/src/internal/test-matrix/generator.js +28 -0
  4. package/src/internal/test-matrix/generator.js.map +1 -1
  5. package/src/migrations/latest/react-website-unique-dev-ports/metadata.json +3 -0
  6. package/src/migrations/latest/react-website-unique-dev-ports/migration.d.ts +6 -0
  7. package/src/migrations/latest/react-website-unique-dev-ports/migration.js +79 -0
  8. package/src/migrations/latest/react-website-unique-dev-ports/migration.js.map +1 -0
  9. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +90 -115
  10. package/src/py/agent/files/package/main.py.template +13 -0
  11. package/src/py/agent/generator.d.ts +6 -1
  12. package/src/py/agent/generator.js +82 -45
  13. package/src/py/agent/generator.js.map +1 -1
  14. package/src/py/agent/schema.d.js.map +1 -1
  15. package/src/py/agent/schema.d.ts +2 -1
  16. package/src/py/agent/schema.json +2 -2
  17. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +64 -113
  18. package/src/py/mcp-server/files/package/main.py.template +13 -0
  19. package/src/py/mcp-server/generator.d.ts +6 -1
  20. package/src/py/mcp-server/generator.js +79 -43
  21. package/src/py/mcp-server/generator.js.map +1 -1
  22. package/src/py/mcp-server/schema.d.js.map +1 -1
  23. package/src/py/mcp-server/schema.d.ts +2 -1
  24. package/src/py/mcp-server/schema.json +2 -2
  25. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +12 -59
  26. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +77 -114
  27. package/src/ts/agent/generator.d.ts +26 -1
  28. package/src/ts/agent/generator.js +71 -45
  29. package/src/ts/agent/generator.js.map +1 -1
  30. package/src/ts/agent/schema.d.js.map +1 -1
  31. package/src/ts/agent/schema.d.ts +2 -1
  32. package/src/ts/agent/schema.json +2 -2
  33. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +64 -113
  34. package/src/ts/mcp-server/generator.d.ts +26 -1
  35. package/src/ts/mcp-server/generator.js +66 -38
  36. package/src/ts/mcp-server/generator.js.map +1 -1
  37. package/src/ts/mcp-server/schema.d.js.map +1 -1
  38. package/src/ts/mcp-server/schema.d.ts +2 -1
  39. package/src/ts/mcp-server/schema.json +2 -2
  40. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +16 -110
  41. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +2 -0
  42. package/src/ts/react-website/app/generator.js +16 -0
  43. package/src/ts/react-website/app/generator.js.map +1 -1
  44. package/src/ts/react-website/cognito-auth/generator.js +14 -2
  45. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  46. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +25 -6
  47. package/src/utils/agent-core-constructs/agent-core-constructs.js +36 -7
  48. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  49. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +20 -4
  50. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +34 -1
  51. package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +51 -112
  52. package/src/utils/agent-core-constructs/files/terraform/core/agent-core-code/runtime.tf.template +204 -0
  53. package/src/utils/agent-core-constructs/files/terraform/core/agent-core-container/runtime.tf.template +235 -0
  54. package/src/utils/agent-core-packaging.d.ts +119 -0
  55. package/src/utils/agent-core-packaging.js +131 -0
  56. package/src/utils/agent-core-packaging.js.map +1 -0
  57. package/src/utils/agent-core-runtime-resolution.d.ts +35 -0
  58. package/src/utils/agent-core-runtime-resolution.js +68 -0
  59. package/src/utils/agent-core-runtime-resolution.js.map +1 -0
  60. package/src/utils/files/terraform/src/core/asset-ecr/asset-ecr.tf.template +137 -0
  61. package/src/utils/identity-constructs/files/cdk/core/user-identity.ts.template +1 -1
  62. package/src/utils/identity-constructs/files/terraform/core/user-identity/identity/identity.tf.template +1 -4
  63. package/src/utils/identity-constructs/identity-constructs.d.ts +22 -2
  64. package/src/utils/identity-constructs/identity-constructs.js +75 -5
  65. package/src/utils/identity-constructs/identity-constructs.js.map +1 -1
  66. package/src/utils/port.d.ts +5 -0
  67. package/src/utils/port.js +1 -1
  68. package/src/utils/port.js.map +1 -1
  69. package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +12 -59
  70. package/src/utils/versions.d.ts +20 -0
  71. package/src/utils/versions.js +17 -0
  72. package/src/utils/versions.js.map +1 -1
  73. /package/src/ts/mcp-server/files/{http.ts.template → app/http.ts.template} +0 -0
  74. /package/src/ts/mcp-server/files/{index.ts.template → app/index.ts.template} +0 -0
  75. /package/src/ts/mcp-server/files/{resources → app/resources}/sample-guidance.ts.template +0 -0
  76. /package/src/ts/mcp-server/files/{server.ts.template → app/server.ts.template} +0 -0
  77. /package/src/ts/mcp-server/files/{stdio.ts.template → app/stdio.ts.template} +0 -0
  78. /package/src/ts/mcp-server/files/{tools → app/tools}/divide.ts.template +0 -0
  79. /package/src/ts/mcp-server/files/{Dockerfile.template → deploy/Dockerfile.template} +0 -0
@@ -60,6 +60,16 @@ variable "appconfig_application_id" {
60
60
  type = string
61
61
  }
62
62
 
63
+ variable "asset_ecr_repository_url" {
64
+ description = "URL of the shared asset ECR repository the agent's image is published to. Instantiate the \`core/asset-ecr\` module once per deployment and pass its \`repository_url\` output here."
65
+ type = string
66
+ }
67
+
68
+ variable "asset_ecr_repository_arn" {
69
+ description = "ARN of the shared asset ECR repository (from \`core/asset-ecr.repository_arn\`), used to scope the runtime's image pull grant to it."
70
+ type = string
71
+ }
72
+
63
73
  variable "session_force_destroy" {
64
74
  description = "Whether to allow the session bucket to be destroyed even if it still contains objects."
65
75
  type = bool
@@ -255,9 +265,11 @@ resource "aws_dynamodb_table" "session" {
255
265
  }
256
266
 
257
267
  module "agent_core_runtime" {
258
- source = "../../../core/agent-core"
268
+ source = "../../../core/agent-core-container"
259
269
  agent_runtime_name = "DynamodbTerraformAgent"
260
270
  docker_image_tag = "proj-dynamodb-terraform-agent:latest"
271
+ asset_ecr_repository_url = var.asset_ecr_repository_url
272
+ asset_ecr_repository_arn = var.asset_ecr_repository_arn
261
273
  server_protocol = "HTTP"
262
274
  enable_vpc = var.enable_vpc
263
275
  vpc_id = var.vpc_id
@@ -424,6 +436,16 @@ variable "appconfig_application_id" {
424
436
  type = string
425
437
  }
426
438
 
439
+ variable "asset_ecr_repository_url" {
440
+ description = "URL of the shared asset ECR repository the agent's image is published to. Instantiate the \`core/asset-ecr\` module once per deployment and pass its \`repository_url\` output here."
441
+ type = string
442
+ }
443
+
444
+ variable "asset_ecr_repository_arn" {
445
+ description = "ARN of the shared asset ECR repository (from \`core/asset-ecr.repository_arn\`), used to scope the runtime's image pull grant to it."
446
+ type = string
447
+ }
448
+
427
449
  variable "session_force_destroy" {
428
450
  description = "Whether to allow the session bucket to be destroyed even if it still contains objects."
429
451
  type = bool
@@ -576,9 +598,11 @@ resource "aws_cloudwatch_log_delivery" "session" {
576
598
  }
577
599
 
578
600
  module "agent_core_runtime" {
579
- source = "../../../core/agent-core"
601
+ source = "../../../core/agent-core-container"
580
602
  agent_runtime_name = "TerraformSnapshotAgent"
581
603
  docker_image_tag = "proj-terraform-snapshot-agent:latest"
604
+ asset_ecr_repository_url = var.asset_ecr_repository_url
605
+ asset_ecr_repository_arn = var.asset_ecr_repository_arn
582
606
  server_protocol = "HTTP"
583
607
  enable_vpc = var.enable_vpc
584
608
  vpc_id = var.vpc_id
@@ -682,10 +706,6 @@ exports[`py#agent generator > should match snapshot for Terraform generated file
682
706
  source = "hashicorp/aws"
683
707
  version = "6.62.0"
684
708
  }
685
- external = {
686
- source = "hashicorp/external"
687
- version = "2.4.1"
688
- }
689
709
  null = {
690
710
  source = "hashicorp/null"
691
711
  version = "3.3.1"
@@ -729,9 +749,36 @@ variable "authorizer_configuration" {
729
749
  default = null
730
750
  }
731
751
 
732
- variable "docker_image_tag" {
733
- description = "Name of the docker image tag to use as the agent core runtime"
734
- type = string
752
+ variable "container_configuration" {
753
+ description = "Container artifact for this runtime. Set exactly one of this or \`code_configuration\`; the \`agent-core-container\` module renders it."
754
+ type = object({
755
+ container_uri = string
756
+ })
757
+ default = null
758
+ }
759
+
760
+ variable "code_configuration" {
761
+ description = "Code artifact for this runtime. Set exactly one of this or \`container_configuration\`; the \`agent-core-code\` module renders it."
762
+ type = object({
763
+ entry_point = list(string)
764
+ runtime = string
765
+ s3_bucket = string
766
+ s3_key = string
767
+ })
768
+ default = null
769
+
770
+ validation {
771
+ # Evaluated at plan time, since Terraform defers validation that reads
772
+ # another variable.
773
+ condition = (var.code_configuration == null) != (var.container_configuration == null)
774
+ error_message = "Set exactly one of code_configuration or container_configuration."
775
+ }
776
+ }
777
+
778
+ variable "artifact_dependencies" {
779
+ description = "Resources the artifact is produced by (an image push or a code upload), so the runtime is created only once they exist."
780
+ type = list(any)
781
+ default = []
735
782
  }
736
783
 
737
784
  variable "env" {
@@ -794,47 +841,6 @@ resource "random_id" "unique_suffix" {
794
841
  byte_length = 4
795
842
  }
796
843
 
797
- # ECR Repository
798
- resource "aws_ecr_repository" "agent_core_repository" {
799
- #checkov:skip=CKV_AWS_136:AES256 encryption is sufficient for ECR repositories
800
- name = "\${lower(var.agent_runtime_name)}_repository_\${random_id.unique_suffix.hex}"
801
-
802
- image_tag_mutability = "IMMUTABLE"
803
- force_delete = true
804
-
805
- image_scanning_configuration {
806
- scan_on_push = true
807
- }
808
-
809
- tags = var.tags
810
- }
811
-
812
- # ECR Repository Policy
813
- resource "aws_ecr_repository_policy" "agent_core_ecr_policy" {
814
- repository = aws_ecr_repository.agent_core_repository.name
815
-
816
- policy = jsonencode({
817
- Version = "2012-10-17"
818
- Statement = [
819
- {
820
- Sid = "AllowPushPull"
821
- Effect = "Allow"
822
- Principal = {
823
- AWS = "arn:aws:iam::\${local.aws_account_id}:root"
824
- }
825
- Action = [
826
- "ecr:GetDownloadUrlForLayer",
827
- "ecr:BatchGetImage",
828
- "ecr:BatchCheckLayerAvailability",
829
- "ecr:PutImage",
830
- "ecr:InitiateLayerUpload",
831
- "ecr:UploadLayerPart",
832
- "ecr:CompleteLayerUpload"
833
- ]
834
- }
835
- ]
836
- })
837
- }
838
844
 
839
845
  # IAM Role for Agent Core Runtime
840
846
  resource "aws_iam_role" "agent_core_runtime_role" {
@@ -873,27 +879,6 @@ resource "aws_iam_policy" "agent_core_runtime_policy" {
873
879
  policy = jsonencode({
874
880
  Version = "2012-10-17"
875
881
  Statement = concat([
876
- {
877
- Sid = "ECRImageAccess"
878
- Effect = "Allow"
879
- Action = [
880
- "ecr:BatchGetImage",
881
- "ecr:GetDownloadUrlForLayer"
882
- ]
883
- Resource = [
884
- aws_ecr_repository.agent_core_repository.arn
885
- ]
886
- },
887
- {
888
- Sid = "ECRTokenAccess"
889
- Effect = "Allow"
890
- Action = [
891
- "ecr:GetAuthorizationToken"
892
- ]
893
- Resource = [
894
- "*"
895
- ]
896
- },
897
882
  {
898
883
  "Effect" : "Allow",
899
884
  "Action" : [
@@ -968,46 +953,6 @@ resource "aws_iam_role_policy_attachment" "agent_core_policy" {
968
953
  policy_arn = aws_iam_policy.agent_core_runtime_policy.arn
969
954
  }
970
955
 
971
- # Data source to get container image digest
972
- data "external" "docker_digest" {
973
- program = ["sh", "-c", "echo '{\\"digest\\":\\"'$(docker inspect \${var.docker_image_tag} --format '{{.Id}}')'\\"}' "]
974
- }
975
-
976
- locals {
977
- # Content-based, immutable image tag derived from the local image digest
978
- image_tag = replace(data.external.docker_digest.result.digest, "sha256:", "")
979
- }
980
-
981
- # Null resource for container image publish
982
- resource "null_resource" "docker_publish" {
983
- triggers = {
984
- docker_digest = data.external.docker_digest.result.digest
985
- repository_url = aws_ecr_repository.agent_core_repository.repository_url
986
- docker_image_tag = var.docker_image_tag
987
- image_tag = local.image_tag
988
- }
989
-
990
- provisioner "local-exec" {
991
- command = <<-EOT
992
- # Get ECR login token
993
- aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$REPOSITORY_URL"
994
-
995
- # Tag the image with the immutable content-based tag
996
- docker tag "$DOCKER_IMAGE_TAG" "$REPOSITORY_URL:$IMAGE_TAG"
997
-
998
- # Push the image
999
- docker push "$REPOSITORY_URL:$IMAGE_TAG"
1000
- EOT
1001
- environment = {
1002
- AWS_REGION = local.aws_region
1003
- REPOSITORY_URL = self.triggers.repository_url
1004
- DOCKER_IMAGE_TAG = self.triggers.docker_image_tag
1005
- IMAGE_TAG = self.triggers.image_tag
1006
- }
1007
- }
1008
-
1009
- depends_on = [aws_ecr_repository_policy.agent_core_ecr_policy]
1010
- }
1011
956
 
1012
957
  # Security group for the agent core runtime, used when running inside a VPC
1013
958
  resource "aws_security_group" "agent_core_runtime" {
@@ -1038,8 +983,26 @@ resource "aws_bedrockagentcore_agent_runtime" "agent_runtime" {
1038
983
  role_arn = aws_iam_role.agent_core_runtime_role.arn
1039
984
 
1040
985
  agent_runtime_artifact {
1041
- container_configuration {
1042
- container_uri = "\${aws_ecr_repository.agent_core_repository.repository_url}:\${local.image_tag}"
986
+ dynamic "container_configuration" {
987
+ for_each = var.container_configuration != null ? [var.container_configuration] : []
988
+ content {
989
+ container_uri = container_configuration.value.container_uri
990
+ }
991
+ }
992
+
993
+ dynamic "code_configuration" {
994
+ for_each = var.code_configuration != null ? [var.code_configuration] : []
995
+ content {
996
+ entry_point = code_configuration.value.entry_point
997
+ runtime = code_configuration.value.runtime
998
+
999
+ code {
1000
+ s3 {
1001
+ bucket = code_configuration.value.s3_bucket
1002
+ prefix = code_configuration.value.s3_key
1003
+ }
1004
+ }
1005
+ }
1043
1006
  }
1044
1007
  }
1045
1008
 
@@ -1083,7 +1046,7 @@ resource "aws_bedrockagentcore_agent_runtime" "agent_runtime" {
1083
1046
  tags = var.tags
1084
1047
 
1085
1048
  depends_on = [
1086
- null_resource.docker_publish,
1049
+ var.artifact_dependencies,
1087
1050
  aws_iam_role_policy_attachment.agent_core_policy
1088
1051
  ]
1089
1052
  }
@@ -1241,15 +1204,27 @@ variable "appconfig_application_id" {
1241
1204
  type = string
1242
1205
  }
1243
1206
 
1207
+ variable "asset_ecr_repository_url" {
1208
+ description = "URL of the shared asset ECR repository the agent's image is published to. Instantiate the \`core/asset-ecr\` module once per deployment and pass its \`repository_url\` output here."
1209
+ type = string
1210
+ }
1211
+
1212
+ variable "asset_ecr_repository_arn" {
1213
+ description = "ARN of the shared asset ECR repository (from \`core/asset-ecr.repository_arn\`), used to scope the runtime's image pull grant to it."
1214
+ type = string
1215
+ }
1216
+
1244
1217
  variable "appconfig_application_arn" {
1245
1218
  description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the agent runtime."
1246
1219
  type = string
1247
1220
  }
1248
1221
 
1249
1222
  module "agent_core_runtime" {
1250
- source = "../../../core/agent-core"
1223
+ source = "../../../core/agent-core-container"
1251
1224
  agent_runtime_name = "InMemoryTerraformAgent"
1252
1225
  docker_image_tag = "proj-in-memory-terraform-agent:latest"
1226
+ asset_ecr_repository_url = var.asset_ecr_repository_url
1227
+ asset_ecr_repository_arn = var.asset_ecr_repository_arn
1253
1228
  server_protocol = "HTTP"
1254
1229
  enable_vpc = var.enable_vpc
1255
1230
  vpc_id = var.vpc_id
@@ -0,0 +1,13 @@
1
+ """AgentCore Runtime entry point.
2
+
3
+ Runs at the root of the deployment package, where the managed runtime executes
4
+ it by file path. The agent is imported absolutely so its own relative imports
5
+ resolve.
6
+ """
7
+
8
+ import uvicorn
9
+
10
+ from <%- moduleName %>.<%- agentNameSnakeCase %>.main import app
11
+
12
+ if __name__ == "__main__":
13
+ uvicorn.run(app, host="0.0.0.0", port=<%- port %>)
@@ -5,7 +5,7 @@
5
5
  import { type GeneratorCallback, type Tree } from '@nx/devkit';
6
6
  import { type NxGeneratorInfo } from '../../utils/nx.js';
7
7
  import type { IacMetadata } from '../../utils/shared-constructs-constants.js';
8
- import type { AgentProtocol, PyAgentFramework, PyAgentGeneratorSchema, PyAgentSession } from './schema';
8
+ import type { AgentProtocol, PyAgentFramework, PyAgentGeneratorSchema, PyAgentInfra, PyAgentSession } from './schema';
9
9
  /** The metadata this generator records, which its predicates read. */
10
10
  export interface PyAgentMetadata extends IacMetadata {
11
11
  readonly port: number;
@@ -18,6 +18,11 @@ export interface PyAgentMetadata extends IacMetadata {
18
18
  */
19
19
  readonly framework: PyAgentFramework;
20
20
  readonly session: PyAgentSession;
21
+ /**
22
+ * How this component is packaged and hosted, so a consumer can tell a
23
+ * code-packaged runtime from a container-packaged one without re-deriving it.
24
+ */
25
+ readonly infra: PyAgentInfra;
21
26
  }
22
27
  export declare const DEPENDENCIES: import("../../utils/declared-dependencies.js").DependencyDeclaration<readonly [{
23
28
  readonly name: "agent-chat-cli";
@@ -8,6 +8,7 @@ import { addPyDependencies, addTsDependencies } from "../../utils/add-dependenci
8
8
  import { addAgentChatScripts } from "../../utils/agent-chat/agent-chat.js";
9
9
  import { AGENT_CONNECTION_PY_DEPENDENCIES, addPythonFrameworkBase, ensureLangchainS3CheckpointSaver, ensurePythonAgentConnectionProject, getPythonAgentConnectionModuleName, getPythonAgentConnectionProject } from "../../utils/agent-connection/agent-connection.js";
10
10
  import { addAgentInfra } from "../../utils/agent-core-constructs/agent-core-constructs.js";
11
+ import { addPythonCodePackageTarget, agentCorePythonRuntime, isAgentCoreHosted, isContainerHosted } from "../../utils/agent-core-packaging.js";
11
12
  import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
12
13
  import { resolveContainers } from "../../utils/containers.js";
13
14
  import { declareDependencies, ownedElsewhere } from "../../utils/declared-dependencies.js";
@@ -289,55 +290,91 @@ export const pyAgentGenerator = async (tree, options)=>{
289
290
  generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', framework, protocolLower), targetSourceDir, templateContext, {
290
291
  overwriteStrategy: OverwriteStrategy.KeepExisting
291
292
  });
292
- if (infra === 'agentcore') {
293
+ if (isAgentCoreHosted(infra)) {
294
+ const container = isContainerHosted(infra);
293
295
  const containers = await resolveContainers(tree, 'inherit');
294
296
  const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;
295
297
  // Add bundle target
296
298
  const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(project, {
297
299
  pythonPlatform: 'aarch64-manylinux_2_28'
298
300
  });
299
- // Add the Dockerfile
300
- generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'deploy'), targetSourceDir, {
301
- agentNameSnakeCase,
302
- moduleName,
303
- bundleOutputDir,
304
- protocol,
305
- pythonBaseImage: BASE_IMAGES.python
306
- }, {
307
- overwriteStrategy: OverwriteStrategy.KeepExisting
308
- });
309
- const dockerOutputDir = joinPathFragments('dist', project.root, 'docker', name);
310
- const dockerTargetName = `${agentTargetPrefix}-docker`;
311
- // Add a docker target that prepares the docker context and builds the image
312
- const fs = new FsCommands(tree, DEPENDENCIES);
313
- project.targets[dockerTargetName] = {
314
- cache: IMAGE_BUILD_CACHE,
315
- executor: 'nx:run-commands',
316
- options: {
317
- commands: [
318
- fs.rm(dockerOutputDir),
319
- fs.mkdir(dockerOutputDir),
320
- fs.cp(bundleOutputDir, dockerOutputDir),
321
- fs.cp(`${targetSourceDir}/Dockerfile`, `${dockerOutputDir}/Dockerfile`),
322
- `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`
323
- ],
324
- parallel: false
325
- },
326
- dependsOn: [
327
- bundleTargetName
328
- ]
329
- };
330
- addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);
331
- addArtifactDependencyToTargets(project, 'docker');
332
- addDockerScanTarget(tree, {
333
- project,
334
- containerEngine: containers,
335
- trivyTargetName: `${agentTargetPrefix}-trivy`,
336
- dockerTargetName,
337
- imageTags: [
338
- dockerImageTag
339
- ]
340
- }, DEPENDENCIES);
301
+ let artifact;
302
+ if (container) {
303
+ // Add the Dockerfile
304
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'deploy'), targetSourceDir, {
305
+ agentNameSnakeCase,
306
+ moduleName,
307
+ bundleOutputDir,
308
+ protocol,
309
+ pythonBaseImage: BASE_IMAGES.python
310
+ }, {
311
+ overwriteStrategy: OverwriteStrategy.KeepExisting
312
+ });
313
+ const dockerOutputDir = joinPathFragments('dist', project.root, 'docker', name);
314
+ const dockerTargetName = `${agentTargetPrefix}-docker`;
315
+ // Add a docker target that prepares the docker context and builds the image
316
+ const fs = new FsCommands(tree, DEPENDENCIES);
317
+ project.targets[dockerTargetName] = {
318
+ cache: IMAGE_BUILD_CACHE,
319
+ executor: 'nx:run-commands',
320
+ options: {
321
+ commands: [
322
+ fs.rm(dockerOutputDir),
323
+ fs.mkdir(dockerOutputDir),
324
+ fs.cp(bundleOutputDir, dockerOutputDir),
325
+ fs.cp(`${targetSourceDir}/Dockerfile`, `${dockerOutputDir}/Dockerfile`),
326
+ `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`
327
+ ],
328
+ parallel: false
329
+ },
330
+ dependsOn: [
331
+ bundleTargetName
332
+ ]
333
+ };
334
+ addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);
335
+ addArtifactDependencyToTargets(project, 'docker');
336
+ addDockerScanTarget(tree, {
337
+ project,
338
+ containerEngine: containers,
339
+ trivyTargetName: `${agentTargetPrefix}-trivy`,
340
+ dockerTargetName,
341
+ imageTags: [
342
+ dockerImageTag
343
+ ]
344
+ }, DEPENDENCIES);
345
+ artifact = {
346
+ type: 'container',
347
+ dockerImageTag,
348
+ outputDir: dockerOutputDir
349
+ };
350
+ } else {
351
+ // The entry point the managed runtime runs, at the package root.
352
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'package'), joinPathFragments(project.root, 'package', agentNameSnakeCase), {
353
+ agentNameSnakeCase,
354
+ moduleName,
355
+ port: protocol === 'a2a' ? 9000 : 8080
356
+ }, {
357
+ overwriteStrategy: OverwriteStrategy.KeepExisting
358
+ });
359
+ const packageOutputDir = joinPathFragments('dist', project.root, 'package', name);
360
+ addPythonCodePackageTarget(tree, {
361
+ project,
362
+ targetName: `${agentTargetPrefix}-package`,
363
+ bundleTargetName,
364
+ bundleOutputDir,
365
+ packageOutputDir,
366
+ sourceRoot: project.sourceRoot,
367
+ moduleName,
368
+ entryPointPath: joinPathFragments(project.root, 'package', agentNameSnakeCase, 'main.py'),
369
+ entryPointFileName: 'main.py'
370
+ }, DEPENDENCIES);
371
+ artifact = {
372
+ type: 'code',
373
+ outputDir: packageOutputDir,
374
+ runtime: agentCorePythonRuntime(),
375
+ entryPoint: 'main.py'
376
+ };
377
+ }
341
378
  // Add shared constructs
342
379
  await sharedConstructsGenerator(tree, {
343
380
  iac
@@ -348,8 +385,7 @@ export const pyAgentGenerator = async (tree, options)=>{
348
385
  await addAgentInfra(tree, {
349
386
  agentNameKebabCase: name,
350
387
  agentNameClassName,
351
- dockerImageTag,
352
- dockerOutputDir,
388
+ artifact,
353
389
  iac,
354
390
  projectName: project.name,
355
391
  auth,
@@ -370,6 +406,7 @@ export const pyAgentGenerator = async (tree, options)=>{
370
406
  // Recorded below and read by the declaration's predicates, so the packages
371
407
  // added here are exactly the ones the version sync will own.
372
408
  const metadata = {
409
+ infra,
373
410
  port: localDevPort,
374
411
  rc: agentNameClassName,
375
412
  auth,