@aws/nx-plugin 1.0.0-rc.89 → 1.0.0-rc.90

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 (148) hide show
  1. package/README.md +22 -22
  2. package/executors.json +5 -0
  3. package/generators.json +2 -1
  4. package/migrations.json +47 -2
  5. package/package.json +1 -1
  6. package/src/infra/app/__snapshots__/generator.spec.ts.snap +24 -12
  7. package/src/infra/app/generator.js +9 -7
  8. package/src/infra/app/generator.js.map +1 -1
  9. package/src/mcp-server/generator-info.d.ts +5 -0
  10. package/src/mcp-server/generator-info.js +6 -2
  11. package/src/mcp-server/generator-info.js.map +1 -1
  12. package/src/migrations/latest/add-assemble-target/metadata.json +3 -0
  13. package/src/migrations/latest/add-assemble-target/migration.d.ts +6 -0
  14. package/src/migrations/latest/add-assemble-target/migration.js +241 -0
  15. package/src/migrations/latest/add-assemble-target/migration.js.map +1 -0
  16. package/src/migrations/latest/declare-cacheable-target-inputs/metadata.json +3 -0
  17. package/src/migrations/latest/declare-cacheable-target-inputs/migration.d.ts +6 -0
  18. package/src/migrations/latest/declare-cacheable-target-inputs/migration.js +94 -0
  19. package/src/migrations/latest/declare-cacheable-target-inputs/migration.js.map +1 -0
  20. package/src/migrations/latest/dev-target-depends-on-pull-image/metadata.json +3 -0
  21. package/src/migrations/latest/dev-target-depends-on-pull-image/migration.d.ts +6 -0
  22. package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js +67 -0
  23. package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js.map +1 -0
  24. package/src/migrations/latest/docker-target-cache-soundness/metadata.json +3 -0
  25. package/src/migrations/latest/docker-target-cache-soundness/migration.d.ts +6 -0
  26. package/src/migrations/latest/docker-target-cache-soundness/migration.js +95 -0
  27. package/src/migrations/latest/docker-target-cache-soundness/migration.js.map +1 -0
  28. package/src/migrations/latest/open-api-codegen-executor/metadata.json +3 -0
  29. package/src/migrations/latest/open-api-codegen-executor/migration.d.ts +6 -0
  30. package/src/migrations/latest/open-api-codegen-executor/migration.js +100 -0
  31. package/src/migrations/latest/open-api-codegen-executor/migration.js.map +1 -0
  32. package/src/migrations/latest/python-test-input-scoping/metadata.json +3 -0
  33. package/src/migrations/latest/python-test-input-scoping/migration.d.ts +6 -0
  34. package/src/migrations/latest/python-test-input-scoping/migration.js +142 -0
  35. package/src/migrations/latest/python-test-input-scoping/migration.js.map +1 -0
  36. package/src/migrations/latest/terraform-fmt-check/metadata.json +3 -0
  37. package/src/migrations/latest/terraform-fmt-check/migration.d.ts +6 -0
  38. package/src/migrations/latest/terraform-fmt-check/migration.js +165 -0
  39. package/src/migrations/latest/terraform-fmt-check/migration.js.map +1 -0
  40. package/src/migrations/latest/terraform-provider-plugin-cache/metadata.json +3 -0
  41. package/src/migrations/latest/terraform-provider-plugin-cache/migration.d.ts +6 -0
  42. package/src/migrations/latest/terraform-provider-plugin-cache/migration.js +164 -0
  43. package/src/migrations/latest/terraform-provider-plugin-cache/migration.js.map +1 -0
  44. package/src/migrations/latest/vitest-coverage-output-dir/metadata.json +3 -0
  45. package/src/migrations/latest/vitest-coverage-output-dir/migration.d.ts +6 -0
  46. package/src/migrations/latest/vitest-coverage-output-dir/migration.js +177 -0
  47. package/src/migrations/latest/vitest-coverage-output-dir/migration.js.map +1 -0
  48. package/src/open-api/codegen/executor-schema.d.js +6 -0
  49. package/src/open-api/codegen/executor-schema.d.js.map +1 -0
  50. package/src/open-api/codegen/executor-schema.d.ts +18 -0
  51. package/src/open-api/codegen/executor-schema.json +33 -0
  52. package/src/open-api/codegen/executor.d.ts +18 -0
  53. package/src/open-api/codegen/executor.js +56 -0
  54. package/src/open-api/codegen/executor.js.map +1 -0
  55. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -1
  56. package/src/py/agent/generator.js +21 -22
  57. package/src/py/agent/generator.js.map +1 -1
  58. package/src/py/agent/react-connection/generator.js +9 -0
  59. package/src/py/agent/react-connection/generator.js.map +1 -1
  60. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +0 -30
  61. package/src/py/fast-api/react/open-api.js +19 -7
  62. package/src/py/fast-api/react/open-api.js.map +1 -1
  63. package/src/py/mcp-server/generator.js +4 -4
  64. package/src/py/mcp-server/generator.js.map +1 -1
  65. package/src/py/project/generator.d.ts +9 -0
  66. package/src/py/project/generator.js +51 -1
  67. package/src/py/project/generator.js.map +1 -1
  68. package/src/py/rdb/generator.js +10 -4
  69. package/src/py/rdb/generator.js.map +1 -1
  70. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +15 -0
  71. package/src/smithy/project/generator.js +10 -0
  72. package/src/smithy/project/generator.js.map +1 -1
  73. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +7 -0
  74. package/src/terraform/project/files/application/scripts/env.ts.template +11 -0
  75. package/src/terraform/project/files/application/scripts/init.ts.template +2 -1
  76. package/src/terraform/project/files/application/src/providers.tf.template +2 -2
  77. package/src/terraform/project/generator.d.ts +11 -1
  78. package/src/terraform/project/generator.js +104 -20
  79. package/src/terraform/project/generator.js.map +1 -1
  80. package/src/trpc/backend/generator.js +2 -2
  81. package/src/trpc/backend/generator.js.map +1 -1
  82. package/src/ts/agent/generator.js +4 -7
  83. package/src/ts/agent/generator.js.map +1 -1
  84. package/src/ts/astro-docs/generator.js +5 -0
  85. package/src/ts/astro-docs/generator.js.map +1 -1
  86. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +0 -30
  87. package/src/ts/dynamodb/generator.js +3 -0
  88. package/src/ts/dynamodb/generator.js.map +1 -1
  89. package/src/ts/lib/__snapshots__/generator.spec.ts.snap +10 -1
  90. package/src/ts/lib/__snapshots__/vitest.spec.ts.snap +1 -1
  91. package/src/ts/lib/generator.d.ts +16 -0
  92. package/src/ts/lib/generator.js +31 -5
  93. package/src/ts/lib/generator.js.map +1 -1
  94. package/src/ts/lib/vitest.d.ts +11 -0
  95. package/src/ts/lib/vitest.js +31 -2
  96. package/src/ts/lib/vitest.js.map +1 -1
  97. package/src/ts/mcp-server/generator.js +4 -7
  98. package/src/ts/mcp-server/generator.js.map +1 -1
  99. package/src/ts/rdb/generator.js +8 -5
  100. package/src/ts/rdb/generator.js.map +1 -1
  101. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +27 -11
  102. package/src/ts/react-website/app/generator.js +9 -1
  103. package/src/ts/react-website/app/generator.js.map +1 -1
  104. package/src/ts/sync/generator.js +19 -2
  105. package/src/ts/sync/generator.js.map +1 -1
  106. package/src/utils/agent-core-constructs/agent-core-constructs.js +3 -3
  107. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  108. package/src/utils/api-constructs/api-constructs.js +2 -2
  109. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  110. package/src/utils/api-constructs/open-api-metadata.js +15 -36
  111. package/src/utils/api-constructs/open-api-metadata.js.map +1 -1
  112. package/src/utils/api-constructs/trpc-operations-metadata.js +9 -3
  113. package/src/utils/api-constructs/trpc-operations-metadata.js.map +1 -1
  114. package/src/utils/bundle/bundle.js +13 -4
  115. package/src/utils/bundle/bundle.js.map +1 -1
  116. package/src/utils/connection/open-api/react.js +7 -17
  117. package/src/utils/connection/open-api/react.js.map +1 -1
  118. package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js +2 -2
  119. package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js.map +1 -1
  120. package/src/utils/docker.d.ts +22 -10
  121. package/src/utils/docker.js +27 -17
  122. package/src/utils/docker.js.map +1 -1
  123. package/src/utils/dynamodb-constructs/dynamodb-constructs.js +2 -2
  124. package/src/utils/dynamodb-constructs/dynamodb-constructs.js.map +1 -1
  125. package/src/utils/files/common/scripts/src/dynamodb/start-container.ts.template +0 -15
  126. package/src/utils/files/common/scripts/src/rdb/shared/start-container.ts.template +0 -15
  127. package/src/utils/format.d.ts +5 -0
  128. package/src/utils/format.js +5 -0
  129. package/src/utils/format.js.map +1 -1
  130. package/src/utils/function-constructs/function-constructs.js +2 -2
  131. package/src/utils/function-constructs/function-constructs.js.map +1 -1
  132. package/src/utils/generators.d.ts +33 -0
  133. package/src/utils/generators.js +18 -3
  134. package/src/utils/generators.js.map +1 -1
  135. package/src/utils/init.js +4 -6
  136. package/src/utils/init.js.map +1 -1
  137. package/src/utils/mock-project-graph.js +5 -2
  138. package/src/utils/mock-project-graph.js.map +1 -1
  139. package/src/utils/nx.d.ts +19 -0
  140. package/src/utils/nx.js +23 -0
  141. package/src/utils/nx.js.map +1 -1
  142. package/src/utils/open-api-codegen-target.d.ts +28 -0
  143. package/src/utils/open-api-codegen-target.js +31 -0
  144. package/src/utils/open-api-codegen-target.js.map +1 -0
  145. package/src/utils/rdb-constructs/rdb-constructs.js +2 -2
  146. package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
  147. package/src/utils/website-constructs/website-constructs.js +2 -2
  148. package/src/utils/website-constructs/website-constructs.js.map +1 -1
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ /** Which code the executor generates from an OpenAPI specification. */ export { };
5
+
6
+ //# sourceMappingURL=executor-schema.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/open-api/codegen/executor-schema.d.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/** Which code the executor generates from an OpenAPI specification. */\nexport type OpenApiCodegenTarget =\n | 'ts-client'\n | 'ts-hooks'\n | 'ts-metadata'\n | 'json-metadata';\n\nexport interface OpenApiCodegenExecutorSchema {\n generator: OpenApiCodegenTarget;\n openApiSpecPath: string;\n outputPath: string;\n dryRun?: boolean;\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GAED,qEAAqE,GAOrE,WAKC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ /** Which code the executor generates from an OpenAPI specification. */
7
+ export type OpenApiCodegenTarget =
8
+ | 'ts-client'
9
+ | 'ts-hooks'
10
+ | 'ts-metadata'
11
+ | 'json-metadata';
12
+
13
+ export interface OpenApiCodegenExecutorSchema {
14
+ generator: OpenApiCodegenTarget;
15
+ openApiSpecPath: string;
16
+ outputPath: string;
17
+ dryRun?: boolean;
18
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "OpenApiCodegen",
4
+ "title": "OpenAPI Code Generation",
5
+ "description": "Generate code from an OpenAPI specification",
6
+ "type": "object",
7
+ "properties": {
8
+ "generator": {
9
+ "type": "string",
10
+ "description": "Which code to generate from the specification",
11
+ "enum": ["ts-client", "ts-hooks", "ts-metadata", "json-metadata"],
12
+ "x-priority": "important"
13
+ },
14
+ "openApiSpecPath": {
15
+ "type": "string",
16
+ "description": "Path to the OpenAPI specification relative to the monorepo root",
17
+ "x-priority": "important"
18
+ },
19
+ "outputPath": {
20
+ "type": "string",
21
+ "description": "Path to the directory to generate into, relative to the monorepo root",
22
+ "x-priority": "important"
23
+ },
24
+ "dryRun": {
25
+ "type": "boolean",
26
+ "description": "Print the files that would be generated without writing them",
27
+ "default": false,
28
+ "alias": "d"
29
+ }
30
+ },
31
+ "required": ["generator", "openApiSpecPath", "outputPath"],
32
+ "additionalProperties": false
33
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type ExecutorContext } from '@nx/devkit';
6
+ import type { OpenApiCodegenExecutorSchema } from './executor-schema';
7
+ /**
8
+ * Runs an OpenAPI code generator against the workspace.
9
+ *
10
+ * Generated codegen targets use this rather than shelling out to `nx g`, which
11
+ * pays a second full Nx bootstrap — project graph, plugin resolution and
12
+ * schema validation — for work the running Nx process has already done. The
13
+ * generator is invoked directly against a tree rooted at the workspace, so the
14
+ * output is the same as `nx g` produces, including formatting.
15
+ */
16
+ export default function openApiCodegenExecutor(options: OpenApiCodegenExecutorSchema, _context: ExecutorContext): Promise<{
17
+ success: boolean;
18
+ }>;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { logger, workspaceRoot } from "@nx/devkit";
5
+ // `@nx/devkit` re-exports FsTree only from its `internal` entry and does not
6
+ // export flushChanges at all, so the tree is taken from nx directly, as the
7
+ // `nx g` command itself does.
8
+ import { FsTree, flushChanges, printChanges } from "nx/src/generators/tree.js";
9
+ /**
10
+ * The generators this executor can run, loaded on demand so a run only pays for
11
+ * the code generation it asks for.
12
+ */ const GENERATORS = {
13
+ 'ts-client': ()=>import("../ts-client/generator.js"),
14
+ 'ts-hooks': ()=>import("../ts-hooks/generator.js"),
15
+ 'ts-metadata': ()=>import("../ts-metadata/generator.js"),
16
+ 'json-metadata': ()=>import("../json-metadata/generator.js")
17
+ };
18
+ /**
19
+ * Runs an OpenAPI code generator against the workspace.
20
+ *
21
+ * Generated codegen targets use this rather than shelling out to `nx g`, which
22
+ * pays a second full Nx bootstrap — project graph, plugin resolution and
23
+ * schema validation — for work the running Nx process has already done. The
24
+ * generator is invoked directly against a tree rooted at the workspace, so the
25
+ * output is the same as `nx g` produces, including formatting.
26
+ */ export default async function openApiCodegenExecutor(options, _context) {
27
+ // `Object.hasOwn` so an inherited key (eg `constructor`) is not mistaken for a
28
+ // generator, which would fail with a TypeError rather than the message below.
29
+ if (!Object.hasOwn(GENERATORS, options.generator)) {
30
+ logger.error(`Unknown generator "${options.generator}". Expected one of ${Object.keys(GENERATORS).join(', ')}.`);
31
+ return {
32
+ success: false
33
+ };
34
+ }
35
+ const generator = (await GENERATORS[options.generator]()).default;
36
+ const tree = new FsTree(workspaceRoot, process.env.NX_VERBOSE_LOGGING === 'true');
37
+ await generator(tree, {
38
+ openApiSpecPath: options.openApiSpecPath,
39
+ outputPath: options.outputPath
40
+ });
41
+ tree.lock();
42
+ const changes = tree.listChanges();
43
+ printChanges(changes);
44
+ if (options.dryRun) {
45
+ logger.warn('\nNOTE: The "dryRun" flag means no changes were made.');
46
+ return {
47
+ success: true
48
+ };
49
+ }
50
+ flushChanges(workspaceRoot, changes);
51
+ return {
52
+ success: true
53
+ };
54
+ }
55
+
56
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/open-api/codegen/executor.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { type ExecutorContext, logger, workspaceRoot } from '@nx/devkit';\n// `@nx/devkit` re-exports FsTree only from its `internal` entry and does not\n// export flushChanges at all, so the tree is taken from nx directly, as the\n// `nx g` command itself does.\nimport { FsTree, flushChanges, printChanges } from 'nx/src/generators/tree.js';\nimport type { OpenApiCodegenExecutorSchema } from './executor-schema';\n\n/**\n * The generators this executor can run, loaded on demand so a run only pays for\n * the code generation it asks for.\n */\nconst GENERATORS = {\n 'ts-client': () => import('../ts-client/generator.js'),\n 'ts-hooks': () => import('../ts-hooks/generator.js'),\n 'ts-metadata': () => import('../ts-metadata/generator.js'),\n 'json-metadata': () => import('../json-metadata/generator.js'),\n} as const;\n\n/**\n * Runs an OpenAPI code generator against the workspace.\n *\n * Generated codegen targets use this rather than shelling out to `nx g`, which\n * pays a second full Nx bootstrap — project graph, plugin resolution and\n * schema validation — for work the running Nx process has already done. The\n * generator is invoked directly against a tree rooted at the workspace, so the\n * output is the same as `nx g` produces, including formatting.\n */\nexport default async function openApiCodegenExecutor(\n options: OpenApiCodegenExecutorSchema,\n _context: ExecutorContext,\n): Promise<{ success: boolean }> {\n // `Object.hasOwn` so an inherited key (eg `constructor`) is not mistaken for a\n // generator, which would fail with a TypeError rather than the message below.\n if (!Object.hasOwn(GENERATORS, options.generator)) {\n logger.error(\n `Unknown generator \"${options.generator}\". Expected one of ${Object.keys(GENERATORS).join(', ')}.`,\n );\n return { success: false };\n }\n\n const generator = (await GENERATORS[options.generator]()).default;\n\n const tree = new FsTree(\n workspaceRoot,\n process.env.NX_VERBOSE_LOGGING === 'true',\n );\n await generator(tree, {\n openApiSpecPath: options.openApiSpecPath,\n outputPath: options.outputPath,\n });\n\n tree.lock();\n const changes = tree.listChanges();\n printChanges(changes);\n\n if (options.dryRun) {\n logger.warn('\\nNOTE: The \"dryRun\" flag means no changes were made.');\n return { success: true };\n }\n\n flushChanges(workspaceRoot, changes);\n\n return { success: true };\n}\n"],"names":["logger","workspaceRoot","FsTree","flushChanges","printChanges","GENERATORS","openApiCodegenExecutor","options","_context","Object","hasOwn","generator","error","keys","join","success","default","tree","process","env","NX_VERBOSE_LOGGING","openApiSpecPath","outputPath","lock","changes","listChanges","dryRun","warn"],"mappings":"AAAA;;;CAGC,GACD,SAA+BA,MAAM,EAAEC,aAAa,QAAQ,aAAa;AACzE,6EAA6E;AAC7E,4EAA4E;AAC5E,8BAA8B;AAC9B,SAASC,MAAM,EAAEC,YAAY,EAAEC,YAAY,QAAQ,4BAA4B;AAG/E;;;CAGC,GACD,MAAMC,aAAa;IACjB,aAAa,IAAM,MAAM,CAAC;IAC1B,YAAY,IAAM,MAAM,CAAC;IACzB,eAAe,IAAM,MAAM,CAAC;IAC5B,iBAAiB,IAAM,MAAM,CAAC;AAChC;AAEA;;;;;;;;CAQC,GACD,eAAe,eAAeC,uBAC5BC,OAAqC,EACrCC,QAAyB;IAEzB,+EAA+E;IAC/E,8EAA8E;IAC9E,IAAI,CAACC,OAAOC,MAAM,CAACL,YAAYE,QAAQI,SAAS,GAAG;QACjDX,OAAOY,KAAK,CACV,CAAC,mBAAmB,EAAEL,QAAQI,SAAS,CAAC,mBAAmB,EAAEF,OAAOI,IAAI,CAACR,YAAYS,IAAI,CAAC,MAAM,CAAC,CAAC;QAEpG,OAAO;YAAEC,SAAS;QAAM;IAC1B;IAEA,MAAMJ,YAAY,AAAC,CAAA,MAAMN,UAAU,CAACE,QAAQI,SAAS,CAAC,EAAC,EAAGK,OAAO;IAEjE,MAAMC,OAAO,IAAIf,OACfD,eACAiB,QAAQC,GAAG,CAACC,kBAAkB,KAAK;IAErC,MAAMT,UAAUM,MAAM;QACpBI,iBAAiBd,QAAQc,eAAe;QACxCC,YAAYf,QAAQe,UAAU;IAChC;IAEAL,KAAKM,IAAI;IACT,MAAMC,UAAUP,KAAKQ,WAAW;IAChCrB,aAAaoB;IAEb,IAAIjB,QAAQmB,MAAM,EAAE;QAClB1B,OAAO2B,IAAI,CAAC;QACZ,OAAO;YAAEZ,SAAS;QAAK;IACzB;IAEAZ,aAAaF,eAAeuB;IAE5B,OAAO;QAAET,SAAS;IAAK;AACzB"}
@@ -94,7 +94,7 @@ The following list of generators are what is currently available in the \`@aws/n
94
94
 
95
95
  - **agentcore-gateway**: Generate an AgentCore Gateway project
96
96
 
97
- - **agentcore-harness**: Generate an AgentCore Harness project
97
+ - **agentcore-harness**: Generate an AgentCore Harness project (experimental)
98
98
 
99
99
  - **connection**: Integrates a source project with a target project
100
100
 
@@ -298,6 +298,7 @@ exports[`preset generator > should run successfully > biome.json 1`] = `
298
298
  "**",
