@aws/nx-plugin 1.0.0-rc.71 → 1.0.0-rc.73

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 (168) hide show
  1. package/LICENSE-THIRD-PARTY +210 -730
  2. package/migrations.json +34 -19
  3. package/package.json +4 -4
  4. package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +1 -1
  5. package/src/agentcore-harness/generator.d.ts +1 -1
  6. package/src/infra/app/__snapshots__/generator.spec.ts.snap +3 -3
  7. package/src/infra/app/generator.d.ts +1 -1
  8. package/src/init/generator.d.ts +1 -1
  9. package/src/license/config.d.ts +9 -0
  10. package/src/license/config.js +28 -0
  11. package/src/license/config.js.map +1 -1
  12. package/src/license/dependency-check/collectors/collector.js.map +1 -1
  13. package/src/license/dependency-check/evaluator.js +55 -10
  14. package/src/license/dependency-check/evaluator.js.map +1 -1
  15. package/src/license/generator.js +3 -17
  16. package/src/license/generator.js.map +1 -1
  17. package/src/license/known-exceptions.d.ts +0 -1
  18. package/src/license/known-exceptions.js +1 -23
  19. package/src/license/known-exceptions.js.map +1 -1
  20. package/src/migrations/latest/apt-security-updates-in-container-images/__snapshots__/migration.spec.ts.snap +90 -0
  21. package/src/migrations/latest/apt-security-updates-in-container-images/metadata.json +3 -0
  22. package/src/migrations/latest/apt-security-updates-in-container-images/migration.js +90 -0
  23. package/src/migrations/latest/apt-security-updates-in-container-images/migration.js.map +1 -0
  24. package/src/migrations/latest/remove-mcp-inspector-license-exceptions/metadata.json +3 -0
  25. package/src/migrations/latest/remove-mcp-inspector-license-exceptions/migration.d.ts +6 -0
  26. package/src/migrations/latest/remove-mcp-inspector-license-exceptions/migration.js +38 -0
  27. package/src/migrations/latest/remove-mcp-inspector-license-exceptions/migration.js.map +1 -0
  28. package/src/migrations/v1.0.0-rc.67/0001-smithy-server-package-rename/migration.js.map +1 -0
  29. package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/migration.js.map +1 -0
  30. package/src/migrations/{latest/py-agent-a2a-lifespan-construction → v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction}/migration.js +14 -2
  31. package/src/migrations/v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction/migration.js.map +1 -0
  32. package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/migration.d.ts +6 -0
  33. package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/migration.js.map +1 -0
  34. package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/metadata.json +3 -0
  35. package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.d.ts +2 -0
  36. package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.js +308 -0
  37. package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.js.map +1 -0
  38. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
  39. package/src/preset/generator.d.ts +1 -1
  40. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +626 -10
  41. package/src/py/agent/__snapshots__/generator.core.spec.ts.snap +186 -0
  42. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +55 -11
  43. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +669 -4
  44. package/src/py/agent/a2a-connection/generator.js +5 -11
  45. package/src/py/agent/a2a-connection/generator.js.map +1 -1
  46. package/src/py/agent/files/deploy/Dockerfile.template +7 -0
  47. package/src/py/agent/files/langchain/common/__init__.py.template +0 -0
  48. package/src/py/agent/files/langchain/common/agent.py.template +3 -3
  49. package/src/py/agent/files/langchain/common/session.py.template +61 -0
  50. package/src/py/agent/files/strands/ag-ui/main.py.template +5 -1
  51. package/src/py/agent/files/strands/common/agent.py.template +9 -2
  52. package/src/py/agent/files/strands/common/session.py.template +36 -0
  53. package/src/py/agent/generator.d.ts +11 -1
  54. package/src/py/agent/generator.js +78 -28
  55. package/src/py/agent/generator.js.map +1 -1
  56. package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -0
  57. package/src/py/agent/react-connection/generator.d.ts +1 -1
  58. package/src/py/agent/schema.d.js.map +1 -1
  59. package/src/py/agent/schema.d.ts +1 -1
  60. package/src/py/agent/schema.json +3 -3
  61. package/src/py/fast-api/react/generator.d.ts +1 -1
  62. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +5 -5
  63. package/src/py/mcp-server/files/deploy/Dockerfile.template +7 -0
  64. package/src/py/mcp-server/generator.js +8 -3
  65. package/src/py/mcp-server/generator.js.map +1 -1
  66. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +7 -5
  67. package/src/py/rdb/generator.js +36 -2
  68. package/src/py/rdb/generator.js.map +1 -1
  69. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +14 -14
  70. package/src/smithy/project/generator.d.ts +1 -1
  71. package/src/smithy/react-connection/generator.d.ts +1 -1
  72. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1 -1
  73. package/src/terraform/project/generator.d.ts +1 -1
  74. package/src/trpc/react/generator.d.ts +1 -1
  75. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +36 -8
  76. package/src/ts/agent/a2a-connection/generator.d.ts +1 -1
  77. package/src/ts/agent/a2a-connection/generator.js +4 -2
  78. package/src/ts/agent/a2a-connection/generator.js.map +1 -1
  79. package/src/ts/agent/files/deploy/Dockerfile.template +7 -0
  80. package/src/ts/agent/gateway-connection/generator.d.ts +1 -1
  81. package/src/ts/agent/mcp-connection/generator.d.ts +1 -1
  82. package/src/ts/agent/react-connection/generator.d.ts +1 -1
  83. package/src/ts/astro-docs/generator.d.ts +1 -1
  84. package/src/ts/dcr-proxy/generator.d.ts +1 -1
  85. package/src/ts/dynamodb/generator.d.ts +1 -1
  86. package/src/ts/lambda-function/generator.d.ts +1 -1
  87. package/src/ts/lib/generator.d.ts +1 -1
  88. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +2 -2
  89. package/src/ts/mcp-server/files/Dockerfile.template +7 -0
  90. package/src/ts/mcp-server/generator.js +8 -3
  91. package/src/ts/mcp-server/generator.js.map +1 -1
  92. package/src/ts/nx-generator/generator.d.ts +1 -1
  93. package/src/ts/nx-migration/generator.d.ts +1 -1
  94. package/src/ts/nx-plugin/generator.d.ts +1 -1
  95. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +8 -6
  96. package/src/ts/rdb/generator.d.ts +1 -1
  97. package/src/ts/rdb/generator.js +29 -2
  98. package/src/ts/rdb/generator.js.map +1 -1
  99. package/src/ts/react-website/agui/generator.d.ts +1 -1
  100. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +15 -15
  101. package/src/ts/react-website/app/generator.js +4 -2
  102. package/src/ts/react-website/app/generator.js.map +1 -1
  103. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +1 -1
  104. package/src/utils/agent-connection/agent-connection.d.ts +10 -0
  105. package/src/utils/agent-connection/agent-connection.js +20 -9
  106. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  107. package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +5 -3
  108. package/src/utils/agent-connection/files/py-core-langchain/s3/s3_checkpoint_saver_langchain.py.template +360 -0
  109. package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +2 -4
  110. package/src/utils/agent-connection/files/py-core-strands/base/tool_errors_strands.py.template +24 -0
  111. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +1 -1
  112. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  113. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +113 -13
  114. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +76 -7
  115. package/src/utils/ast.d.ts +29 -0
  116. package/src/utils/ast.js +31 -0
  117. package/src/utils/ast.js.map +1 -1
  118. package/src/utils/metrics.js +2 -2
  119. package/src/utils/metrics.js.map +1 -1
  120. package/src/utils/versions.d.ts +75 -72
  121. package/src/utils/versions.js +72 -69
  122. package/src/utils/versions.js.map +1 -1
  123. package/src/migrations/latest/py-agent-a2a-httpx-client-per-call/migration.js.map +0 -1
  124. package/src/migrations/latest/py-agent-a2a-lifespan-construction/migration.js.map +0 -1
  125. package/src/migrations/latest/smithy-server-package-rename/migration.js.map +0 -1
  126. package/src/migrations/latest/translate-script-whole-file-writes/migration.js.map +0 -1
  127. package/src/py/rdb/files/__name__/__init__.py.template +0 -3
  128. package/src/py/rdb/files/config.json.template +0 -14
  129. package/src/ts/rdb/files/config.json.template +0 -14
  130. package/src/ts/rdb/files/src/index.ts.template +0 -1
  131. /package/src/migrations/latest/{py-agent-a2a-httpx-client-per-call → apt-security-updates-in-container-images}/migration.d.ts +0 -0
  132. /package/src/migrations/{latest/smithy-server-package-rename → v1.0.0-rc.67/0001-smithy-server-package-rename}/metadata.json +0 -0
  133. /package/src/migrations/{latest/py-agent-a2a-lifespan-construction → v1.0.0-rc.67/0001-smithy-server-package-rename}/migration.d.ts +0 -0
  134. /package/src/migrations/{latest/smithy-server-package-rename → v1.0.0-rc.67/0001-smithy-server-package-rename}/migration.js +0 -0
  135. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/build-system-prompt.ts.fixture +0 -0
  136. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/build-user-prompt.ts.fixture +0 -0
  137. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/config-path.ts.fixture +0 -0
  138. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/file-to-translate.ts.fixture +0 -0
  139. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/get-files-to-translate.ts.fixture +0 -0
  140. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/header.ts.fixture +0 -0
  141. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/log.ts.fixture +0 -0
  142. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/main-call.ts.fixture +0 -0
  143. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/main.ts.fixture +0 -0
  144. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/project-root.ts.fixture +0 -0
  145. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/run-with-concurrency.ts.fixture +0 -0
  146. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/scripts-dir.ts.fixture +0 -0
  147. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/files/translate-file-for-language.ts.fixture +0 -0
  148. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/already-migrated.grit +0 -0
  149. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/build-system-prompt.grit +0 -0
  150. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/build-user-prompt.grit +0 -0
  151. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/config-path.grit +0 -0
  152. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/file-to-translate.grit +0 -0
  153. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/get-files-to-translate.grit +0 -0
  154. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/log.grit +0 -0
  155. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/main-call.grit +0 -0
  156. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/main.grit +0 -0
  157. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/project-root.grit +0 -0
  158. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/run-with-concurrency.grit +0 -0
  159. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/grit/translate-file-for-language.grit +0 -0
  160. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/metadata.json +0 -0
  161. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/migration.d.ts +0 -0
  162. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/migration.js +0 -0
  163. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/test-fixtures/released-script-first.ts.fixture +0 -0
  164. /package/src/migrations/{latest/translate-script-whole-file-writes → v1.0.0-rc.68/0001-translate-script-whole-file-writes}/test-fixtures/released-script.ts.fixture +0 -0
  165. /package/src/migrations/{latest/py-agent-a2a-lifespan-construction → v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction}/metadata.json +0 -0
  166. /package/src/migrations/{latest/smithy-server-package-rename → v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction}/migration.d.ts +0 -0
  167. /package/src/migrations/{latest/py-agent-a2a-httpx-client-per-call → v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call}/metadata.json +0 -0
  168. /package/src/migrations/{latest/py-agent-a2a-httpx-client-per-call → v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call}/migration.js +0 -0
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { readFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { getProjects, joinPathFragments, visitNotIgnoredFiles } from "@nx/devkit";
7
+ import { PY_AGENT_GENERATOR_INFO } from "../../../py/agent/generator.js";
8
+ import { addPyDependencies } from "../../../utils/add-dependencies.js";
9
+ import { addPythonReExport, getPythonAgentConnectionModuleName, getPythonAgentConnectionProjectDir } from "../../../utils/agent-connection/agent-connection.js";
10
+ import { applyGritQL, captureGritQLVariable, matchGritQL } from "../../../utils/ast.js";
11
+ import { declareDependencies } from "../../../utils/declared-dependencies.js";
12
+ import { formatFilesInSubtree } from "../../../utils/format.js";
13
+ import { kebabCase } from "../../../utils/names.js";
14
+ import { getRelativePathToRootByDirectory, toProjectRelativePath } from "../../../utils/paths.js";
15
+ /**
16
+ * Add session management support to py#agent.
17
+ *
18
+ * How to write a migration:
19
+ * - https://nx.dev/docs/kb/migration-generators
20
+ * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject
21
+ *
22
+ * Guardrails:
23
+ * - Pattern-match before writing: skip files that have diverged from the shape
24
+ * your generators produce and report them via `nextSteps`, rather than
25
+ * clobbering the user's changes.
26
+ * - Idempotent: re-running must be a no-op.
27
+ * - Format what you write: finish with `formatFilesInSubtree` so the files
28
+ * this migration wrote are formatted correctly.
29
+ */ // Captures the agent-connection module a file imports `log_model_errors` (or
30
+ // `session_id_context`) from, and gates every rewrite below on the import
31
+ // actually being present. Generic over `$names` since a connection generator
32
+ // may have merged its own import into the same line.
33
+ const LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN = 'language python\n`from $mod import $names` where { $names <: contains `log_model_errors` }';
34
+ const SESSION_ID_CONTEXT_IMPORT_CAPTURE_PATTERN = 'language python\n`from $mod import $names` where { $names <: contains `session_id_context` }';
35
+ const DEPENDENCIES = declareDependencies()({
36
+ py: [
37
+ {
38
+ name: 'langgraph-checkpoint-sqlite'
39
+ },
40
+ {
41
+ name: 'aiosqlite'
42
+ }
43
+ ],
44
+ ts: []
45
+ });
46
+ const LANGCHAIN_AGENT_MATCH_PATTERN = 'language python\n`create_agent($args)` where { $args <: contains `system_prompt=$_`, $args <: contains `checkpointer=InMemorySaver()` }';
47
+ const LANGCHAIN_CHECKPOINTER_PATTERN = 'language python\n`checkpointer=InMemorySaver()` => `checkpointer=get_checkpointer()`';
48
+ const LANGCHAIN_IN_MEMORY_IMPORT_PATTERN = 'language python\n`from langgraph.checkpoint.memory import InMemorySaver` => .';
49
+ const langChainSessionImportPattern = 'language python\n`from langchain.agents import create_agent` => raw`from langchain.agents import create_agent\n\nfrom .session import get_checkpointer`';
50
+ // Every strands agent.py already hooks log_model_errors regardless of
51
+ // protocol (hooks, unlike session_manager, carry over per-thread for AG-UI
52
+ // without special wiring — see StrandsAgent's kwargs-forwarding), so
53
+ // log_tool_errors is retrofitted the same way for every protocol.
54
+ const LOG_TOOL_ERRORS_HOOKS_PATTERN = 'language python\n`hooks=[$hooks]` where { $hooks <: contains `log_model_errors`, $hooks <: not contains `log_tool_errors` }';
55
+ const logToolErrorsImportPattern = (mod)=>`language python\n\`from contextlib import contextmanager\` => raw\`from contextlib import contextmanager\nfrom ${mod} import log_tool_errors\``;
56
+ const LOG_TOOL_ERRORS_WRITE_PATTERN = 'language python\n`hooks=[log_model_errors]` => `hooks=[log_model_errors, log_tool_errors]`';
57
+ // Existing agent-connection projects predate tool_errors_strands.py. This has
58
+ // no EJS templating, so it's read verbatim from the generator's own template
59
+ // rather than kept as a second, hand-copied source of truth.
60
+ const TOOL_ERRORS_STRANDS_PY_CONTENT = readFileSync(join(import.meta.dirname, '../../../utils/agent-connection/files/py-core-strands/base/tool_errors_strands.py.template'), 'utf-8');
61
+ /**
62
+ * Ensures the shared Python agent-connection project has tool_errors_strands.py
63
+ * and re-exports log_tool_errors, backfilling projects generated before this
64
+ * helper existed. Returns false (and leaves the tree untouched) if the
65
+ * agent-connection project itself can't be found.
66
+ */ async function ensureToolErrorsBase(tree) {
67
+ const projectDir = getPythonAgentConnectionProjectDir(tree);
68
+ if (!tree.exists(joinPathFragments(projectDir, 'project.json'))) {
69
+ return false;
70
+ }
71
+ const moduleDir = joinPathFragments(projectDir, getPythonAgentConnectionModuleName(tree));
72
+ const toolErrorsPath = joinPathFragments(moduleDir, 'core', 'tool_errors_strands.py');
73
+ if (!tree.exists(toolErrorsPath)) {
74
+ tree.write(toolErrorsPath, TOOL_ERRORS_STRANDS_PY_CONTENT);
75
+ }
76
+ await addPythonReExport(tree, joinPathFragments(moduleDir, '__init__.py'), '.core.tool_errors_strands', 'log_tool_errors');
77
+ return true;
78
+ }
79
+ // HTTP/A2A agents build one Agent per session (via with_session_id), so
80
+ // wiring `session_manager` directly into the constructor is safe. Anchored
81
+ // on a `tools=` keyword argument so this only matches an inline kwargs call
82
+ // (as the generator produces), not e.g. `Agent(**agent_kwargs)`.
83
+ const AGENT_PY_CONSTRUCTOR_MATCH_PATTERN = 'language python\n`Agent($args)` where { $args <: contains `tools=$_` }';
84
+ const AGENT_PY_SESSION_MANAGER_PATTERN = 'language python\n`yield Agent($args)` => `yield Agent(session_manager=get_session_manager(), $args)` where { $args <: not contains `session_manager=$_` }';
85
+ const AGENT_PY_SESSION_IMPORT_PATTERN = 'language python\n`from contextlib import contextmanager` => raw`from contextlib import contextmanager\n\nfrom .session import get_session_manager`';
86
+ // AG-UI's StrandsAgent adapter needs a session_manager_provider (called once
87
+ // per thread_id) rather than a plain session_manager.
88
+ const AGUI_MAIN_IMPORT_PATTERN = 'language python\n`from ag_ui_strands import $names` => `from ag_ui_strands import StrandsAgentConfig, $names` where { $names <: contains `StrandsAgent`, $names <: not contains `StrandsAgentConfig` }';
89
+ const AGUI_MAIN_CONSTRUCTOR_MATCH_PATTERN = 'language python\n`StrandsAgent($args)` where { $args <: contains `agent=$_` }';
90
+ const AGUI_MAIN_CONSTRUCTOR_PATTERN = `${AGUI_MAIN_CONSTRUCTOR_MATCH_PATTERN} => \`StrandsAgent(config=StrandsAgentConfig(session_manager_provider=lambda _input_data: get_session_manager()), $args)\` where { $args <: not contains \`config=\` }`;
91
+ const AGUI_MAIN_SESSION_IMPORT_PATTERN = 'language python\n`from .agent import get_agent` => raw`from .agent import get_agent\nfrom .session import get_session_manager` where { $program <: not contains `from .session import get_session_manager` }';
92
+ // Existing agents predate session.py, so there's no prior storage to
93
+ // preserve — default to in-memory, mirroring the ts#agent migration.
94
+ const legacySessionManagerContent = (agentConnectionModule, localSessionsDir)=>`import os
95
+
96
+ from strands.session import FileSessionManager, SessionManager
97
+
98
+ from ${agentConnectionModule} import get_current_session_id
99
+
100
+
101
+ def get_session_manager() -> SessionManager | None:
102
+ """Returns a SessionManager for persisting conversation state across
103
+ invocations. Local development always uses local file storage for
104
+ convenience, regardless of the configured session option. Without a
105
+ configured session option, conversation state is kept in memory only and
106
+ does not survive process restarts.
107
+ """
108
+ session_id = get_current_session_id()
109
+ if not session_id:
110
+ raise RuntimeError(
111
+ "No current session id — cannot resolve a SessionManager outside of a request scope."
112
+ )
113
+ if os.environ.get("LOCAL_DEV") == "true":
114
+ return FileSessionManager(session_id=session_id, storage_dir="${localSessionsDir}")
115
+ return None
116
+ `;
117
+ const legacyLangChainSessionContent = (localSessionsDir)=>`import os
118
+
119
+ import aiosqlite
120
+ from langgraph.checkpoint.base import BaseCheckpointSaver
121
+ from langgraph.checkpoint.memory import InMemorySaver
122
+ from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
123
+
124
+
125
+ def get_checkpointer() -> BaseCheckpointSaver:
126
+ """Returns the checkpointer used to persist conversation state."""
127
+ if os.environ.get("LOCAL_DEV") == "true":
128
+ os.makedirs("${localSessionsDir}", exist_ok=True)
129
+ conn = aiosqlite.connect(os.path.join("${localSessionsDir}", "checkpoints.sqlite"))
130
+ return AsyncSqliteSaver(conn)
131
+ return InMemorySaver()
132
+ `;
133
+ /** The Nx project owning `dirPath`, if any (the longest-matching project.root). */ const findOwningProject = (tree, dirPath)=>{
134
+ let best;
135
+ for (const project of getProjects(tree).values()){
136
+ if ((dirPath === project.root || dirPath.startsWith(`${project.root}/`)) && (!best || project.root.length > best.root.length)) {
137
+ best = project;
138
+ }
139
+ }
140
+ return best;
141
+ };
142
+ /** This agent's metadata, accepting both current and legacy component paths. */ const findAgentComponentMetadata = (project, dirRelativeToProjectRoot)=>project.metadata?.components?.find((component)=>component.generator === PY_AGENT_GENERATOR_INFO.id && (component.path === dirRelativeToProjectRoot || component.path === `${dirRelativeToProjectRoot}/agent.py`));
143
+ /**
144
+ * This agent's real kebab-case name — the generator's own target-prefix
145
+ * (ComponentMetadata's `name` field), used directly rather than
146
+ * reconstructing it by kebab-casing the class name (`rc`). That round trip
147
+ * loses word boundaries for names with single-letter segments, e.g.
148
+ * `kebabCase("OldSHttp")` => "old-shttp", not the real "old-s-http".
149
+ *
150
+ * When no `--name` was given at generation time, the generator falls back
151
+ * to `${project}-agent` for the real name, but records a literal 'agent' as
152
+ * the target-prefix — indistinguishable from an agent explicitly named
153
+ * "agent" — so re-derive the fallback from the project name in that case,
154
+ * exactly as the generator itself does.
155
+ */ const agentTmpNameFor = (project, dir)=>{
156
+ const dirRelativeToProjectRoot = toProjectRelativePath(project, dir);
157
+ const targetPrefix = findAgentComponentMetadata(project, dirRelativeToProjectRoot)?.name;
158
+ if (!targetPrefix) return undefined;
159
+ if (targetPrefix !== 'agent') return targetPrefix;
160
+ return kebabCase(`${project.name.split('.').pop() ?? project.name}-agent`);
161
+ };
162
+ /** This agent's protocol + framework, from its ComponentMetadata entry. */ const agentComponentFor = (project, dir)=>{
163
+ const dirRelativeToProjectRoot = toProjectRelativePath(project, dir);
164
+ return findAgentComponentMetadata(project, dirRelativeToProjectRoot);
165
+ };
166
+ /** The relative path from `projectRoot` up to this agent's workspace-root-level local session storage. */ const localSessionsDirFor = (projectRoot, agentTmpName, framework = 'strands')=>joinPathFragments(getRelativePathToRootByDirectory(projectRoot), `tmp/agents/${framework}/${agentTmpName}`);
167
+ export default async function migration(tree) {
168
+ const nextSteps = [];
169
+ const filePaths = [];
170
+ visitNotIgnoredFiles(tree, '', (filePath)=>filePaths.push(filePath));
171
+ for (const filePath of filePaths){
172
+ if (filePath.endsWith('/agent.py')) {
173
+ // log_tool_errors applies to every protocol (unlike session_manager),
174
+ // so retrofit it independently of whether the owning project can be
175
+ // resolved below. LOG_TOOL_ERRORS_HOOKS_PATTERN's own `where` clause
176
+ // (contains log_model_errors, not already containing log_tool_errors)
177
+ // doubles as the "still needs retrofitting" check.
178
+ if (await matchGritQL(tree, filePath, LOG_TOOL_ERRORS_HOOKS_PATTERN)) {
179
+ const mod = await captureGritQLVariable(tree, filePath, LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN, 'mod');
180
+ if (await ensureToolErrorsBase(tree) && mod) {
181
+ await applyGritQL(tree, filePath, logToolErrorsImportPattern(mod));
182
+ await applyGritQL(tree, filePath, LOG_TOOL_ERRORS_WRITE_PATTERN);
183
+ } else {
184
+ nextSteps.push(`${filePath}: could not find the shared agent-connection project — manually add \`log_tool_errors\` to the hooks list (see the py#agent generator's template).`);
185
+ }
186
+ }
187
+ const dir = filePath.split('/').slice(0, -1).join('/');
188
+ const project = findOwningProject(tree, dir);
189
+ // Without a registered project there's no ComponentMetadata, so this
190
+ // agent's protocol/framework/agent-connection module can't be
191
+ // resolved — and a pre-migration AG-UI agent.py is textually identical
192
+ // to an HTTP/A2A one, so there's nothing left to safely guess from.
193
+ if (!project) {
194
+ if (await matchGritQL(tree, filePath, LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN)) {
195
+ nextSteps.push(`${filePath}: could not determine the project root — manually verify whether this is an AG-UI or HTTP/A2A Strands agent and wire session_manager in accordingly (see the py#agent generator's template).`);
196
+ }
197
+ continue;
198
+ }
199
+ const component = agentComponentFor(project, dir);
200
+ if (component?.framework === 'langchain') {
201
+ const content = tree.read(filePath, 'utf-8') ?? '';
202
+ if (content.includes('checkpointer=get_checkpointer()')) {
203
+ continue;
204
+ }
205
+ if (!await matchGritQL(tree, filePath, LANGCHAIN_AGENT_MATCH_PATTERN)) {
206
+ nextSteps.push(`${filePath}: the create_agent call has diverged from the generated shape — manually create ${dir}/session.py and pass \`checkpointer=get_checkpointer()\` to \`create_agent\` (see the py#agent generator's template).`);
207
+ continue;
208
+ }
209
+ const agentName = agentTmpNameFor(project, dir);
210
+ const sessionPath = `${dir}/session.py`;
211
+ if (!agentName) {
212
+ nextSteps.push(`${filePath}: could not determine this agent's name from its ComponentMetadata — manually create ${sessionPath} and pass \`checkpointer=get_checkpointer()\` to \`create_agent\` (see the py#agent generator's template).`);
213
+ continue;
214
+ }
215
+ if (!tree.exists(sessionPath)) {
216
+ tree.write(sessionPath, legacyLangChainSessionContent(localSessionsDirFor(project.root, agentName, 'langchain')));
217
+ }
218
+ addPyDependencies(tree, DEPENDENCIES, {
219
+ projectRoot: project.root
220
+ });
221
+ await applyGritQL(tree, filePath, langChainSessionImportPattern);
222
+ await applyGritQL(tree, filePath, LANGCHAIN_IN_MEMORY_IMPORT_PATTERN);
223
+ await applyGritQL(tree, filePath, LANGCHAIN_CHECKPOINTER_PATTERN);
224
+ const migratedContent = tree.read(filePath, 'utf-8') ?? '';
225
+ if (!migratedContent.includes('from .session import get_checkpointer') || !migratedContent.includes('checkpointer=get_checkpointer()')) {
226
+ nextSteps.push(`${filePath}: session.py was created but the checkpointer could not be wired automatically — import \`get_checkpointer\` from it and pass \`checkpointer=get_checkpointer()\` to \`create_agent\`.`);
227
+ }
228
+ continue;
229
+ }
230
+ // AG-UI wires session_manager_provider on the StrandsAgent adapter in
231
+ // main.py instead — handled by the branch below.
232
+ if (component?.protocol === 'ag-ui') {
233
+ continue;
234
+ }
235
+ if (!component?.protocol) {
236
+ if (await matchGritQL(tree, filePath, LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN)) {
237
+ nextSteps.push(`${filePath}: could not determine this agent's protocol/framework from its ComponentMetadata — manually verify whether it's AG-UI or HTTP/A2A Strands and wire session_manager in accordingly (see the py#agent generator's template).`);
238
+ }
239
+ continue;
240
+ }
241
+ // HTTP/A2A: wire session_manager into the Agent constructor and create
242
+ // the sibling session.py if it doesn't exist yet.
243
+ if (!await matchGritQL(tree, filePath, LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN)) {
244
+ continue;
245
+ }
246
+ const sessionPath = `${dir}/session.py`;
247
+ if (!await matchGritQL(tree, filePath, AGENT_PY_CONSTRUCTOR_MATCH_PATTERN)) {
248
+ nextSteps.push(`${filePath}: the Agent is not constructed with an inline \`Agent(...)\` call, so session_manager could not be wired in automatically. Manually add \`session_manager=get_session_manager()\` to its constructor (see the py#agent generator's template), creating ${sessionPath} first if it doesn't already exist.`);
249
+ continue;
250
+ }
251
+ if (!tree.exists(sessionPath)) {
252
+ const mod = await captureGritQLVariable(tree, filePath, LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN, 'mod');
253
+ const agentName = agentTmpNameFor(project, dir);
254
+ if (mod && agentName) {
255
+ tree.write(sessionPath, legacySessionManagerContent(mod, localSessionsDirFor(project.root, agentName)));
256
+ } else {
257
+ nextSteps.push(`${filePath}: could not determine the agent-connection module or this agent's name from its ComponentMetadata — manually create ${sessionPath} (see the py#agent generator's template) and wire \`session_manager=get_session_manager()\` into the Agent constructor.`);
258
+ continue;
259
+ }
260
+ }
261
+ const agentContent = tree.read(filePath, 'utf-8') ?? '';
262
+ if (!agentContent.includes('from .session import get_session_manager')) {
263
+ await applyGritQL(tree, filePath, AGENT_PY_SESSION_IMPORT_PATTERN);
264
+ await applyGritQL(tree, filePath, AGENT_PY_SESSION_MANAGER_PATTERN);
265
+ }
266
+ if (!(tree.read(filePath, 'utf-8') ?? '').includes('get_session_manager')) {
267
+ nextSteps.push(`${filePath}: found ${sessionPath} but couldn't confirm the get_session_manager import — wire \`session_manager=get_session_manager()\` into the Agent constructor manually.`);
268
+ continue;
269
+ }
270
+ continue;
271
+ }
272
+ if (filePath.endsWith('/main.py') && (tree.read(filePath, 'utf-8') ?? '').includes('ag_ui_strands')) {
273
+ const alreadyWired = (tree.read(filePath, 'utf-8') ?? '').includes('StrandsAgentConfig');
274
+ if (!alreadyWired) {
275
+ const needsWiring = await matchGritQL(tree, filePath, AGUI_MAIN_CONSTRUCTOR_MATCH_PATTERN);
276
+ if (!needsWiring) {
277
+ nextSteps.push(`${filePath}: the StrandsAgent constructor has diverged from the generated shape - left as-is. Manually add \`config=StrandsAgentConfig(session_manager_provider=lambda _input_data: get_session_manager())\` to it (see the py#agent generator's template).`);
278
+ continue;
279
+ }
280
+ await applyGritQL(tree, filePath, AGUI_MAIN_IMPORT_PATTERN);
281
+ await applyGritQL(tree, filePath, AGUI_MAIN_CONSTRUCTOR_PATTERN);
282
+ }
283
+ const dir = filePath.split('/').slice(0, -1).join('/');
284
+ const sessionPath = `${dir}/session.py`;
285
+ if (!tree.exists(sessionPath)) {
286
+ const project = findOwningProject(tree, dir);
287
+ const mod = await captureGritQLVariable(tree, filePath, SESSION_ID_CONTEXT_IMPORT_CAPTURE_PATTERN, 'mod');
288
+ const agentName = project && agentTmpNameFor(project, dir);
289
+ if (project && mod && agentName) {
290
+ tree.write(sessionPath, legacySessionManagerContent(mod, localSessionsDirFor(project.root, agentName)));
291
+ } else {
292
+ nextSteps.push(`${filePath}: could not determine the project root, agent-connection module, or this agent's name from its ComponentMetadata — manually create ${sessionPath} (see the py#agent generator's template) and wire \`config=StrandsAgentConfig(session_manager_provider=lambda _input_data: get_session_manager())\` into the StrandsAgent constructor.`);
293
+ continue;
294
+ }
295
+ }
296
+ await applyGritQL(tree, filePath, AGUI_MAIN_SESSION_IMPORT_PATTERN);
297
+ if (!(tree.read(filePath, 'utf-8') ?? '').includes('get_session_manager')) {
298
+ nextSteps.push(`${filePath}: found ${sessionPath} but couldn't confirm the get_session_manager import — wire it into the StrandsAgent constructor manually.`);
299
+ }
300
+ }
301
+ }
302
+ await formatFilesInSubtree(tree);
303
+ return {
304
+ nextSteps
305
+ };
306
+ }
307
+
308
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type Tree,\n visitNotIgnoredFiles,\n} from '@nx/devkit';\nimport { PY_AGENT_GENERATOR_INFO } from '../../../py/agent/generator';\nimport { addPyDependencies } from '../../../utils/add-dependencies';\nimport {\n addPythonReExport,\n getPythonAgentConnectionModuleName,\n getPythonAgentConnectionProjectDir,\n} from '../../../utils/agent-connection/agent-connection';\nimport {\n applyGritQL,\n captureGritQLVariable,\n matchGritQL,\n} from '../../../utils/ast';\nimport { declareDependencies } from '../../../utils/declared-dependencies';\nimport { formatFilesInSubtree } from '../../../utils/format';\nimport { kebabCase } from '../../../utils/names';\nimport type { ComponentMetadata } from '../../../utils/nx';\nimport {\n getRelativePathToRootByDirectory,\n toProjectRelativePath,\n} from '../../../utils/paths';\n\n/**\n * Add session management support to py#agent.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Pattern-match before writing: skip files that have diverged from the shape\n * your generators produce and report them via `nextSteps`, rather than\n * clobbering the user's changes.\n * - Idempotent: re-running must be a no-op.\n * - Format what you write: finish with `formatFilesInSubtree` so the files\n * this migration wrote are formatted correctly.\n */\n\n// Captures the agent-connection module a file imports `log_model_errors` (or\n// `session_id_context`) from, and gates every rewrite below on the import\n// actually being present. Generic over `$names` since a connection generator\n// may have merged its own import into the same line.\nconst LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN =\n 'language python\\n`from $mod import $names` where { $names <: contains `log_model_errors` }';\nconst SESSION_ID_CONTEXT_IMPORT_CAPTURE_PATTERN =\n 'language python\\n`from $mod import $names` where { $names <: contains `session_id_context` }';\n\nconst DEPENDENCIES = declareDependencies()({\n py: [{ name: 'langgraph-checkpoint-sqlite' }, { name: 'aiosqlite' }],\n ts: [],\n});\n\nconst LANGCHAIN_AGENT_MATCH_PATTERN =\n 'language python\\n`create_agent($args)` where { $args <: contains `system_prompt=$_`, $args <: contains `checkpointer=InMemorySaver()` }';\nconst LANGCHAIN_CHECKPOINTER_PATTERN =\n 'language python\\n`checkpointer=InMemorySaver()` => `checkpointer=get_checkpointer()`';\nconst LANGCHAIN_IN_MEMORY_IMPORT_PATTERN =\n 'language python\\n`from langgraph.checkpoint.memory import InMemorySaver` => .';\nconst langChainSessionImportPattern =\n 'language python\\n`from langchain.agents import create_agent` => raw`from langchain.agents import create_agent\\n\\nfrom .session import get_checkpointer`';\n\n// Every strands agent.py already hooks log_model_errors regardless of\n// protocol (hooks, unlike session_manager, carry over per-thread for AG-UI\n// without special wiring — see StrandsAgent's kwargs-forwarding), so\n// log_tool_errors is retrofitted the same way for every protocol.\nconst LOG_TOOL_ERRORS_HOOKS_PATTERN =\n 'language python\\n`hooks=[$hooks]` where { $hooks <: contains `log_model_errors`, $hooks <: not contains `log_tool_errors` }';\nconst logToolErrorsImportPattern = (mod: string) =>\n `language python\\n\\`from contextlib import contextmanager\\` => raw\\`from contextlib import contextmanager\\nfrom ${mod} import log_tool_errors\\``;\nconst LOG_TOOL_ERRORS_WRITE_PATTERN =\n 'language python\\n`hooks=[log_model_errors]` => `hooks=[log_model_errors, log_tool_errors]`';\n\n// Existing agent-connection projects predate tool_errors_strands.py. This has\n// no EJS templating, so it's read verbatim from the generator's own template\n// rather than kept as a second, hand-copied source of truth.\nconst TOOL_ERRORS_STRANDS_PY_CONTENT = readFileSync(\n join(\n import.meta.dirname,\n '../../../utils/agent-connection/files/py-core-strands/base/tool_errors_strands.py.template',\n ),\n 'utf-8',\n);\n\n/**\n * Ensures the shared Python agent-connection project has tool_errors_strands.py\n * and re-exports log_tool_errors, backfilling projects generated before this\n * helper existed. Returns false (and leaves the tree untouched) if the\n * agent-connection project itself can't be found.\n */\nasync function ensureToolErrorsBase(tree: Tree): Promise<boolean> {\n const projectDir = getPythonAgentConnectionProjectDir(tree);\n if (!tree.exists(joinPathFragments(projectDir, 'project.json'))) {\n return false;\n }\n const moduleDir = joinPathFragments(\n projectDir,\n getPythonAgentConnectionModuleName(tree),\n );\n const toolErrorsPath = joinPathFragments(\n moduleDir,\n 'core',\n 'tool_errors_strands.py',\n );\n if (!tree.exists(toolErrorsPath)) {\n tree.write(toolErrorsPath, TOOL_ERRORS_STRANDS_PY_CONTENT);\n }\n await addPythonReExport(\n tree,\n joinPathFragments(moduleDir, '__init__.py'),\n '.core.tool_errors_strands',\n 'log_tool_errors',\n );\n return true;\n}\n\n// HTTP/A2A agents build one Agent per session (via with_session_id), so\n// wiring `session_manager` directly into the constructor is safe. Anchored\n// on a `tools=` keyword argument so this only matches an inline kwargs call\n// (as the generator produces), not e.g. `Agent(**agent_kwargs)`.\nconst AGENT_PY_CONSTRUCTOR_MATCH_PATTERN =\n 'language python\\n`Agent($args)` where { $args <: contains `tools=$_` }';\nconst AGENT_PY_SESSION_MANAGER_PATTERN =\n 'language python\\n`yield Agent($args)` => `yield Agent(session_manager=get_session_manager(), $args)` where { $args <: not contains `session_manager=$_` }';\nconst AGENT_PY_SESSION_IMPORT_PATTERN =\n 'language python\\n`from contextlib import contextmanager` => raw`from contextlib import contextmanager\\n\\nfrom .session import get_session_manager`';\n\n// AG-UI's StrandsAgent adapter needs a session_manager_provider (called once\n// per thread_id) rather than a plain session_manager.\nconst AGUI_MAIN_IMPORT_PATTERN =\n 'language python\\n`from ag_ui_strands import $names` => `from ag_ui_strands import StrandsAgentConfig, $names` where { $names <: contains `StrandsAgent`, $names <: not contains `StrandsAgentConfig` }';\nconst AGUI_MAIN_CONSTRUCTOR_MATCH_PATTERN =\n 'language python\\n`StrandsAgent($args)` where { $args <: contains `agent=$_` }';\nconst AGUI_MAIN_CONSTRUCTOR_PATTERN = `${AGUI_MAIN_CONSTRUCTOR_MATCH_PATTERN} => \\`StrandsAgent(config=StrandsAgentConfig(session_manager_provider=lambda _input_data: get_session_manager()), $args)\\` where { $args <: not contains \\`config=\\` }`;\nconst AGUI_MAIN_SESSION_IMPORT_PATTERN =\n 'language python\\n`from .agent import get_agent` => raw`from .agent import get_agent\\nfrom .session import get_session_manager` where { $program <: not contains `from .session import get_session_manager` }';\n\n// Existing agents predate session.py, so there's no prior storage to\n// preserve — default to in-memory, mirroring the ts#agent migration.\nconst legacySessionManagerContent = (\n agentConnectionModule: string,\n localSessionsDir: string,\n): string =>\n `import os\n\nfrom strands.session import FileSessionManager, SessionManager\n\nfrom ${agentConnectionModule} import get_current_session_id\n\n\ndef get_session_manager() -> SessionManager | None:\n \"\"\"Returns a SessionManager for persisting conversation state across\n invocations. Local development always uses local file storage for\n convenience, regardless of the configured session option. Without a\n configured session option, conversation state is kept in memory only and\n does not survive process restarts.\n \"\"\"\n session_id = get_current_session_id()\n if not session_id:\n raise RuntimeError(\n \"No current session id — cannot resolve a SessionManager outside of a request scope.\"\n )\n if os.environ.get(\"LOCAL_DEV\") == \"true\":\n return FileSessionManager(session_id=session_id, storage_dir=\"${localSessionsDir}\")\n return None\n`;\n\nconst legacyLangChainSessionContent = (localSessionsDir: string): string =>\n `import os\n\nimport aiosqlite\nfrom langgraph.checkpoint.base import BaseCheckpointSaver\nfrom langgraph.checkpoint.memory import InMemorySaver\nfrom langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver\n\n\ndef get_checkpointer() -> BaseCheckpointSaver:\n \"\"\"Returns the checkpointer used to persist conversation state.\"\"\"\n if os.environ.get(\"LOCAL_DEV\") == \"true\":\n os.makedirs(\"${localSessionsDir}\", exist_ok=True)\n conn = aiosqlite.connect(os.path.join(\"${localSessionsDir}\", \"checkpoints.sqlite\"))\n return AsyncSqliteSaver(conn)\n return InMemorySaver()\n`;\n\n/** The Nx project owning `dirPath`, if any (the longest-matching project.root). */\nconst findOwningProject = (\n tree: Tree,\n dirPath: string,\n): ProjectConfiguration | undefined => {\n let best: ProjectConfiguration | undefined;\n for (const project of getProjects(tree).values()) {\n if (\n (dirPath === project.root || dirPath.startsWith(`${project.root}/`)) &&\n (!best || project.root.length > best.root.length)\n ) {\n best = project;\n }\n }\n return best;\n};\n\n/** This agent's metadata, accepting both current and legacy component paths. */\nconst findAgentComponentMetadata = (\n project: ProjectConfiguration,\n dirRelativeToProjectRoot: string,\n): ComponentMetadata | undefined =>\n (project.metadata as { components?: ComponentMetadata[] })?.components?.find(\n (component) =>\n component.generator === PY_AGENT_GENERATOR_INFO.id &&\n (component.path === dirRelativeToProjectRoot ||\n component.path === `${dirRelativeToProjectRoot}/agent.py`),\n );\n\n/**\n * This agent's real kebab-case name — the generator's own target-prefix\n * (ComponentMetadata's `name` field), used directly rather than\n * reconstructing it by kebab-casing the class name (`rc`). That round trip\n * loses word boundaries for names with single-letter segments, e.g.\n * `kebabCase(\"OldSHttp\")` => \"old-shttp\", not the real \"old-s-http\".\n *\n * When no `--name` was given at generation time, the generator falls back\n * to `${project}-agent` for the real name, but records a literal 'agent' as\n * the target-prefix — indistinguishable from an agent explicitly named\n * \"agent\" — so re-derive the fallback from the project name in that case,\n * exactly as the generator itself does.\n */\nconst agentTmpNameFor = (\n project: ProjectConfiguration,\n dir: string,\n): string | undefined => {\n const dirRelativeToProjectRoot = toProjectRelativePath(project, dir);\n const targetPrefix = findAgentComponentMetadata(\n project,\n dirRelativeToProjectRoot,\n )?.name;\n if (!targetPrefix) return undefined;\n if (targetPrefix !== 'agent') return targetPrefix;\n return kebabCase(`${project.name.split('.').pop() ?? project.name}-agent`);\n};\n\n/** This agent's protocol + framework, from its ComponentMetadata entry. */\nconst agentComponentFor = (\n project: ProjectConfiguration,\n dir: string,\n): ComponentMetadata | undefined => {\n const dirRelativeToProjectRoot = toProjectRelativePath(project, dir);\n return findAgentComponentMetadata(project, dirRelativeToProjectRoot);\n};\n\n/** The relative path from `projectRoot` up to this agent's workspace-root-level local session storage. */\nconst localSessionsDirFor = (\n projectRoot: string,\n agentTmpName: string,\n framework: 'strands' | 'langchain' = 'strands',\n): string =>\n joinPathFragments(\n getRelativePathToRootByDirectory(projectRoot),\n `tmp/agents/${framework}/${agentTmpName}`,\n );\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n const filePaths: string[] = [];\n visitNotIgnoredFiles(tree, '', (filePath) => filePaths.push(filePath));\n\n for (const filePath of filePaths) {\n if (filePath.endsWith('/agent.py')) {\n // log_tool_errors applies to every protocol (unlike session_manager),\n // so retrofit it independently of whether the owning project can be\n // resolved below. LOG_TOOL_ERRORS_HOOKS_PATTERN's own `where` clause\n // (contains log_model_errors, not already containing log_tool_errors)\n // doubles as the \"still needs retrofitting\" check.\n if (await matchGritQL(tree, filePath, LOG_TOOL_ERRORS_HOOKS_PATTERN)) {\n const mod = await captureGritQLVariable(\n tree,\n filePath,\n LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN,\n 'mod',\n );\n if ((await ensureToolErrorsBase(tree)) && mod) {\n await applyGritQL(tree, filePath, logToolErrorsImportPattern(mod));\n await applyGritQL(tree, filePath, LOG_TOOL_ERRORS_WRITE_PATTERN);\n } else {\n nextSteps.push(\n `${filePath}: could not find the shared agent-connection project — manually add \\`log_tool_errors\\` to the hooks list (see the py#agent generator's template).`,\n );\n }\n }\n\n const dir = filePath.split('/').slice(0, -1).join('/');\n const project = findOwningProject(tree, dir);\n\n // Without a registered project there's no ComponentMetadata, so this\n // agent's protocol/framework/agent-connection module can't be\n // resolved — and a pre-migration AG-UI agent.py is textually identical\n // to an HTTP/A2A one, so there's nothing left to safely guess from.\n if (!project) {\n if (\n await matchGritQL(\n tree,\n filePath,\n LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN,\n )\n ) {\n nextSteps.push(\n `${filePath}: could not determine the project root — manually verify whether this is an AG-UI or HTTP/A2A Strands agent and wire session_manager in accordingly (see the py#agent generator's template).`,\n );\n }\n continue;\n }\n\n const component = agentComponentFor(project, dir);\n\n if (component?.framework === 'langchain') {\n const content = tree.read(filePath, 'utf-8') ?? '';\n if (content.includes('checkpointer=get_checkpointer()')) {\n continue;\n }\n if (\n !(await matchGritQL(tree, filePath, LANGCHAIN_AGENT_MATCH_PATTERN))\n ) {\n nextSteps.push(\n `${filePath}: the create_agent call has diverged from the generated shape — manually create ${dir}/session.py and pass \\`checkpointer=get_checkpointer()\\` to \\`create_agent\\` (see the py#agent generator's template).`,\n );\n continue;\n }\n\n const agentName = agentTmpNameFor(project, dir);\n const sessionPath = `${dir}/session.py`;\n if (!agentName) {\n nextSteps.push(\n `${filePath}: could not determine this agent's name from its ComponentMetadata — manually create ${sessionPath} and pass \\`checkpointer=get_checkpointer()\\` to \\`create_agent\\` (see the py#agent generator's template).`,\n );\n continue;\n }\n\n if (!tree.exists(sessionPath)) {\n tree.write(\n sessionPath,\n legacyLangChainSessionContent(\n localSessionsDirFor(project.root, agentName, 'langchain'),\n ),\n );\n }\n addPyDependencies(tree, DEPENDENCIES, { projectRoot: project.root });\n await applyGritQL(tree, filePath, langChainSessionImportPattern);\n await applyGritQL(tree, filePath, LANGCHAIN_IN_MEMORY_IMPORT_PATTERN);\n await applyGritQL(tree, filePath, LANGCHAIN_CHECKPOINTER_PATTERN);\n const migratedContent = tree.read(filePath, 'utf-8') ?? '';\n if (\n !migratedContent.includes('from .session import get_checkpointer') ||\n !migratedContent.includes('checkpointer=get_checkpointer()')\n ) {\n nextSteps.push(\n `${filePath}: session.py was created but the checkpointer could not be wired automatically — import \\`get_checkpointer\\` from it and pass \\`checkpointer=get_checkpointer()\\` to \\`create_agent\\`.`,\n );\n }\n continue;\n }\n\n // AG-UI wires session_manager_provider on the StrandsAgent adapter in\n // main.py instead — handled by the branch below.\n if (component?.protocol === 'ag-ui') {\n continue;\n }\n\n if (!component?.protocol) {\n if (\n await matchGritQL(\n tree,\n filePath,\n LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN,\n )\n ) {\n nextSteps.push(\n `${filePath}: could not determine this agent's protocol/framework from its ComponentMetadata — manually verify whether it's AG-UI or HTTP/A2A Strands and wire session_manager in accordingly (see the py#agent generator's template).`,\n );\n }\n continue;\n }\n\n // HTTP/A2A: wire session_manager into the Agent constructor and create\n // the sibling session.py if it doesn't exist yet.\n if (\n !(await matchGritQL(\n tree,\n filePath,\n LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN,\n ))\n ) {\n continue;\n }\n\n const sessionPath = `${dir}/session.py`;\n\n if (\n !(await matchGritQL(tree, filePath, AGENT_PY_CONSTRUCTOR_MATCH_PATTERN))\n ) {\n nextSteps.push(\n `${filePath}: the Agent is not constructed with an inline \\`Agent(...)\\` call, so session_manager could not be wired in automatically. Manually add \\`session_manager=get_session_manager()\\` to its constructor (see the py#agent generator's template), creating ${sessionPath} first if it doesn't already exist.`,\n );\n continue;\n }\n\n if (!tree.exists(sessionPath)) {\n const mod = await captureGritQLVariable(\n tree,\n filePath,\n LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN,\n 'mod',\n );\n const agentName = agentTmpNameFor(project, dir);\n\n if (mod && agentName) {\n tree.write(\n sessionPath,\n legacySessionManagerContent(\n mod,\n localSessionsDirFor(project.root, agentName),\n ),\n );\n } else {\n nextSteps.push(\n `${filePath}: could not determine the agent-connection module or this agent's name from its ComponentMetadata — manually create ${sessionPath} (see the py#agent generator's template) and wire \\`session_manager=get_session_manager()\\` into the Agent constructor.`,\n );\n continue;\n }\n }\n\n const agentContent = tree.read(filePath, 'utf-8') ?? '';\n if (!agentContent.includes('from .session import get_session_manager')) {\n await applyGritQL(tree, filePath, AGENT_PY_SESSION_IMPORT_PATTERN);\n await applyGritQL(tree, filePath, AGENT_PY_SESSION_MANAGER_PATTERN);\n }\n\n if (\n !(tree.read(filePath, 'utf-8') ?? '').includes('get_session_manager')\n ) {\n nextSteps.push(\n `${filePath}: found ${sessionPath} but couldn't confirm the get_session_manager import — wire \\`session_manager=get_session_manager()\\` into the Agent constructor manually.`,\n );\n continue;\n }\n\n continue;\n }\n\n if (\n filePath.endsWith('/main.py') &&\n (tree.read(filePath, 'utf-8') ?? '').includes('ag_ui_strands')\n ) {\n const alreadyWired = (tree.read(filePath, 'utf-8') ?? '').includes(\n 'StrandsAgentConfig',\n );\n\n if (!alreadyWired) {\n const needsWiring = await matchGritQL(\n tree,\n filePath,\n AGUI_MAIN_CONSTRUCTOR_MATCH_PATTERN,\n );\n if (!needsWiring) {\n nextSteps.push(\n `${filePath}: the StrandsAgent constructor has diverged from the generated shape - left as-is. Manually add \\`config=StrandsAgentConfig(session_manager_provider=lambda _input_data: get_session_manager())\\` to it (see the py#agent generator's template).`,\n );\n continue;\n }\n\n await applyGritQL(tree, filePath, AGUI_MAIN_IMPORT_PATTERN);\n await applyGritQL(tree, filePath, AGUI_MAIN_CONSTRUCTOR_PATTERN);\n }\n\n const dir = filePath.split('/').slice(0, -1).join('/');\n const sessionPath = `${dir}/session.py`;\n\n if (!tree.exists(sessionPath)) {\n const project = findOwningProject(tree, dir);\n const mod = await captureGritQLVariable(\n tree,\n filePath,\n SESSION_ID_CONTEXT_IMPORT_CAPTURE_PATTERN,\n 'mod',\n );\n const agentName = project && agentTmpNameFor(project, dir);\n\n if (project && mod && agentName) {\n tree.write(\n sessionPath,\n legacySessionManagerContent(\n mod,\n localSessionsDirFor(project.root, agentName),\n ),\n );\n } else {\n nextSteps.push(\n `${filePath}: could not determine the project root, agent-connection module, or this agent's name from its ComponentMetadata — manually create ${sessionPath} (see the py#agent generator's template) and wire \\`config=StrandsAgentConfig(session_manager_provider=lambda _input_data: get_session_manager())\\` into the StrandsAgent constructor.`,\n );\n continue;\n }\n }\n\n await applyGritQL(tree, filePath, AGUI_MAIN_SESSION_IMPORT_PATTERN);\n\n if (\n !(tree.read(filePath, 'utf-8') ?? '').includes('get_session_manager')\n ) {\n nextSteps.push(\n `${filePath}: found ${sessionPath} but couldn't confirm the get_session_manager import — wire it into the StrandsAgent constructor manually.`,\n );\n }\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["readFileSync","join","getProjects","joinPathFragments","visitNotIgnoredFiles","PY_AGENT_GENERATOR_INFO","addPyDependencies","addPythonReExport","getPythonAgentConnectionModuleName","getPythonAgentConnectionProjectDir","applyGritQL","captureGritQLVariable","matchGritQL","declareDependencies","formatFilesInSubtree","kebabCase","getRelativePathToRootByDirectory","toProjectRelativePath","LOG_MODEL_ERRORS_IMPORT_CAPTURE_PATTERN","SESSION_ID_CONTEXT_IMPORT_CAPTURE_PATTERN","DEPENDENCIES","py","name","ts","LANGCHAIN_AGENT_MATCH_PATTERN","LANGCHAIN_CHECKPOINTER_PATTERN","LANGCHAIN_IN_MEMORY_IMPORT_PATTERN","langChainSessionImportPattern","LOG_TOOL_ERRORS_HOOKS_PATTERN","logToolErrorsImportPattern","mod","LOG_TOOL_ERRORS_WRITE_PATTERN","TOOL_ERRORS_STRANDS_PY_CONTENT","dirname","ensureToolErrorsBase","tree","projectDir","exists","moduleDir","toolErrorsPath","write","AGENT_PY_CONSTRUCTOR_MATCH_PATTERN","AGENT_PY_SESSION_MANAGER_PATTERN","AGENT_PY_SESSION_IMPORT_PATTERN","AGUI_MAIN_IMPORT_PATTERN","AGUI_MAIN_CONSTRUCTOR_MATCH_PATTERN","AGUI_MAIN_CONSTRUCTOR_PATTERN","AGUI_MAIN_SESSION_IMPORT_PATTERN","legacySessionManagerContent","agentConnectionModule","localSessionsDir","legacyLangChainSessionContent","findOwningProject","dirPath","best","project","values","root","startsWith","length","findAgentComponentMetadata","dirRelativeToProjectRoot","metadata","components","find","component","generator","id","path","agentTmpNameFor","dir","targetPrefix","undefined","split","pop","agentComponentFor","localSessionsDirFor","projectRoot","agentTmpName","framework","migration","nextSteps","filePaths","filePath","push","endsWith","slice","content","read","includes","agentName","sessionPath","migratedContent","protocol","agentContent","alreadyWired","needsWiring"],"mappings":"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"}
@@ -252,7 +252,7 @@ export default {
252
252
 
253
253
  exports[`preset generator > should run successfully > biome.json 1`] = `
254
254
  "{
255
- "$schema": "https://biomejs.dev/schemas/2.5.7/schema.json",
255
+ "$schema": "https://biomejs.dev/schemas/2.5.8/schema.json",
256
256
  "root": true,
257
257
  "formatter": {
258
258
  "enabled": true,
@@ -418,7 +418,7 @@ catalog:
418
418
  '@nx/js': 23.1.1
419
419
  '@nx/workspace': 23.1.1
420
420
  typescript: ~6.0.3
421
- '@biomejs/biome': 2.5.7
421
+ '@biomejs/biome': 2.5.8
422
422
  '@aws/nx-plugin': ^0.0.0
423
423
  '@aws/nx-plugin-mcp': ^0.0.0
424
424
  "
@@ -17,7 +17,7 @@ export declare const DEPENDENCIES: import("../utils/declared-dependencies").Depe
17
17
  readonly name: "typescript";
18
18
  }, {
19
19
  readonly name: "@biomejs/biome";
20
- }], readonly import("../utils/declared-dependencies").DeclaredPyDependency<"a2a-sdk" | "ag-ui-langgraph" | "ag-ui-protocol" | "ag-ui-strands" | "aws-lambda-powertools" | "aws-lambda-powertools[tracer]" | "aws-lambda-powertools[parser]" | "aws-opentelemetry-distro" | "bedrock-agentcore" | "boto3" | "checkov" | "fastapi" | "fastapi[standard]" | "httpx" | "langchain" | "langchain-aws" | "langchain-mcp-adapters" | "langgraph" | "mcp" | "pip-check-updates" | "pip-licenses" | "ruff" | "strands-agents" | "strands-agents[a2a]" | "strands-agents-tools" | "ty" | "pynamodb" | "uvicorn" | "sqlmodel" | "alembic" | "aiomysql" | "asyncpg" | "greenlet", Record<string, never>>[]>;
20
+ }], readonly import("../utils/declared-dependencies").DeclaredPyDependency<"a2a-sdk" | "ag-ui-langgraph" | "ag-ui-protocol" | "ag-ui-strands" | "aiosqlite" | "aws-lambda-powertools" | "aws-lambda-powertools[tracer]" | "aws-lambda-powertools[parser]" | "aws-opentelemetry-distro" | "bedrock-agentcore" | "boto3" | "checkov" | "fastapi" | "fastapi[standard]" | "httpx" | "langchain" | "langchain-aws" | "langchain-mcp-adapters" | "langgraph" | "langgraph-checkpoint-aws" | "langgraph-checkpoint-sqlite" | "mcp" | "pip-check-updates" | "pip-licenses" | "ruff" | "strands-agents" | "strands-agents[a2a]" | "strands-agents-tools" | "ty" | "pynamodb" | "uvicorn" | "sqlmodel" | "alembic" | "aiomysql" | "asyncpg" | "greenlet", Record<string, never>>[]>;
21
21
  export declare const PRESET_GENERATOR_INFO: NxGeneratorInfo;
22
22
  /**
23
23
  * Determines if the current user is an Amazon employee based on their git configuration.