299
299
  "!**/dist",
300
300
  "!**/out-tsc",
301
+ "!**/test-output",
301
302
  "!**/node_modules",
302
303
  "!**/.nx",
303
304
  "!**/.venv",
@@ -11,7 +11,7 @@ import { addAgentInfra } from "../../utils/agent-core-constructs/agent-core-cons
11
11
  import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
12
12
  import { resolveContainers } from "../../utils/containers.js";
13
13
  import { declareDependencies, ownedElsewhere } from "../../utils/declared-dependencies.js";
14
- import { addDockerScanTarget, DOCKER_DEPENDENCIES } from "../../utils/docker.js";
14
+ import { addDockerScanTarget, DOCKER_DEPENDENCIES, IMAGE_BUILD_CACHE } from "../../utils/docker.js";
15
15
  import { formatFilesInSubtree } from "../../utils/format.js";
16
16
  import { FS_DEPENDENCIES, FsCommands } from "../../utils/fs.js";
17
17
  import { updateGitIgnore } from "../../utils/git.js";
@@ -20,8 +20,9 @@ import { installDependencies } from "../../utils/install.js";
20
20
  import { addGeneratorMetricsIfApplicable } from "../../utils/metrics.js";
21
21
  import { kebabCase, toClassName, toSnakeCase } from "../../utils/names.js";
22
22
  import { getNpmScope } from "../../utils/npm-scope.js";
23
- import { addComponentDevTarget, addComponentGeneratorMetadata, addDependencyToTargetIfNotPresent, getGeneratorInfo, normalizeTargetKeyOrder, readProjectConfigurationUnqualified } from "../../utils/nx.js";
23
+ import { addArtifactDependencyToTargets, addComponentDevTarget, addComponentGeneratorMetadata, addDependencyToTargetIfNotPresent, getGeneratorInfo, normalizeTargetKeyOrder, readProjectConfigurationUnqualified } from "../../utils/nx.js";
24
24
  import { sortObjectKeys } from "../../utils/object.js";
25
+ import { openApiCodegenTarget } from "../../utils/open-api-codegen-target.js";
25
26
  import { getRelativePathToRootByDirectory, toProjectRelativePath } from "../../utils/paths.js";
26
27
  import { assignPort } from "../../utils/port.js";
27
28
  import { addWorkspaceDependencyToPyProject } from "../../utils/py.js";
@@ -310,7 +311,7 @@ export const pyAgentGenerator = async (tree, options)=>{
310
311
  // Add a docker target that prepares the docker context and builds the image
311
312
  const fs = new FsCommands(tree, DEPENDENCIES);
312
313
  project.targets[dockerTargetName] = {
313
- cache: true,
314
+ cache: IMAGE_BUILD_CACHE,
314
315
  executor: 'nx:run-commands',
315
316
  options: {
316
317
  commands: [
@@ -327,7 +328,7 @@ export const pyAgentGenerator = async (tree, options)=>{
327
328
  ]
328
329
  };
329
330
  addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);
330
- addDependencyToTargetIfNotPresent(project, 'build', 'docker');
331
+ addArtifactDependencyToTargets(project, 'docker');
331
332
  addDockerScanTarget(tree, {
332
333
  project,
333
334
  containerEngine: containers,
@@ -427,6 +428,15 @@ export const pyAgentGenerator = async (tree, options)=>{
427
428
  const httpOnlyTargets = protocol === 'http' ? {
428
429
  [openApiTargetName]: {
429
430
  cache: true,
431
+ // The spec serialises models a dependency may own, and this target
432
+ // has no `dependsOn` for `default`'s transitive
433
+ // `dependentTasksOutputFiles` to resolve against — so `^production`
434
+ // is the only edge to the dependency, and without it a model change
435
+ // there serves a stale spec.
436
+ inputs: [
437
+ 'production',
438
+ '^production'
439
+ ],
430
440
  executor: 'nx:run-commands',
431
441
  outputs: [
432
442
  `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`
@@ -437,26 +447,15 @@ export const pyAgentGenerator = async (tree, options)=>{
437
447
  ]
438
448
  }
439
449
  },
440
- [clientGenTargetName]: {
441
- cache: true,
442
- executor: 'nx:run-commands',
443
- dependsOn: [
444
- openApiTargetName
445
- ],
446
- inputs: [
447
- {
448
- dependentTasksOutputFiles: '**/*.json'
449
- }
450
- ],
450
+ [clientGenTargetName]: openApiCodegenTarget({
451
+ generator: 'ts-client',
452
+ openApiSpecPath: `dist/${project.root}/openapi/${agentNameSnakeCase}/openapi.json`,
453
+ outputPath: `${project.root}/scripts/${agentTargetPrefix}/generated`,
454
+ specBuildTargetName: openApiTargetName,
451
455
  outputs: [
452
456
  `{projectRoot}/scripts/${agentTargetPrefix}/generated`
453
- ],
454
- options: {
455
- commands: [
456
- `nx g @aws/nx-plugin:open-api#ts-client --openApiSpecPath="dist/${project.root}/openapi/${agentNameSnakeCase}/openapi.json" --outputPath="${project.root}/scripts/${agentTargetPrefix}/generated" --no-interactive`
457
- ]
458
- }
459
- }
457
+ ]
458
+ })
460
459
  } : {};
461
460
  const agentTargets = {
462
461
  ...project.targets,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/agent/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 OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { ensureLicenseExceptions } from '../../license/config.js';\nimport { AG_UI_LANGGRAPH_EXCEPTIONS } from '../../license/known-exceptions.js';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { addAgentChatScripts } from '../../utils/agent-chat/agent-chat.js';\nimport {\n AGENT_CONNECTION_PY_DEPENDENCIES,\n addPythonFrameworkBase,\n ensureLangchainS3CheckpointSaver,\n ensurePythonAgentConnectionProject,\n getPythonAgentConnectionModuleName,\n getPythonAgentConnectionProject,\n} from '../../utils/agent-connection/agent-connection.js';\nimport { addAgentInfra } from '../../utils/agent-core-constructs/agent-core-constructs.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n normalizeTargetKeyOrder,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport {\n getRelativePathToRootByDirectory,\n toProjectRelativePath,\n} from '../../utils/paths.js';\nimport { assignPort } from '../../utils/port.js';\nimport { addWorkspaceDependencyToPyProject } from '../../utils/py.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants.js';\nimport { BASE_IMAGES } from '../../utils/versions.js';\nimport type {\n AgentProtocol,\n PyAgentFramework,\n PyAgentGeneratorSchema,\n PyAgentSession,\n} from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyAgentMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n readonly protocol: AgentProtocol;\n /**\n * The mcp / gateway connection generators dispatch on this field to pick the\n * Strands vs LangChain Layer-2 client + agent.py transform.\n */\n readonly framework: PyAgentFramework;\n readonly session: PyAgentSession;\n}\n\n/** Whether the chat CLI signs its requests, which only IAM auth needs. */\nconst isIam = (m: PyAgentMetadata) => m.auth === 'iam';\n\n// Each entry names the framework and protocol branch it belongs to, so the same\n// declaration drives both adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<PyAgentMetadata>()({\n ts: [\n // The chat CLI, which runs standalone via tsx for every protocol and\n // resolves the deployed agent from AppConfig. `agent-chat-cli` transitively\n // bundles the protocol clients (@a2a-js/sdk, @ag-ui/client).\n { name: 'agent-chat-cli', dev: true, root: true },\n { name: 'tsx', dev: true, root: true },\n { name: '@types/node', dev: true, root: true },\n { name: '@aws-lambda-powertools/parameters', dev: true, root: true },\n { name: '@aws-sdk/client-appconfigdata', dev: true, root: true },\n { name: 'aws4fetch', when: isIam, dev: true, root: true },\n {\n name: '@aws-sdk/credential-providers',\n when: isIam,\n dev: true,\n root: true,\n },\n {\n name: '@a2a-js/sdk',\n when: (m) => m.protocol === 'a2a',\n dev: true,\n root: true,\n },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'aws-opentelemetry-distro' },\n { name: 'bedrock-agentcore' },\n { name: 'boto3' },\n { name: 'fastapi' },\n { name: 'mcp' },\n // langchain pulls no Strands dependencies — the langchain model binding\n // plus the per-protocol server adapter: ag-ui-langgraph for AG-UI, a2a-sdk\n // for A2A, nothing extra for HTTP (FastAPI is added for every agent).\n { name: 'langchain', when: (m) => m.framework === 'langchain' },\n { name: 'langchain-aws', when: (m) => m.framework === 'langchain' },\n { name: 'langgraph', when: (m) => m.framework === 'langchain' },\n // Local dev uses a SQLite-backed checkpointer for convenience (parity\n // with the strands framework's local FileSessionManager).\n {\n name: 'langgraph-checkpoint-sqlite',\n when: (m) => m.framework === 'langchain',\n },\n // AsyncSqliteSaver's driver, required alongside langgraph-checkpoint-sqlite.\n { name: 'aiosqlite', when: (m) => m.framework === 'langchain' },\n // Provides DynamoDBSaver (with S3 offloading for large checkpoints).\n {\n name: 'langgraph-checkpoint-aws',\n when: (m) => m.framework === 'langchain' && m.session === 'dynamodb-s3',\n },\n {\n name: 'ag-ui-protocol',\n when: (m) => m.framework === 'langchain' && m.protocol === 'ag-ui',\n },\n {\n name: 'ag-ui-langgraph',\n when: (m) => m.framework === 'langchain' && m.protocol === 'ag-ui',\n },\n {\n name: 'a2a-sdk',\n when: (m) => m.framework === 'langchain' && m.protocol === 'a2a',\n },\n {\n name: 'strands-agents[a2a]',\n when: (m) => m.framework === 'strands' && m.protocol === 'a2a',\n },\n {\n name: 'strands-agents',\n when: (m) => m.framework === 'strands' && m.protocol !== 'a2a',\n },\n {\n name: 'strands-agents-tools',\n when: (m) => m.framework === 'strands',\n },\n // Declared again here so a Strands AG-UI agent lists it in the same order\n // the generated pyproject.toml had before.\n {\n name: 'ag-ui-protocol',\n when: (m) => m.framework === 'strands' && m.protocol === 'ag-ui',\n },\n {\n name: 'ag-ui-strands',\n when: (m) => m.framework === 'strands' && m.protocol === 'ag-ui',\n },\n { name: 'uvicorn' },\n // `fastapi dev` runs the local server for every protocol.\n { name: 'fastapi[standard]', group: 'dev' },\n // The agent-connection helper adds these to its own project.\n ...ownedElsewhere(AGENT_CONNECTION_PY_DEPENDENCIES),\n ],\n});\n\nexport const PY_AGENT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyAgentGenerator = async (\n tree: Tree,\n options: PyAgentGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-agent`,\n );\n const agentTargetPrefix = options.name ? name : 'agent';\n\n const agentNameSnakeCase = toSnakeCase(options.name || 'agent');\n const agentNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n agentNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n const protocol = options.protocol ?? 'http';\n const framework = options.framework ?? 'strands';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Session backends are framework-specific: Strands' SessionManager only has\n // an S3-backed implementation here (via strands.session.S3SessionManager),\n // while LangChain uses dedicated S3 and DynamoDB checkpointer libraries.\n // 'in-memory' is valid for both.\n const SESSIONS_BY_FRAMEWORK: Record<\n PyAgentFramework,\n readonly PyAgentSession[]\n > = {\n strands: ['s3', 'in-memory'],\n langchain: ['s3', 'dynamodb-s3', 'in-memory'],\n };\n if (\n options.session &&\n !SESSIONS_BY_FRAMEWORK[framework].includes(options.session)\n ) {\n throw new Error(\n `Unsupported combination: session '${options.session}' is not implemented for the ${framework} framework (supported: ${SESSIONS_BY_FRAMEWORK[framework].join(', ')}).`,\n );\n }\n const session = options.session ?? 's3';\n\n // With infra=none there's no CDK/Terraform construct to provision a bucket\n // or table or set RUNTIME_CONFIG_APP_ID, so session.py's non-local-dev\n // branch has nothing to read from AppConfig at runtime — the generated code\n // still honors `session`, but only works outside local dev if the caller\n // wires up matching infra/runtime config themselves.\n if (infra === 'none' && session !== 'in-memory') {\n console.warn(\n `Warning: session '${session}' requires infrastructure to configure it automatically (no infrastructure is generated for infra=none) — outside local dev this will fail unless you configure matching runtime config yourself`,\n );\n }\n\n // Local-dev session storage lives at the workspace root\n // (`tmp/agents/<framework>/<agent-name>`), not inside the project, so each\n // agent gets its own storage directory — shared by both frameworks\n // (Strands' FileSessionManager, LangChain's SqliteSaver). The\n // `-dev`/`-serve` targets run with cwd={projectRoot}, so compute that\n // directory relative to the project root here rather than resolving it at\n // runtime.\n const localSessionsDir = joinPathFragments(\n getRelativePathToRootByDirectory(project.root),\n `tmp/agents/${framework}/${name}`,\n );\n\n // Ensure the shared agent-connection project exists so the server entry\n // point can import `session_id_context` and propagate the AgentCore\n // session ID to any downstream MCP / A2A clients a later connection\n // generator wires into this agent.\n await ensurePythonAgentConnectionProject(tree, DEPENDENCIES);\n // The agent server imports the framework base helpers (session cache + model\n // error logging) regardless of whether a connection client is wired in. The\n // LangChain framework has no base layer (its AG-UI foundation reuses only the\n // framework-agnostic session context), so this is a no-op for LangChain.\n await addPythonFrameworkBase(tree, DEPENDENCIES, framework);\n const agentConnectionModuleName = getPythonAgentConnectionModuleName(tree);\n addWorkspaceDependencyToPyProject(\n tree,\n project,\n getPythonAgentConnectionProject(tree),\n );\n\n const templateContext = {\n name,\n agentNameSnakeCase,\n agentNameClassName,\n moduleName,\n agentConnectionModuleName,\n framework,\n protocol,\n session,\n localSessionsDir,\n };\n\n // Files live under a per-framework dir (files/strands, files/langchain),\n // mirrored one-for-one — including files that don't vary by framework\n // (e.g. the empty package __init__.py) — so there's a single, uniform\n // <framework>/<protocol> layout with no cross-framework fallbacks.\n // `framework` is itself the directory name.\n\n // Common files shared by both protocols: the agent module (Strands yields a\n // contextmanaged Agent with a session.py sibling; LangChain returns a\n // compiled create_agent graph) and the package __init__.py.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', framework, 'common'),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (framework === 'langchain' && session === 's3') {\n ensureLangchainS3CheckpointSaver(tree);\n }\n\n // Protocol-specific files. Each protocol's server entry point is\n // framework-specific (Strands yields a contextmanaged Agent; LangChain\n // drives a compiled create_agent graph).\n const protocolLower = protocol.toLowerCase();\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', framework, protocolLower),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n // Add the Dockerfile\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n agentNameSnakeCase,\n moduleName,\n bundleOutputDir,\n protocol,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${agentTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addDependencyToTargetIfNotPresent(project, 'build', 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${agentTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the agent.\n // AG-UI uses HTTP as the AgentCore protocol type (AG-UI is HTTP-based with SSE over POST).\n const infraProtocol =\n protocol === 'ag-ui' ? ('http' as const) : (protocol as 'http' | 'a2a');\n await addAgentInfra(tree, {\n agentNameKebabCase: name,\n agentNameClassName,\n dockerImageTag,\n dockerOutputDir,\n iac,\n projectName: project.name,\n auth,\n session,\n serverProtocol: infraProtocol,\n containers,\n });\n }\n\n // A2A servers use port 9000 as per the Strands A2A SDK default and AgentCore A2A contract.\n // HTTP and AG-UI agents use port 8081+ to avoid conflict with VS Code server on 8080.\n const localDevPortStart = protocol === 'a2a' ? 9000 : 8081;\n const localDevPort = assignPort(tree, project, localDevPortStart, {\n component: { info: PY_AGENT_GENERATOR_INFO, name: agentTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyAgentMetadata = {\n port: localDevPort,\n rc: agentNameClassName,\n auth,\n protocol,\n framework,\n session,\n ...(iac ? { iac } : {}),\n };\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n // All protocols use fastapi dev for hot reload:\n // - HTTP: FastAPI app directly defined in init.py\n // - A2A: A2AServer.to_fastapi_app() creates a FastAPI app in main.py\n // - AG-UI: create_strands_app() creates a FastAPI app in main.py\n const serveCommand = `uv run fastapi dev ${moduleName}/${agentNameSnakeCase}/main.py --port ${localDevPort}`;\n\n // HTTP chat uses the type-safe TypeScript client generated from the\n // agent's OpenAPI spec (same generated client the react-connection\n // generator produces). A2A and AG-UI speak standard protocols, so\n // we can run `agent-chat-cli` directly as a binary.\n const openApiTargetName = `${agentTargetPrefix}-openapi`;\n const clientGenTargetName = `${agentTargetPrefix}-generate-client`;\n\n const scriptsDir = joinPathFragments(\n project.root,\n 'scripts',\n agentTargetPrefix,\n );\n\n if (protocol === 'http') {\n // Emit the OpenAPI spec generator script (shared with react-connection)\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'react-connection',\n 'files',\n 'agent',\n ),\n project.root,\n {\n moduleName,\n agentNameSnakeCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // Ignore the generated client directory\n updateGitIgnore(tree, project.root, (patterns) => [\n ...patterns,\n `scripts/${agentTargetPrefix}/generated/`,\n ]);\n }\n\n // Every protocol gets a standalone `chat.ts`. It connects to the local\n // `dev` server by default, or to the deployed agent (with the\n // appropriate auth) when `RUNTIME_CONFIG_APP_ID` is set.\n addAgentChatScripts(tree, {\n scriptsDir,\n protocol,\n language: 'py',\n agentNameClassName,\n auth,\n });\n\n const chatUrl =\n protocol === 'ag-ui'\n ? `http://localhost:${localDevPort}/invocations`\n : `http://localhost:${localDevPort}`;\n const chatCommand = `tsx ./scripts/${agentTargetPrefix}/chat.ts`;\n\n const httpOnlyTargets =\n protocol === 'http'\n ? {\n [openApiTargetName]: {\n cache: true,\n executor: 'nx:run-commands',\n outputs: [\n `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`,\n ],\n options: {\n commands: [\n `uv run python {projectRoot}/scripts/${agentNameSnakeCase}_openapi.py \"dist/{projectRoot}/openapi/${agentNameSnakeCase}/openapi.json\"`,\n ],\n },\n },\n [clientGenTargetName]: {\n cache: true,\n executor: 'nx:run-commands',\n dependsOn: [openApiTargetName],\n inputs: [\n {\n dependentTasksOutputFiles: '**/*.json',\n },\n ],\n outputs: [`{projectRoot}/scripts/${agentTargetPrefix}/generated`],\n options: {\n commands: [\n `nx g @aws/nx-plugin:open-api#ts-client --openApiSpecPath=\"dist/${project.root}/openapi/${agentNameSnakeCase}/openapi.json\" --outputPath=\"${project.root}/scripts/${agentTargetPrefix}/generated\" --no-interactive`,\n ],\n },\n },\n }\n : {};\n\n const agentTargets = {\n ...project.targets,\n ...httpOnlyTargets,\n [`${agentTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${agentTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n // HTTP chat imports the generated client, so ensure it's built first.\n // No dev dependency — chat runs standalone against a local or\n // deployed agent. normalizeTargetKeyOrder keeps the conditional dependsOn\n // in Nx 23's serialization order so re-runs stay byte-identical.\n [`${agentTargetPrefix}-chat`]: normalizeTargetKeyOrder({\n executor: 'nx:run-commands',\n options: {\n commands: [chatCommand],\n cwd: '{projectRoot}',\n env: {\n URL: chatUrl,\n },\n },\n ...(protocol === 'http' ? { dependsOn: [clientGenTargetName] } : {}),\n }),\n };\n\n // Aggregate `<agent>-dev` under the project-level `dev` target.\n addComponentDevTarget(agentTargets, `${agentTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: sortObjectKeys(agentTargets),\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_AGENT_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n agentTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_AGENT_GENERATOR_INFO]);\n\n // langchain-core (pulled by every langchain agent regardless of protocol)\n // brings jsonpatch/jsonpointer, whose wheels ship without resolvable SPDX\n // license metadata, so register those exceptions so the workspace license\n // check still passes.\n if (framework === 'langchain') {\n await ensureLicenseExceptions(tree, AG_UI_LANGGRAPH_EXCEPTIONS);\n }\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyAgentGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","ensureLicenseExceptions","AG_UI_LANGGRAPH_EXCEPTIONS","addPyDependencies","addTsDependencies","addAgentChatScripts","AGENT_CONNECTION_PY_DEPENDENCIES","addPythonFrameworkBase","ensureLangchainS3CheckpointSaver","ensurePythonAgentConnectionProject","getPythonAgentConnectionModuleName","getPythonAgentConnectionProject","addAgentInfra","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","normalizeTargetKeyOrder","readProjectConfigurationUnqualified","sortObjectKeys","getRelativePathToRootByDirectory","toProjectRelativePath","assignPort","addWorkspaceDependencyToPyProject","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","isIam","m","auth","DEPENDENCIES","ts","name","dev","root","when","protocol","py","framework","session","group","PY_AGENT_GENERATOR_INFO","filename","pyAgentGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","agentTargetPrefix","agentNameSnakeCase","agentNameClassName","targetSourceDir","infra","iac","undefined","console","warn","SESSIONS_BY_FRAMEWORK","strands","langchain","includes","join","localSessionsDir","agentConnectionModuleName","templateContext","dirname","overwriteStrategy","KeepExisting","protocolLower","toLowerCase","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","infraProtocol","agentNameKebabCase","projectName","serverProtocol","localDevPortStart","localDevPort","component","info","metadata","port","rc","projectRoot","serveCommand","openApiTargetName","clientGenTargetName","scriptsDir","patterns","language","chatUrl","chatCommand","httpOnlyTargets","outputs","inputs","dependentTasksOutputFiles","agentTargets","continuous","cwd","env","PORT","LOCAL_DEV","URL","preferInstallDependencies","languages"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/agent/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 OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { ensureLicenseExceptions } from '../../license/config.js';\nimport { AG_UI_LANGGRAPH_EXCEPTIONS } from '../../license/known-exceptions.js';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { addAgentChatScripts } from '../../utils/agent-chat/agent-chat.js';\nimport {\n AGENT_CONNECTION_PY_DEPENDENCIES,\n addPythonFrameworkBase,\n ensureLangchainS3CheckpointSaver,\n ensurePythonAgentConnectionProject,\n getPythonAgentConnectionModuleName,\n getPythonAgentConnectionProject,\n} from '../../utils/agent-connection/agent-connection.js';\nimport { addAgentInfra } from '../../utils/agent-core-constructs/agent-core-constructs.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n IMAGE_BUILD_CACHE,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addArtifactDependencyToTargets,\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n normalizeTargetKeyOrder,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport { openApiCodegenTarget } from '../../utils/open-api-codegen-target.js';\nimport {\n getRelativePathToRootByDirectory,\n toProjectRelativePath,\n} from '../../utils/paths.js';\nimport { assignPort } from '../../utils/port.js';\nimport { addWorkspaceDependencyToPyProject } from '../../utils/py.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants.js';\nimport { BASE_IMAGES } from '../../utils/versions.js';\nimport type {\n AgentProtocol,\n PyAgentFramework,\n PyAgentGeneratorSchema,\n PyAgentSession,\n} from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyAgentMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n readonly protocol: AgentProtocol;\n /**\n * The mcp / gateway connection generators dispatch on this field to pick the\n * Strands vs LangChain Layer-2 client + agent.py transform.\n */\n readonly framework: PyAgentFramework;\n readonly session: PyAgentSession;\n}\n\n/** Whether the chat CLI signs its requests, which only IAM auth needs. */\nconst isIam = (m: PyAgentMetadata) => m.auth === 'iam';\n\n// Each entry names the framework and protocol branch it belongs to, so the same\n// declaration drives both adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<PyAgentMetadata>()({\n ts: [\n // The chat CLI, which runs standalone via tsx for every protocol and\n // resolves the deployed agent from AppConfig. `agent-chat-cli` transitively\n // bundles the protocol clients (@a2a-js/sdk, @ag-ui/client).\n { name: 'agent-chat-cli', dev: true, root: true },\n { name: 'tsx', dev: true, root: true },\n { name: '@types/node', dev: true, root: true },\n { name: '@aws-lambda-powertools/parameters', dev: true, root: true },\n { name: '@aws-sdk/client-appconfigdata', dev: true, root: true },\n { name: 'aws4fetch', when: isIam, dev: true, root: true },\n {\n name: '@aws-sdk/credential-providers',\n when: isIam,\n dev: true,\n root: true,\n },\n {\n name: '@a2a-js/sdk',\n when: (m) => m.protocol === 'a2a',\n dev: true,\n root: true,\n },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'aws-opentelemetry-distro' },\n { name: 'bedrock-agentcore' },\n { name: 'boto3' },\n { name: 'fastapi' },\n { name: 'mcp' },\n // langchain pulls no Strands dependencies — the langchain model binding\n // plus the per-protocol server adapter: ag-ui-langgraph for AG-UI, a2a-sdk\n // for A2A, nothing extra for HTTP (FastAPI is added for every agent).\n { name: 'langchain', when: (m) => m.framework === 'langchain' },\n { name: 'langchain-aws', when: (m) => m.framework === 'langchain' },\n { name: 'langgraph', when: (m) => m.framework === 'langchain' },\n // Local dev uses a SQLite-backed checkpointer for convenience (parity\n // with the strands framework's local FileSessionManager).\n {\n name: 'langgraph-checkpoint-sqlite',\n when: (m) => m.framework === 'langchain',\n },\n // AsyncSqliteSaver's driver, required alongside langgraph-checkpoint-sqlite.\n { name: 'aiosqlite', when: (m) => m.framework === 'langchain' },\n // Provides DynamoDBSaver (with S3 offloading for large checkpoints).\n {\n name: 'langgraph-checkpoint-aws',\n when: (m) => m.framework === 'langchain' && m.session === 'dynamodb-s3',\n },\n {\n name: 'ag-ui-protocol',\n when: (m) => m.framework === 'langchain' && m.protocol === 'ag-ui',\n },\n {\n name: 'ag-ui-langgraph',\n when: (m) => m.framework === 'langchain' && m.protocol === 'ag-ui',\n },\n {\n name: 'a2a-sdk',\n when: (m) => m.framework === 'langchain' && m.protocol === 'a2a',\n },\n {\n name: 'strands-agents[a2a]',\n when: (m) => m.framework === 'strands' && m.protocol === 'a2a',\n },\n {\n name: 'strands-agents',\n when: (m) => m.framework === 'strands' && m.protocol !== 'a2a',\n },\n {\n name: 'strands-agents-tools',\n when: (m) => m.framework === 'strands',\n },\n // Declared again here so a Strands AG-UI agent lists it in the same order\n // the generated pyproject.toml had before.\n {\n name: 'ag-ui-protocol',\n when: (m) => m.framework === 'strands' && m.protocol === 'ag-ui',\n },\n {\n name: 'ag-ui-strands',\n when: (m) => m.framework === 'strands' && m.protocol === 'ag-ui',\n },\n { name: 'uvicorn' },\n // `fastapi dev` runs the local server for every protocol.\n { name: 'fastapi[standard]', group: 'dev' },\n // The agent-connection helper adds these to its own project.\n ...ownedElsewhere(AGENT_CONNECTION_PY_DEPENDENCIES),\n ],\n});\n\nexport const PY_AGENT_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyAgentGenerator = async (\n tree: Tree,\n options: PyAgentGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-agent`,\n );\n const agentTargetPrefix = options.name ? name : 'agent';\n\n const agentNameSnakeCase = toSnakeCase(options.name || 'agent');\n const agentNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n agentNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n const protocol = options.protocol ?? 'http';\n const framework = options.framework ?? 'strands';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Session backends are framework-specific: Strands' SessionManager only has\n // an S3-backed implementation here (via strands.session.S3SessionManager),\n // while LangChain uses dedicated S3 and DynamoDB checkpointer libraries.\n // 'in-memory' is valid for both.\n const SESSIONS_BY_FRAMEWORK: Record<\n PyAgentFramework,\n readonly PyAgentSession[]\n > = {\n strands: ['s3', 'in-memory'],\n langchain: ['s3', 'dynamodb-s3', 'in-memory'],\n };\n if (\n options.session &&\n !SESSIONS_BY_FRAMEWORK[framework].includes(options.session)\n ) {\n throw new Error(\n `Unsupported combination: session '${options.session}' is not implemented for the ${framework} framework (supported: ${SESSIONS_BY_FRAMEWORK[framework].join(', ')}).`,\n );\n }\n const session = options.session ?? 's3';\n\n // With infra=none there's no CDK/Terraform construct to provision a bucket\n // or table or set RUNTIME_CONFIG_APP_ID, so session.py's non-local-dev\n // branch has nothing to read from AppConfig at runtime — the generated code\n // still honors `session`, but only works outside local dev if the caller\n // wires up matching infra/runtime config themselves.\n if (infra === 'none' && session !== 'in-memory') {\n console.warn(\n `Warning: session '${session}' requires infrastructure to configure it automatically (no infrastructure is generated for infra=none) — outside local dev this will fail unless you configure matching runtime config yourself`,\n );\n }\n\n // Local-dev session storage lives at the workspace root\n // (`tmp/agents/<framework>/<agent-name>`), not inside the project, so each\n // agent gets its own storage directory — shared by both frameworks\n // (Strands' FileSessionManager, LangChain's SqliteSaver). The\n // `-dev`/`-serve` targets run with cwd={projectRoot}, so compute that\n // directory relative to the project root here rather than resolving it at\n // runtime.\n const localSessionsDir = joinPathFragments(\n getRelativePathToRootByDirectory(project.root),\n `tmp/agents/${framework}/${name}`,\n );\n\n // Ensure the shared agent-connection project exists so the server entry\n // point can import `session_id_context` and propagate the AgentCore\n // session ID to any downstream MCP / A2A clients a later connection\n // generator wires into this agent.\n await ensurePythonAgentConnectionProject(tree, DEPENDENCIES);\n // The agent server imports the framework base helpers (session cache + model\n // error logging) regardless of whether a connection client is wired in. The\n // LangChain framework has no base layer (its AG-UI foundation reuses only the\n // framework-agnostic session context), so this is a no-op for LangChain.\n await addPythonFrameworkBase(tree, DEPENDENCIES, framework);\n const agentConnectionModuleName = getPythonAgentConnectionModuleName(tree);\n addWorkspaceDependencyToPyProject(\n tree,\n project,\n getPythonAgentConnectionProject(tree),\n );\n\n const templateContext = {\n name,\n agentNameSnakeCase,\n agentNameClassName,\n moduleName,\n agentConnectionModuleName,\n framework,\n protocol,\n session,\n localSessionsDir,\n };\n\n // Files live under a per-framework dir (files/strands, files/langchain),\n // mirrored one-for-one — including files that don't vary by framework\n // (e.g. the empty package __init__.py) — so there's a single, uniform\n // <framework>/<protocol> layout with no cross-framework fallbacks.\n // `framework` is itself the directory name.\n\n // Common files shared by both protocols: the agent module (Strands yields a\n // contextmanaged Agent with a session.py sibling; LangChain returns a\n // compiled create_agent graph) and the package __init__.py.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', framework, 'common'),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (framework === 'langchain' && session === 's3') {\n ensureLangchainS3CheckpointSaver(tree);\n }\n\n // Protocol-specific files. Each protocol's server entry point is\n // framework-specific (Strands yields a contextmanaged Agent; LangChain\n // drives a compiled create_agent graph).\n const protocolLower = protocol.toLowerCase();\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', framework, protocolLower),\n targetSourceDir,\n templateContext,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n // Add the Dockerfile\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n agentNameSnakeCase,\n moduleName,\n bundleOutputDir,\n protocol,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${agentTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: IMAGE_BUILD_CACHE,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addArtifactDependencyToTargets(project, 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${agentTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the agent.\n // AG-UI uses HTTP as the AgentCore protocol type (AG-UI is HTTP-based with SSE over POST).\n const infraProtocol =\n protocol === 'ag-ui' ? ('http' as const) : (protocol as 'http' | 'a2a');\n await addAgentInfra(tree, {\n agentNameKebabCase: name,\n agentNameClassName,\n dockerImageTag,\n dockerOutputDir,\n iac,\n projectName: project.name,\n auth,\n session,\n serverProtocol: infraProtocol,\n containers,\n });\n }\n\n // A2A servers use port 9000 as per the Strands A2A SDK default and AgentCore A2A contract.\n // HTTP and AG-UI agents use port 8081+ to avoid conflict with VS Code server on 8080.\n const localDevPortStart = protocol === 'a2a' ? 9000 : 8081;\n const localDevPort = assignPort(tree, project, localDevPortStart, {\n component: { info: PY_AGENT_GENERATOR_INFO, name: agentTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyAgentMetadata = {\n port: localDevPort,\n rc: agentNameClassName,\n auth,\n protocol,\n framework,\n session,\n ...(iac ? { iac } : {}),\n };\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n // All protocols use fastapi dev for hot reload:\n // - HTTP: FastAPI app directly defined in init.py\n // - A2A: A2AServer.to_fastapi_app() creates a FastAPI app in main.py\n // - AG-UI: create_strands_app() creates a FastAPI app in main.py\n const serveCommand = `uv run fastapi dev ${moduleName}/${agentNameSnakeCase}/main.py --port ${localDevPort}`;\n\n // HTTP chat uses the type-safe TypeScript client generated from the\n // agent's OpenAPI spec (same generated client the react-connection\n // generator produces). A2A and AG-UI speak standard protocols, so\n // we can run `agent-chat-cli` directly as a binary.\n const openApiTargetName = `${agentTargetPrefix}-openapi`;\n const clientGenTargetName = `${agentTargetPrefix}-generate-client`;\n\n const scriptsDir = joinPathFragments(\n project.root,\n 'scripts',\n agentTargetPrefix,\n );\n\n if (protocol === 'http') {\n // Emit the OpenAPI spec generator script (shared with react-connection)\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'react-connection',\n 'files',\n 'agent',\n ),\n project.root,\n {\n moduleName,\n agentNameSnakeCase,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n // Ignore the generated client directory\n updateGitIgnore(tree, project.root, (patterns) => [\n ...patterns,\n `scripts/${agentTargetPrefix}/generated/`,\n ]);\n }\n\n // Every protocol gets a standalone `chat.ts`. It connects to the local\n // `dev` server by default, or to the deployed agent (with the\n // appropriate auth) when `RUNTIME_CONFIG_APP_ID` is set.\n addAgentChatScripts(tree, {\n scriptsDir,\n protocol,\n language: 'py',\n agentNameClassName,\n auth,\n });\n\n const chatUrl =\n protocol === 'ag-ui'\n ? `http://localhost:${localDevPort}/invocations`\n : `http://localhost:${localDevPort}`;\n const chatCommand = `tsx ./scripts/${agentTargetPrefix}/chat.ts`;\n\n const httpOnlyTargets =\n protocol === 'http'\n ? {\n [openApiTargetName]: {\n cache: true,\n // The spec serialises models a dependency may own, and this target\n // has no `dependsOn` for `default`'s transitive\n // `dependentTasksOutputFiles` to resolve against — so `^production`\n // is the only edge to the dependency, and without it a model change\n // there serves a stale spec.\n inputs: ['production', '^production'],\n executor: 'nx:run-commands',\n outputs: [\n `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`,\n ],\n options: {\n commands: [\n `uv run python {projectRoot}/scripts/${agentNameSnakeCase}_openapi.py \"dist/{projectRoot}/openapi/${agentNameSnakeCase}/openapi.json\"`,\n ],\n },\n },\n [clientGenTargetName]: openApiCodegenTarget({\n generator: 'ts-client',\n openApiSpecPath: `dist/${project.root}/openapi/${agentNameSnakeCase}/openapi.json`,\n outputPath: `${project.root}/scripts/${agentTargetPrefix}/generated`,\n specBuildTargetName: openApiTargetName,\n outputs: [`{projectRoot}/scripts/${agentTargetPrefix}/generated`],\n }),\n }\n : {};\n\n const agentTargets = {\n ...project.targets,\n ...httpOnlyTargets,\n [`${agentTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${agentTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [serveCommand],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n // HTTP chat imports the generated client, so ensure it's built first.\n // No dev dependency — chat runs standalone against a local or\n // deployed agent. normalizeTargetKeyOrder keeps the conditional dependsOn\n // in Nx 23's serialization order so re-runs stay byte-identical.\n [`${agentTargetPrefix}-chat`]: normalizeTargetKeyOrder({\n executor: 'nx:run-commands',\n options: {\n commands: [chatCommand],\n cwd: '{projectRoot}',\n env: {\n URL: chatUrl,\n },\n },\n ...(protocol === 'http' ? { dependsOn: [clientGenTargetName] } : {}),\n }),\n };\n\n // Aggregate `<agent>-dev` under the project-level `dev` target.\n addComponentDevTarget(agentTargets, `${agentTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: sortObjectKeys(agentTargets),\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_AGENT_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n agentTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_AGENT_GENERATOR_INFO]);\n\n // langchain-core (pulled by every langchain agent regardless of protocol)\n // brings jsonpatch/jsonpointer, whose wheels ship without resolvable SPDX\n // license metadata, so register those exceptions so the workspace license\n // check still passes.\n if (framework === 'langchain') {\n await ensureLicenseExceptions(tree, AG_UI_LANGGRAPH_EXCEPTIONS);\n }\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyAgentGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","ensureLicenseExceptions","AG_UI_LANGGRAPH_EXCEPTIONS","addPyDependencies","addTsDependencies","addAgentChatScripts","AGENT_CONNECTION_PY_DEPENDENCIES","addPythonFrameworkBase","ensureLangchainS3CheckpointSaver","ensurePythonAgentConnectionProject","getPythonAgentConnectionModuleName","getPythonAgentConnectionProject","addAgentInfra","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","IMAGE_BUILD_CACHE","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addArtifactDependencyToTargets","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","normalizeTargetKeyOrder","readProjectConfigurationUnqualified","sortObjectKeys","openApiCodegenTarget","getRelativePathToRootByDirectory","toProjectRelativePath","assignPort","addWorkspaceDependencyToPyProject","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","isIam","m","auth","DEPENDENCIES","ts","name","dev","root","when","protocol","py","framework","session","group","PY_AGENT_GENERATOR_INFO","filename","pyAgentGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","agentTargetPrefix","agentNameSnakeCase","agentNameClassName","targetSourceDir","infra","iac","undefined","console","warn","SESSIONS_BY_FRAMEWORK","strands","langchain","includes","join","localSessionsDir","agentConnectionModuleName","templateContext","dirname","overwriteStrategy","KeepExisting","protocolLower","toLowerCase","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","infraProtocol","agentNameKebabCase","projectName","serverProtocol","localDevPortStart","localDevPort","component","info","metadata","port","rc","projectRoot","serveCommand","openApiTargetName","clientGenTargetName","scriptsDir","patterns","language","chatUrl","chatCommand","httpOnlyTargets","inputs","outputs","generator","openApiSpecPath","outputPath","specBuildTargetName","agentTargets","continuous","cwd","env","PORT","LOCAL_DEV","URL","preferInstallDependencies","languages"],"mappings":"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"}
@@ -79,6 +79,15 @@ export const pyAgentReactConnectionGenerator = async (tree, options)=>{
79
79
  ...agentProjectConfig.targets,
80
80
  [openApiTargetName]: {
81
81
  cache: true,
82
+ // The spec serialises models a dependency may own, and this target
83
+ // has no `dependsOn` for `default`'s transitive
84
+ // `dependentTasksOutputFiles` to resolve against — so `^production` is
85
+ // the only edge to the dependency, and without it a model change there
86
+ // serves a stale spec.
87
+ inputs: [
88
+ 'production',
89
+ '^production'
90
+ ],
82
91
  executor: 'nx:run-commands',
83
92
  outputs: [
84
93
  `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/py/agent/react-connection/generator.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 updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addAgentRuntimeToConnectionNamespace } from '../../../connection/agent-runtime-config.js';\nimport type { ResolvedConnectionOptions } from '../../../connection/generator.js';\nimport type { AgentGatewayRoute } from '../../../ts/agent/react-connection/generator.js';\nimport {\n DEPENDENCIES as AGUI_DEPENDENCIES,\n type AgUiAuth,\n addAgUiReactConnection,\n resolveAgUiTheme,\n} from '../../../ts/react-website/agui/generator.js';\nimport {\n addOpenApiReactClient,\n OPEN_API_REACT_DEPENDENCIES,\n} from '../../../utils/connection/open-api/react.js';\nimport {\n declareDependencies,\n onlyWhen,\n} from '../../../utils/declared-dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { installDependencies } from '../../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../../utils/names.js';\nimport {\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n type ComponentMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\nimport { toProjectRelativePath } from '../../../utils/paths.js';\nimport {\n addPyAgentTargetToLocalDev,\n openApiClientLocalDevDeps,\n} from './local-dev.js';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyAgentReactConnectionMetadata {\n readonly protocol: string;\n readonly auth: string;\n /** The AG-UI theme module, which the website's `ux` selects. */\n readonly theme: string;\n}\n\n/** The OpenAPI-over-HTTP path, which the AG-UI path takes none of. */\nconst isHttp = (m: PyAgentReactConnectionMetadata) => m.protocol !== 'ag-ui';\n\n/** The AG-UI path, whose packages `addAgUiReactConnection` adds. */\nconst isAgUi = (m: PyAgentReactConnectionMetadata) => !isHttp(m);\n\n// Each entry names the protocol path it belongs to: the HTTP path's OpenAPI\n// client packages are added by `addOpenApiReactClient`, the AG-UI path's by\n// `addAgUiReactConnection`, both on this generator's behalf. The AG-UI entries\n// keep their own theme and auth conditions, which the metadata below records.\nexport const DEPENDENCIES =\n declareDependencies<PyAgentReactConnectionMetadata>()({\n ts: [\n ...onlyWhen(OPEN_API_REACT_DEPENDENCIES, isHttp),\n ...onlyWhen(AGUI_DEPENDENCIES.ts, isAgUi),\n ],\n });\n\nexport const PY_AGENT_REACT_CONNECTION_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport const pyAgentReactConnectionGenerator = async (\n tree: Tree,\n options: ResolvedConnectionOptions & { gatewayRoute?: AgentGatewayRoute },\n) => {\n const frontendProjectConfig = readProjectConfigurationUnqualified(\n tree,\n options.sourceProject,\n );\n const agentProjectConfig = readProjectConfigurationUnqualified(\n tree,\n options.targetProject,\n );\n\n const targetComponent: ComponentMetadata | undefined =\n options.targetComponent;\n\n // Extract agent metadata from the target component or project metadata\n const metadata = agentProjectConfig.metadata as any;\n const agentName = targetComponent?.name ?? 'agent';\n const agentNameClassName = targetComponent?.rc ?? toClassName(agentName);\n const agentPort = targetComponent?.port ?? metadata?.ports?.[0] ?? 8081;\n // Behind a gateway the browser authenticates with the gateway, not the agent.\n const auth = (\n options.gatewayRoute?.gatewayAuth ??\n targetComponent?.auth ??\n metadata?.auth ??\n 'iam'\n ).toLowerCase();\n const protocol = (targetComponent?.protocol ?? 'http').toLowerCase();\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const connectionMetadata: PyAgentReactConnectionMetadata = {\n protocol,\n auth,\n theme: resolveAgUiTheme(frontendProjectConfig),\n };\n\n if (protocol === 'a2a') {\n throw new Error(\n `Cannot connect a React website to an A2A agent. ` +\n `Consider generating an agent with the HTTP or AG-UI protocol instead.`,\n );\n }\n\n let additionalLocalDevDeps: string[] = [];\n\n if (protocol === 'ag-ui') {\n await addAgUiReactConnection(tree, {\n frontendProjectConfig,\n agentName,\n agentNameClassName,\n auth: auth as AgUiAuth,\n gatewayRoute: options.gatewayRoute,\n });\n } else {\n const moduleName = getModuleName(agentProjectConfig);\n const agentNameSnakeCase = toSnakeCase(agentName);\n const agentTargetPrefix = targetComponent?.name ? agentName : 'agent';\n\n // Add OpenAPI spec generation script scoped to this agent\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files/agent'),\n agentProjectConfig.root,\n {\n moduleName,\n agentNameSnakeCase,\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Instrument the OpenAPI spec generation as a target on the agent project\n const openApiTargetName = `${agentTargetPrefix}-openapi`;\n const openApiDist = joinPathFragments(\n 'dist',\n agentProjectConfig.root,\n 'openapi',\n agentNameSnakeCase,\n );\n const specPath = joinPathFragments(openApiDist, 'openapi.json');\n\n updateProjectConfiguration(tree, agentProjectConfig.name, {\n ...agentProjectConfig,\n targets: sortObjectKeys({\n ...agentProjectConfig.targets,\n [openApiTargetName]: {\n cache: true,\n executor: 'nx:run-commands',\n outputs: [\n `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`,\n ],\n options: {\n commands: [\n `uv run python {projectRoot}/scripts/${agentNameSnakeCase}_openapi.py \"dist/{projectRoot}/openapi/${agentNameSnakeCase}/openapi.json\"`,\n ],\n },\n },\n }),\n });\n\n // Use the shared OpenAPI react client utility for hooks, providers, and build targets.\n // The dev target is handled separately below using the agent-specific dev target.\n await addOpenApiReactClient(\n tree,\n {\n apiName: agentNameClassName,\n frontendProjectConfig,\n backendProjectConfig: agentProjectConfig,\n specBuildProject: agentProjectConfig,\n specPath,\n specBuildTargetName: `${agentProjectConfig.name}:${openApiTargetName}`,\n auth,\n port: agentPort,\n isAgentRuntime: true,\n gatewayRoute: options.gatewayRoute,\n skipLocalDev: true,\n },\n DEPENDENCIES,\n );\n\n additionalLocalDevDeps = openApiClientLocalDevDeps(agentNameClassName);\n\n // HTTP only — the AG-UI branch handles this inside addAgUiReactConnection.\n // Agent constructs publish their runtime ARN to the 'agentcore' namespace\n // by default, which isn't exposed to the website; patch them to also\n // publish under 'connection' so the browser can read it. When routing via\n // a gateway, the gateway publishes its own URL instead.\n if (!options.gatewayRoute) {\n await addAgentRuntimeToConnectionNamespace(tree, {\n agentNameKebabCase: kebabCase(agentNameClassName),\n agentNameClassName,\n });\n }\n }\n\n if (options.gatewayRoute) {\n // The gateway react-connection wires the website's dev target to the\n // local gateway (which proxies to the agent); only the OpenAPI client\n // generation targets are still needed here.\n if (additionalLocalDevDeps.length > 0) {\n const websiteConfig = readProjectConfigurationUnqualified(\n tree,\n frontendProjectConfig.name,\n );\n if (websiteConfig.targets?.['dev']) {\n for (const additional of additionalLocalDevDeps) {\n addDependencyToTargetIfNotPresent(websiteConfig, 'dev', additional);\n }\n updateProjectConfiguration(tree, websiteConfig.name, websiteConfig);\n }\n }\n } else {\n await addPyAgentTargetToLocalDev(\n tree,\n frontendProjectConfig.name,\n agentProjectConfig.name,\n {\n agentName,\n agentNameClassName,\n port: agentPort,\n targetComponent,\n additionalDependencyTargets: additionalLocalDevDeps,\n },\n );\n }\n\n // Recorded so the version sync knows this connection's dependencies are ours.\n addComponentGeneratorMetadata(\n tree,\n frontendProjectConfig.name,\n PY_AGENT_REACT_CONNECTION_GENERATOR_INFO,\n toProjectRelativePath(\n frontendProjectConfig,\n protocol === 'ag-ui'\n ? joinPathFragments(\n frontendProjectConfig.sourceRoot,\n 'hooks',\n `useAgui${agentNameClassName}`,\n )\n : joinPathFragments(\n frontendProjectConfig.sourceRoot,\n 'components',\n `${agentNameClassName}Provider`,\n ),\n ),\n agentNameClassName,\n connectionMetadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n PY_AGENT_REACT_CONNECTION_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\n/**\n * Determine the Python module name from the project configuration\n */\nconst getModuleName = (\n projectConfig: ReturnType<typeof readProjectConfigurationUnqualified>,\n): string => {\n if (projectConfig.sourceRoot) {\n const sourceRootParts = projectConfig.sourceRoot.split('/');\n return sourceRootParts[sourceRootParts.length - 1];\n }\n throw new Error(\n `Could not determine sourceRoot for project ${projectConfig.name}`,\n );\n};\n\nexport default pyAgentReactConnectionGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addAgentRuntimeToConnectionNamespace","DEPENDENCIES","AGUI_DEPENDENCIES","addAgUiReactConnection","resolveAgUiTheme","addOpenApiReactClient","OPEN_API_REACT_DEPENDENCIES","declareDependencies","onlyWhen","formatFilesInSubtree","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","sortObjectKeys","toProjectRelativePath","addPyAgentTargetToLocalDev","openApiClientLocalDevDeps","isHttp","m","protocol","isAgUi","ts","PY_AGENT_REACT_CONNECTION_GENERATOR_INFO","filename","pyAgentReactConnectionGenerator","tree","options","frontendProjectConfig","sourceProject","agentProjectConfig","targetProject","targetComponent","metadata","agentName","name","agentNameClassName","rc","agentPort","port","ports","auth","gatewayRoute","gatewayAuth","toLowerCase","connectionMetadata","theme","Error","additionalLocalDevDeps","moduleName","getModuleName","agentNameSnakeCase","agentTargetPrefix","dirname","root","overwriteStrategy","KeepExisting","openApiTargetName","openApiDist","specPath","targets","cache","executor","outputs","commands","apiName","backendProjectConfig","specBuildProject","specBuildTargetName","isAgentRuntime","skipLocalDev","agentNameKebabCase","length","websiteConfig","additional","additionalDependencyTargets","sourceRoot","preferInstallDependencies","languages","projectConfig","sourceRootParts","split"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/py/agent/react-connection/generator.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 updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addAgentRuntimeToConnectionNamespace } from '../../../connection/agent-runtime-config.js';\nimport type { ResolvedConnectionOptions } from '../../../connection/generator.js';\nimport type { AgentGatewayRoute } from '../../../ts/agent/react-connection/generator.js';\nimport {\n DEPENDENCIES as AGUI_DEPENDENCIES,\n type AgUiAuth,\n addAgUiReactConnection,\n resolveAgUiTheme,\n} from '../../../ts/react-website/agui/generator.js';\nimport {\n addOpenApiReactClient,\n OPEN_API_REACT_DEPENDENCIES,\n} from '../../../utils/connection/open-api/react.js';\nimport {\n declareDependencies,\n onlyWhen,\n} from '../../../utils/declared-dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { installDependencies } from '../../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../../utils/names.js';\nimport {\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n type ComponentMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\nimport { toProjectRelativePath } from '../../../utils/paths.js';\nimport {\n addPyAgentTargetToLocalDev,\n openApiClientLocalDevDeps,\n} from './local-dev.js';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyAgentReactConnectionMetadata {\n readonly protocol: string;\n readonly auth: string;\n /** The AG-UI theme module, which the website's `ux` selects. */\n readonly theme: string;\n}\n\n/** The OpenAPI-over-HTTP path, which the AG-UI path takes none of. */\nconst isHttp = (m: PyAgentReactConnectionMetadata) => m.protocol !== 'ag-ui';\n\n/** The AG-UI path, whose packages `addAgUiReactConnection` adds. */\nconst isAgUi = (m: PyAgentReactConnectionMetadata) => !isHttp(m);\n\n// Each entry names the protocol path it belongs to: the HTTP path's OpenAPI\n// client packages are added by `addOpenApiReactClient`, the AG-UI path's by\n// `addAgUiReactConnection`, both on this generator's behalf. The AG-UI entries\n// keep their own theme and auth conditions, which the metadata below records.\nexport const DEPENDENCIES =\n declareDependencies<PyAgentReactConnectionMetadata>()({\n ts: [\n ...onlyWhen(OPEN_API_REACT_DEPENDENCIES, isHttp),\n ...onlyWhen(AGUI_DEPENDENCIES.ts, isAgUi),\n ],\n });\n\nexport const PY_AGENT_REACT_CONNECTION_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport const pyAgentReactConnectionGenerator = async (\n tree: Tree,\n options: ResolvedConnectionOptions & { gatewayRoute?: AgentGatewayRoute },\n) => {\n const frontendProjectConfig = readProjectConfigurationUnqualified(\n tree,\n options.sourceProject,\n );\n const agentProjectConfig = readProjectConfigurationUnqualified(\n tree,\n options.targetProject,\n );\n\n const targetComponent: ComponentMetadata | undefined =\n options.targetComponent;\n\n // Extract agent metadata from the target component or project metadata\n const metadata = agentProjectConfig.metadata as any;\n const agentName = targetComponent?.name ?? 'agent';\n const agentNameClassName = targetComponent?.rc ?? toClassName(agentName);\n const agentPort = targetComponent?.port ?? metadata?.ports?.[0] ?? 8081;\n // Behind a gateway the browser authenticates with the gateway, not the agent.\n const auth = (\n options.gatewayRoute?.gatewayAuth ??\n targetComponent?.auth ??\n metadata?.auth ??\n 'iam'\n ).toLowerCase();\n const protocol = (targetComponent?.protocol ?? 'http').toLowerCase();\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const connectionMetadata: PyAgentReactConnectionMetadata = {\n protocol,\n auth,\n theme: resolveAgUiTheme(frontendProjectConfig),\n };\n\n if (protocol === 'a2a') {\n throw new Error(\n `Cannot connect a React website to an A2A agent. ` +\n `Consider generating an agent with the HTTP or AG-UI protocol instead.`,\n );\n }\n\n let additionalLocalDevDeps: string[] = [];\n\n if (protocol === 'ag-ui') {\n await addAgUiReactConnection(tree, {\n frontendProjectConfig,\n agentName,\n agentNameClassName,\n auth: auth as AgUiAuth,\n gatewayRoute: options.gatewayRoute,\n });\n } else {\n const moduleName = getModuleName(agentProjectConfig);\n const agentNameSnakeCase = toSnakeCase(agentName);\n const agentTargetPrefix = targetComponent?.name ? agentName : 'agent';\n\n // Add OpenAPI spec generation script scoped to this agent\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files/agent'),\n agentProjectConfig.root,\n {\n moduleName,\n agentNameSnakeCase,\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Instrument the OpenAPI spec generation as a target on the agent project\n const openApiTargetName = `${agentTargetPrefix}-openapi`;\n const openApiDist = joinPathFragments(\n 'dist',\n agentProjectConfig.root,\n 'openapi',\n agentNameSnakeCase,\n );\n const specPath = joinPathFragments(openApiDist, 'openapi.json');\n\n updateProjectConfiguration(tree, agentProjectConfig.name, {\n ...agentProjectConfig,\n targets: sortObjectKeys({\n ...agentProjectConfig.targets,\n [openApiTargetName]: {\n cache: true,\n // The spec serialises models a dependency may own, and this target\n // has no `dependsOn` for `default`'s transitive\n // `dependentTasksOutputFiles` to resolve against — so `^production` is\n // the only edge to the dependency, and without it a model change there\n // serves a stale spec.\n inputs: ['production', '^production'],\n executor: 'nx:run-commands',\n outputs: [\n `{workspaceRoot}/dist/{projectRoot}/openapi/${agentNameSnakeCase}`,\n ],\n options: {\n commands: [\n `uv run python {projectRoot}/scripts/${agentNameSnakeCase}_openapi.py \"dist/{projectRoot}/openapi/${agentNameSnakeCase}/openapi.json\"`,\n ],\n },\n },\n }),\n });\n\n // Use the shared OpenAPI react client utility for hooks, providers, and build targets.\n // The dev target is handled separately below using the agent-specific dev target.\n await addOpenApiReactClient(\n tree,\n {\n apiName: agentNameClassName,\n frontendProjectConfig,\n backendProjectConfig: agentProjectConfig,\n specBuildProject: agentProjectConfig,\n specPath,\n specBuildTargetName: `${agentProjectConfig.name}:${openApiTargetName}`,\n auth,\n port: agentPort,\n isAgentRuntime: true,\n gatewayRoute: options.gatewayRoute,\n skipLocalDev: true,\n },\n DEPENDENCIES,\n );\n\n additionalLocalDevDeps = openApiClientLocalDevDeps(agentNameClassName);\n\n // HTTP only — the AG-UI branch handles this inside addAgUiReactConnection.\n // Agent constructs publish their runtime ARN to the 'agentcore' namespace\n // by default, which isn't exposed to the website; patch them to also\n // publish under 'connection' so the browser can read it. When routing via\n // a gateway, the gateway publishes its own URL instead.\n if (!options.gatewayRoute) {\n await addAgentRuntimeToConnectionNamespace(tree, {\n agentNameKebabCase: kebabCase(agentNameClassName),\n agentNameClassName,\n });\n }\n }\n\n if (options.gatewayRoute) {\n // The gateway react-connection wires the website's dev target to the\n // local gateway (which proxies to the agent); only the OpenAPI client\n // generation targets are still needed here.\n if (additionalLocalDevDeps.length > 0) {\n const websiteConfig = readProjectConfigurationUnqualified(\n tree,\n frontendProjectConfig.name,\n );\n if (websiteConfig.targets?.['dev']) {\n for (const additional of additionalLocalDevDeps) {\n addDependencyToTargetIfNotPresent(websiteConfig, 'dev', additional);\n }\n updateProjectConfiguration(tree, websiteConfig.name, websiteConfig);\n }\n }\n } else {\n await addPyAgentTargetToLocalDev(\n tree,\n frontendProjectConfig.name,\n agentProjectConfig.name,\n {\n agentName,\n agentNameClassName,\n port: agentPort,\n targetComponent,\n additionalDependencyTargets: additionalLocalDevDeps,\n },\n );\n }\n\n // Recorded so the version sync knows this connection's dependencies are ours.\n addComponentGeneratorMetadata(\n tree,\n frontendProjectConfig.name,\n PY_AGENT_REACT_CONNECTION_GENERATOR_INFO,\n toProjectRelativePath(\n frontendProjectConfig,\n protocol === 'ag-ui'\n ? joinPathFragments(\n frontendProjectConfig.sourceRoot,\n 'hooks',\n `useAgui${agentNameClassName}`,\n )\n : joinPathFragments(\n frontendProjectConfig.sourceRoot,\n 'components',\n `${agentNameClassName}Provider`,\n ),\n ),\n agentNameClassName,\n connectionMetadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [\n PY_AGENT_REACT_CONNECTION_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\n/**\n * Determine the Python module name from the project configuration\n */\nconst getModuleName = (\n projectConfig: ReturnType<typeof readProjectConfigurationUnqualified>,\n): string => {\n if (projectConfig.sourceRoot) {\n const sourceRootParts = projectConfig.sourceRoot.split('/');\n return sourceRootParts[sourceRootParts.length - 1];\n }\n throw new Error(\n `Could not determine sourceRoot for project ${projectConfig.name}`,\n );\n};\n\nexport default pyAgentReactConnectionGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addAgentRuntimeToConnectionNamespace","DEPENDENCIES","AGUI_DEPENDENCIES","addAgUiReactConnection","resolveAgUiTheme","addOpenApiReactClient","OPEN_API_REACT_DEPENDENCIES","declareDependencies","onlyWhen","formatFilesInSubtree","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","sortObjectKeys","toProjectRelativePath","addPyAgentTargetToLocalDev","openApiClientLocalDevDeps","isHttp","m","protocol","isAgUi","ts","PY_AGENT_REACT_CONNECTION_GENERATOR_INFO","filename","pyAgentReactConnectionGenerator","tree","options","frontendProjectConfig","sourceProject","agentProjectConfig","targetProject","targetComponent","metadata","agentName","name","agentNameClassName","rc","agentPort","port","ports","auth","gatewayRoute","gatewayAuth","toLowerCase","connectionMetadata","theme","Error","additionalLocalDevDeps","moduleName","getModuleName","agentNameSnakeCase","agentTargetPrefix","dirname","root","overwriteStrategy","KeepExisting","openApiTargetName","openApiDist","specPath","targets","cache","inputs","executor","outputs","commands","apiName","backendProjectConfig","specBuildProject","specBuildTargetName","isAgentRuntime","skipLocalDev","agentNameKebabCase","length","websiteConfig","additional","additionalDependencyTargets","sourceRoot","preferInstallDependencies","languages","projectConfig","sourceRootParts","split"],"mappings":"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"}
@@ -591,27 +591,12 @@ const isRunning = (): boolean => {
591
591
  return result.status === 0 && result.stdout.trim() === 'true';
592
592
  };
593
593
 
594
- // Ensure the image is available locally before starting the container.
595
- const ensureImage = (): void => {
596
- const inspect = spawnSync(containerEngine, ['image', 'inspect', image], {
597
- stdio: 'ignore',
598
- });
599
- if (inspect.status !== 0) {
600
- const pull = spawnSync(containerEngine, ['pull', image], {
601
- stdio: 'inherit',
602
- });
603
- if (pull.status !== 0) process.exit(pull.status ?? 1);
604
- }
605
- };
606
-
607
594
  // Multiple dynamo table packages run dev in parallel sharing the same
608
595
  // container. All processes stream logs, but only the one that created the
609
596
  // container stops it on exit — others just detach.
610
597
  let created = false;
611
598
  let runRetries = 0;
612
599
 
613
- ensureImage();
614
-
615
600
  for (;;) {
616
601
  if (containerExists()) {
617
602
  if (!isRunning()) {
@@ -1327,27 +1312,12 @@ const isRunning = (): boolean => {
1327
1312
  return result.status === 0 && result.stdout.trim() === 'true';
1328
1313
  };
1329
1314
 
1330
- // Ensure the image is available locally before starting the container.
1331
- const ensureImage = (): void => {
1332
- const inspect = spawnSync(containerEngine, ['image', 'inspect', image], {
1333
- stdio: 'ignore',
1334
- });
1335
- if (inspect.status !== 0) {
1336
- const pull = spawnSync(containerEngine, ['pull', image], {
1337
- stdio: 'inherit',
1338
- });
1339
- if (pull.status !== 0) process.exit(pull.status ?? 1);
1340
- }
1341
- };
1342
-
1343
1315
  // Multiple dynamo table packages run dev in parallel sharing the same
1344
1316
  // container. All processes stream logs, but only the one that created the
1345
1317
  // container stops it on exit — others just detach.
1346
1318
  let created = false;
1347
1319
  let runRetries = 0;
1348
1320
 
1349
- ensureImage();
1350
-
1351
1321
  for (;;) {
1352
1322
  if (containerExists()) {
1353
1323
  if (!isRunning()) {