@aws/agentcore 1.0.0-preview.2 → 1.0.0-preview.21

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 (277) hide show
  1. package/README.md +193 -33
  2. package/dist/agent-inspector/index.css +1 -1
  3. package/dist/agent-inspector/index.js +99 -84
  4. package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +3132 -366
  5. package/dist/assets/__tests__/__snapshots__/dockerfile-render.test.ts.snap +6 -2
  6. package/dist/assets/__tests__/assets.snapshot.test.ts +10 -24
  7. package/dist/assets/__tests__/googleadk-session-eviction.test.ts +87 -0
  8. package/dist/assets/__tests__/summarization-namespace.test.ts +43 -0
  9. package/dist/assets/agents/AGENTS.md +87 -11
  10. package/dist/assets/cdk/bin/cdk.ts +87 -26
  11. package/dist/assets/cdk/lib/cdk-stack.ts +185 -55
  12. package/dist/assets/cdk/package.json +1 -1
  13. package/dist/assets/cdk/test/cdk.test.ts +4 -0
  14. package/dist/assets/container/python/Dockerfile +7 -1
  15. package/dist/assets/container/typescript/Dockerfile +25 -0
  16. package/dist/assets/container/typescript/dockerignore.template +24 -0
  17. package/dist/assets/datasets/predefined-v1.jsonl +3 -0
  18. package/dist/assets/datasets/simulated-v1.jsonl +3 -0
  19. package/dist/assets/python/a2a/googleadk/base/main.py +24 -16
  20. package/dist/assets/python/a2a/googleadk/base/pyproject.toml +3 -3
  21. package/dist/assets/python/a2a/langchain_langgraph/base/main.py +24 -16
  22. package/dist/assets/python/a2a/langchain_langgraph/base/pyproject.toml +3 -2
  23. package/dist/assets/python/a2a/strands/base/main.py +23 -17
  24. package/dist/assets/python/a2a/strands/base/pyproject.toml +2 -2
  25. package/dist/assets/python/a2a/strands/capabilities/memory/session.py +10 -2
  26. package/dist/assets/python/agui/googleadk/base/main.py +62 -2
  27. package/dist/assets/python/agui/googleadk/base/pyproject.toml +3 -3
  28. package/dist/assets/python/agui/langchain_langgraph/base/main.py +56 -0
  29. package/dist/assets/python/agui/langchain_langgraph/base/pyproject.toml +2 -1
  30. package/dist/assets/python/agui/strands/base/main.py +63 -1
  31. package/dist/assets/python/agui/strands/base/pyproject.toml +1 -1
  32. package/dist/assets/python/agui/strands/capabilities/memory/session.py +10 -2
  33. package/dist/assets/python/http/autogen/base/main.py +60 -29
  34. package/dist/assets/python/http/autogen/base/pyproject.toml +1 -1
  35. package/dist/assets/python/http/googleadk/base/main.py +69 -24
  36. package/dist/assets/python/http/googleadk/base/mcp_client/client.py +7 -7
  37. package/dist/assets/python/http/googleadk/base/pyproject.toml +2 -1
  38. package/dist/assets/python/http/langchain_langgraph/base/main.py +115 -24
  39. package/dist/assets/python/http/langchain_langgraph/base/mcp_client/client.py +10 -8
  40. package/dist/assets/python/http/langchain_langgraph/base/pyproject.toml +3 -2
  41. package/dist/assets/python/http/openaiagents/base/main.py +61 -32
  42. package/dist/assets/python/http/openaiagents/base/mcp_client/client.py +4 -4
  43. package/dist/assets/python/http/openaiagents/base/pyproject.toml +2 -2
  44. package/dist/assets/python/http/strands/base/main.py +571 -47
  45. package/dist/assets/python/http/strands/base/mcp_client/client.py +49 -6
  46. package/dist/assets/python/http/strands/base/model/load.py +119 -3
  47. package/dist/assets/python/http/strands/base/model/mantle_compat.py +21 -0
  48. package/dist/assets/python/http/strands/base/pyproject.toml +9 -3
  49. package/dist/assets/python/http/strands/base/skills/fetcher.py +279 -0
  50. package/dist/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
  51. package/dist/assets/python/http/strands/capabilities/memory/session.py +10 -2
  52. package/dist/assets/python/http/strands/capabilities/payments/__init__.py +4 -0
  53. package/dist/assets/python/http/strands/capabilities/payments/payments.py +142 -0
  54. package/dist/assets/python/mcp/standalone/base/main.py +58 -0
  55. package/dist/assets/typescript/http/strands/base/README.md +37 -0
  56. package/dist/assets/typescript/http/strands/base/gitignore.template +22 -0
  57. package/dist/assets/typescript/http/strands/base/main.ts +144 -0
  58. package/dist/assets/typescript/http/strands/base/mcp_client/client.ts +11 -0
  59. package/dist/assets/typescript/http/strands/base/model/load.ts +102 -0
  60. package/dist/assets/typescript/http/strands/base/package.json +38 -0
  61. package/dist/assets/typescript/http/strands/base/tsconfig.json +19 -0
  62. package/dist/assets/typescript/http/strands/capabilities/memory/memory.ts +52 -0
  63. package/dist/assets/typescript/http/vercelai/base/README.md +37 -0
  64. package/dist/assets/typescript/http/vercelai/base/gitignore.template +22 -0
  65. package/dist/assets/typescript/http/vercelai/base/main.ts +64 -0
  66. package/dist/assets/typescript/http/vercelai/base/model/load.ts +121 -0
  67. package/dist/assets/typescript/http/vercelai/base/package.json +35 -0
  68. package/dist/assets/typescript/http/vercelai/base/tsconfig.json +19 -0
  69. package/dist/cli/index.mjs +1443 -569
  70. package/dist/lib/constants.d.ts +8 -4
  71. package/dist/lib/constants.d.ts.map +1 -1
  72. package/dist/lib/constants.js +13 -7
  73. package/dist/lib/constants.js.map +1 -1
  74. package/dist/lib/errors/index.d.ts +1 -1
  75. package/dist/lib/errors/index.d.ts.map +1 -1
  76. package/dist/lib/errors/index.js +1 -1
  77. package/dist/lib/errors/index.js.map +1 -1
  78. package/dist/lib/errors/types.d.ts +259 -0
  79. package/dist/lib/errors/types.d.ts.map +1 -0
  80. package/dist/lib/errors/types.js +402 -0
  81. package/dist/lib/errors/types.js.map +1 -0
  82. package/dist/lib/errors/zod.d.ts +8 -0
  83. package/dist/lib/errors/zod.d.ts.map +1 -0
  84. package/dist/lib/errors/{config.js → zod.js} +8 -81
  85. package/dist/lib/errors/zod.js.map +1 -0
  86. package/dist/lib/index.d.ts +3 -0
  87. package/dist/lib/index.d.ts.map +1 -1
  88. package/dist/lib/index.js +4 -1
  89. package/dist/lib/index.js.map +1 -1
  90. package/dist/lib/packaging/build-args.d.ts +6 -0
  91. package/dist/lib/packaging/build-args.d.ts.map +1 -1
  92. package/dist/lib/packaging/build-args.js +11 -2
  93. package/dist/lib/packaging/build-args.js.map +1 -1
  94. package/dist/lib/packaging/build-context-dockerignore.d.ts +23 -0
  95. package/dist/lib/packaging/build-context-dockerignore.d.ts.map +1 -0
  96. package/dist/lib/packaging/build-context-dockerignore.js +63 -0
  97. package/dist/lib/packaging/build-context-dockerignore.js.map +1 -0
  98. package/dist/lib/packaging/build-context.d.ts +21 -0
  99. package/dist/lib/packaging/build-context.d.ts.map +1 -0
  100. package/dist/lib/packaging/build-context.js +21 -0
  101. package/dist/lib/packaging/build-context.js.map +1 -0
  102. package/dist/lib/packaging/container.d.ts.map +1 -1
  103. package/dist/lib/packaging/container.js +20 -9
  104. package/dist/lib/packaging/container.js.map +1 -1
  105. package/dist/lib/packaging/helpers.d.ts +16 -0
  106. package/dist/lib/packaging/helpers.d.ts.map +1 -1
  107. package/dist/lib/packaging/helpers.js +127 -29
  108. package/dist/lib/packaging/helpers.js.map +1 -1
  109. package/dist/lib/packaging/index.d.ts +2 -1
  110. package/dist/lib/packaging/index.d.ts.map +1 -1
  111. package/dist/lib/packaging/index.js +9 -20
  112. package/dist/lib/packaging/index.js.map +1 -1
  113. package/dist/lib/packaging/node.d.ts +2 -2
  114. package/dist/lib/packaging/node.d.ts.map +1 -1
  115. package/dist/lib/packaging/node.js +83 -38
  116. package/dist/lib/packaging/node.js.map +1 -1
  117. package/dist/lib/packaging/python.js +12 -12
  118. package/dist/lib/packaging/python.js.map +1 -1
  119. package/dist/lib/result.d.ts +50 -0
  120. package/dist/lib/result.d.ts.map +1 -0
  121. package/dist/lib/result.js +49 -0
  122. package/dist/lib/result.js.map +1 -0
  123. package/dist/lib/schemas/io/config-io.d.ts +8 -0
  124. package/dist/lib/schemas/io/config-io.d.ts.map +1 -1
  125. package/dist/lib/schemas/io/config-io.js +21 -3
  126. package/dist/lib/schemas/io/config-io.js.map +1 -1
  127. package/dist/lib/schemas/io/global-config.d.ts +40 -0
  128. package/dist/lib/schemas/io/global-config.d.ts.map +1 -0
  129. package/dist/lib/schemas/io/global-config.js +118 -0
  130. package/dist/lib/schemas/io/global-config.js.map +1 -0
  131. package/dist/lib/schemas/io/index.d.ts +1 -2
  132. package/dist/lib/schemas/io/index.d.ts.map +1 -1
  133. package/dist/lib/schemas/io/index.js +1 -4
  134. package/dist/lib/schemas/io/index.js.map +1 -1
  135. package/dist/lib/schemas/io/path-resolver.d.ts +0 -6
  136. package/dist/lib/schemas/io/path-resolver.d.ts.map +1 -1
  137. package/dist/lib/schemas/io/path-resolver.js +3 -13
  138. package/dist/lib/schemas/io/path-resolver.js.map +1 -1
  139. package/dist/lib/secrets/cipher.d.ts +12 -0
  140. package/dist/lib/secrets/cipher.d.ts.map +1 -0
  141. package/dist/lib/secrets/cipher.js +54 -0
  142. package/dist/lib/secrets/cipher.js.map +1 -0
  143. package/dist/lib/secrets/index.d.ts +4 -0
  144. package/dist/lib/secrets/index.d.ts.map +1 -0
  145. package/dist/lib/secrets/index.js +15 -0
  146. package/dist/lib/secrets/index.js.map +1 -0
  147. package/dist/lib/secrets/key-provider.d.ts +16 -0
  148. package/dist/lib/secrets/key-provider.d.ts.map +1 -0
  149. package/dist/lib/secrets/key-provider.js +191 -0
  150. package/dist/lib/secrets/key-provider.js.map +1 -0
  151. package/dist/lib/secrets/sensitive-keys.d.ts +21 -0
  152. package/dist/lib/secrets/sensitive-keys.d.ts.map +1 -0
  153. package/dist/lib/secrets/sensitive-keys.js +67 -0
  154. package/dist/lib/secrets/sensitive-keys.js.map +1 -0
  155. package/dist/lib/time-constants.d.ts +5 -0
  156. package/dist/lib/time-constants.d.ts.map +1 -0
  157. package/dist/lib/time-constants.js +8 -0
  158. package/dist/lib/time-constants.js.map +1 -0
  159. package/dist/lib/utils/env.d.ts +8 -2
  160. package/dist/lib/utils/env.d.ts.map +1 -1
  161. package/dist/lib/utils/env.js +65 -17
  162. package/dist/lib/utils/env.js.map +1 -1
  163. package/dist/lib/utils/index.d.ts +3 -2
  164. package/dist/lib/utils/index.d.ts.map +1 -1
  165. package/dist/lib/utils/index.js +6 -1
  166. package/dist/lib/utils/index.js.map +1 -1
  167. package/dist/lib/utils/polling.d.ts +31 -0
  168. package/dist/lib/utils/polling.d.ts.map +1 -0
  169. package/dist/lib/utils/polling.js +61 -0
  170. package/dist/lib/utils/polling.js.map +1 -0
  171. package/dist/lib/utils/zod.d.ts +16 -0
  172. package/dist/lib/utils/zod.d.ts.map +1 -1
  173. package/dist/lib/utils/zod.js +45 -0
  174. package/dist/lib/utils/zod.js.map +1 -1
  175. package/dist/schema/constants.d.ts +56 -2
  176. package/dist/schema/constants.d.ts.map +1 -1
  177. package/dist/schema/constants.js +82 -7
  178. package/dist/schema/constants.js.map +1 -1
  179. package/dist/schema/schemas/agent-env.d.ts +178 -6
  180. package/dist/schema/schemas/agent-env.d.ts.map +1 -1
  181. package/dist/schema/schemas/agent-env.js +302 -27
  182. package/dist/schema/schemas/agent-env.js.map +1 -1
  183. package/dist/schema/schemas/agentcore-project.d.ts +450 -11
  184. package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
  185. package/dist/schema/schemas/agentcore-project.js +283 -18
  186. package/dist/schema/schemas/agentcore-project.js.map +1 -1
  187. package/dist/schema/schemas/auth.d.ts +174 -0
  188. package/dist/schema/schemas/auth.d.ts.map +1 -1
  189. package/dist/schema/schemas/auth.js +127 -3
  190. package/dist/schema/schemas/auth.js.map +1 -1
  191. package/dist/schema/schemas/aws-targets.d.ts +12 -0
  192. package/dist/schema/schemas/aws-targets.d.ts.map +1 -1
  193. package/dist/schema/schemas/aws-targets.js +4 -0
  194. package/dist/schema/schemas/aws-targets.js.map +1 -1
  195. package/dist/schema/schemas/connections.d.ts +185 -0
  196. package/dist/schema/schemas/connections.d.ts.map +1 -0
  197. package/dist/schema/schemas/connections.js +176 -0
  198. package/dist/schema/schemas/connections.js.map +1 -0
  199. package/dist/schema/schemas/deployed-state.d.ts +361 -5
  200. package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
  201. package/dist/schema/schemas/deployed-state.js +105 -2
  202. package/dist/schema/schemas/deployed-state.js.map +1 -1
  203. package/dist/schema/schemas/index.d.ts +1 -0
  204. package/dist/schema/schemas/index.d.ts.map +1 -1
  205. package/dist/schema/schemas/index.js +1 -0
  206. package/dist/schema/schemas/index.js.map +1 -1
  207. package/dist/schema/schemas/mcp-defs.d.ts +2 -1
  208. package/dist/schema/schemas/mcp-defs.d.ts.map +1 -1
  209. package/dist/schema/schemas/mcp-defs.js +3 -2
  210. package/dist/schema/schemas/mcp-defs.js.map +1 -1
  211. package/dist/schema/schemas/mcp.d.ts +199 -0
  212. package/dist/schema/schemas/mcp.d.ts.map +1 -1
  213. package/dist/schema/schemas/mcp.js +343 -6
  214. package/dist/schema/schemas/mcp.js.map +1 -1
  215. package/dist/schema/schemas/primitives/ab-test.d.ts +135 -0
  216. package/dist/schema/schemas/primitives/ab-test.d.ts.map +1 -0
  217. package/dist/schema/schemas/primitives/ab-test.js +95 -0
  218. package/dist/schema/schemas/primitives/ab-test.js.map +1 -0
  219. package/dist/schema/schemas/primitives/config-bundle.d.ts +32 -0
  220. package/dist/schema/schemas/primitives/config-bundle.d.ts.map +1 -0
  221. package/dist/schema/schemas/primitives/config-bundle.js +41 -0
  222. package/dist/schema/schemas/primitives/config-bundle.js.map +1 -0
  223. package/dist/schema/schemas/primitives/dataset.d.ts +48 -0
  224. package/dist/schema/schemas/primitives/dataset.d.ts.map +1 -0
  225. package/dist/schema/schemas/primitives/dataset.js +58 -0
  226. package/dist/schema/schemas/primitives/dataset.js.map +1 -0
  227. package/dist/schema/schemas/primitives/evaluator.d.ts +8 -0
  228. package/dist/schema/schemas/primitives/evaluator.d.ts.map +1 -1
  229. package/dist/schema/schemas/primitives/evaluator.js +17 -1
  230. package/dist/schema/schemas/primitives/evaluator.js.map +1 -1
  231. package/dist/schema/schemas/primitives/harness.d.ts +377 -19
  232. package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
  233. package/dist/schema/schemas/primitives/harness.js +379 -24
  234. package/dist/schema/schemas/primitives/harness.js.map +1 -1
  235. package/dist/schema/schemas/primitives/index.d.ts +13 -7
  236. package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
  237. package/dist/schema/schemas/primitives/index.js +37 -1
  238. package/dist/schema/schemas/primitives/index.js.map +1 -1
  239. package/dist/schema/schemas/primitives/knowledge-base.d.ts +104 -0
  240. package/dist/schema/schemas/primitives/knowledge-base.d.ts.map +1 -0
  241. package/dist/schema/schemas/primitives/knowledge-base.js +99 -0
  242. package/dist/schema/schemas/primitives/knowledge-base.js.map +1 -0
  243. package/dist/schema/schemas/primitives/memory.d.ts +22 -4
  244. package/dist/schema/schemas/primitives/memory.d.ts.map +1 -1
  245. package/dist/schema/schemas/primitives/memory.js +57 -16
  246. package/dist/schema/schemas/primitives/memory.js.map +1 -1
  247. package/dist/schema/schemas/primitives/online-eval-config.d.ts +21 -2
  248. package/dist/schema/schemas/primitives/online-eval-config.d.ts.map +1 -1
  249. package/dist/schema/schemas/primitives/online-eval-config.js +45 -5
  250. package/dist/schema/schemas/primitives/online-eval-config.js.map +1 -1
  251. package/dist/schema/schemas/primitives/payment.d.ts +54 -0
  252. package/dist/schema/schemas/primitives/payment.d.ts.map +1 -0
  253. package/dist/schema/schemas/primitives/payment.js +79 -0
  254. package/dist/schema/schemas/primitives/payment.js.map +1 -0
  255. package/dist/schema/schemas/primitives/policy.d.ts +26 -0
  256. package/dist/schema/schemas/primitives/policy.d.ts.map +1 -1
  257. package/dist/schema/schemas/primitives/policy.js +5 -1
  258. package/dist/schema/schemas/primitives/policy.js.map +1 -1
  259. package/npm-shrinkwrap.json +17013 -0
  260. package/package.json +43 -21
  261. package/scripts/bump-version.ts +4 -4
  262. package/scripts/bundle.mjs +70 -41
  263. package/scripts/extract-cli-model.mjs +228 -0
  264. package/scripts/render_adoc.py +274 -0
  265. package/scripts/run-e2e-dev.sh +56 -0
  266. package/scripts/run-e2e-local.sh +145 -0
  267. package/dist/lib/errors/config.d.ts +0 -49
  268. package/dist/lib/errors/config.d.ts.map +0 -1
  269. package/dist/lib/errors/config.js.map +0 -1
  270. package/dist/lib/packaging/errors.d.ts +0 -16
  271. package/dist/lib/packaging/errors.d.ts.map +0 -1
  272. package/dist/lib/packaging/errors.js +0 -36
  273. package/dist/lib/packaging/errors.js.map +0 -1
  274. package/dist/lib/schemas/io/cli-config.d.ts +0 -12
  275. package/dist/lib/schemas/io/cli-config.d.ts.map +0 -1
  276. package/dist/lib/schemas/io/cli-config.js +0 -35
  277. package/dist/lib/schemas/io/cli-config.js.map +0 -1
@@ -1,4 +1,7 @@
1
+ {{#if needsOs}}
1
2
  import os
3
+ {{/if}}
4
+ from collections import OrderedDict
2
5
  from google.adk.agents import Agent
3
6
  from google.adk.runners import Runner
4
7
  from google.adk.sessions import InMemorySessionService
@@ -29,18 +32,21 @@ def add_numbers(a: int, b: int) -> int:
29
32
  # Define a collection of tools used by the model
30
33
  tools = [add_numbers]
31
34
 
32
- {{#if sessionStorageMountPath}}
33
- SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
35
+ {{#if needsOs}}
36
+ _MOUNT_PATHS = [
37
+ {{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
38
+ {{#each efsMounts}}"{{mountPath}}",{{/each}}
39
+ {{#each s3Mounts}}"{{mountPath}}",{{/each}}
40
+ ]
34
41
 
35
42
  def _safe_resolve(path: str) -> str:
36
- """Resolve path safely within the storage boundary."""
37
- resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
38
- if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
39
- raise ValueError(f"Path '{path}' is outside the storage boundary")
43
+ resolved = os.path.realpath(path)
44
+ if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
45
+ raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
40
46
  return resolved
41
47
 
42
48
  def file_read(path: str) -> str:
43
- """Read a file from persistent storage. The path is relative to the storage root."""
49
+ """Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
44
50
  try:
45
51
  full_path = _safe_resolve(path)
46
52
  with open(full_path) as f:
@@ -51,7 +57,7 @@ def file_read(path: str) -> str:
51
57
  return f"Error reading '{path}': {e.strerror}"
52
58
 
53
59
  def file_write(path: str, content: str) -> str:
54
- """Write content to a file in persistent storage. The path is relative to the storage root."""
60
+ """Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
55
61
  try:
56
62
  full_path = _safe_resolve(path)
57
63
  parent = os.path.dirname(full_path)
@@ -65,25 +71,28 @@ def file_write(path: str, content: str) -> str:
65
71
  except OSError as e:
66
72
  return f"Error writing '{path}': {e.strerror}"
67
73
 
68
- def list_files(directory: str = "") -> str:
69
- """List files in persistent storage. The directory is relative to the storage root."""
74
+ def list_files(path: str) -> str:
75
+ """List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
70
76
  try:
71
- target = _safe_resolve(directory)
72
- entries = os.listdir(target)
77
+ full_path = _safe_resolve(path)
78
+ entries = os.listdir(full_path)
73
79
  return "\n".join(entries) if entries else "(empty directory)"
74
80
  except ValueError as e:
75
81
  return str(e)
76
82
  except OSError as e:
77
- return f"Error listing '{directory}': {e.strerror}"
83
+ return f"Error listing '{path}': {e.strerror}"
78
84
 
79
85
  tools.extend([file_read, file_write, list_files])
80
86
  {{/if}}
81
87
 
82
88
  AGENT_INSTRUCTION = """
83
89
  I can answer your questions using the knowledge I have!
84
- {{#if sessionStorageMountPath}}
85
- You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
86
- {{/if}}
90
+ {{#if needsOs}}
91
+ You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
92
+ {{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
93
+ {{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
94
+ {{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
95
+ {{/each}}{{/if}}
87
96
  """
88
97
 
89
98
  # Get MCP Toolset
@@ -113,21 +122,57 @@ agent = Agent(
113
122
  )
114
123
 
115
124
 
116
- # Session and Runner
117
- async def setup_session_and_runner(user_id, session_id):
118
- ensure_credentials_loaded()
119
- session_service = InMemorySessionService()
120
- session = await session_service.create_session(
125
+ # Module-level session service and runner preserve history across invocations.
126
+ # InMemorySessionService retains every (app_name, user_id, session_id) triple
127
+ # forever, so we bound it to 128 active sessions with LRU eviction (the
128
+ # least-recently-used session is deleted and its history reset) to keep a
129
+ # long-running process from growing without limit. For durable history, swap in
130
+ # a persistent session service (e.g. DatabaseSessionService).
131
+ _SESSION_LIMIT = 128
132
+ _session_service = InMemorySessionService()
133
+ _session_keys = OrderedDict()
134
+ _runner = None
135
+
136
+
137
+ def get_or_create_runner():
138
+ global _runner
139
+ if _runner is None:
140
+ ensure_credentials_loaded()
141
+ _runner = Runner(
142
+ agent=agent,
143
+ app_name=APP_NAME,
144
+ session_service=_session_service,
145
+ )
146
+ return _runner
147
+
148
+
149
+ async def get_or_create_session(user_id, session_id):
150
+ key = (user_id, session_id)
151
+ if key in _session_keys:
152
+ _session_keys.move_to_end(key)
153
+ else:
154
+ while len(_session_keys) >= _SESSION_LIMIT:
155
+ (old_user_id, old_session_id), _ = _session_keys.popitem(last=False)
156
+ await _session_service.delete_session(
157
+ app_name=APP_NAME, user_id=old_user_id, session_id=old_session_id
158
+ )
159
+ _session_keys[key] = True
160
+
161
+ session = await _session_service.get_session(
121
162
  app_name=APP_NAME, user_id=user_id, session_id=session_id
122
163
  )
123
- runner = Runner(agent=agent, app_name=APP_NAME, session_service=session_service)
124
- return session, runner
164
+ if session is None:
165
+ session = await _session_service.create_session(
166
+ app_name=APP_NAME, user_id=user_id, session_id=session_id
167
+ )
168
+ return session
125
169
 
126
170
 
127
171
  # Agent Interaction
128
172
  async def call_agent_async(query, user_id, session_id):
129
173
  content = types.Content(role="user", parts=[types.Part(text=query)])
130
- session, runner = await setup_session_and_runner(user_id, session_id)
174
+ runner = get_or_create_runner()
175
+ session = await get_or_create_session(user_id, session_id)
131
176
  events = runner.run_async(
132
177
  user_id=user_id, session_id=session.id, new_message=content
133
178
  )
@@ -34,20 +34,20 @@ def get_all_gateway_mcp_toolsets() -> list[MCPToolset]:
34
34
  {{#each gatewayProviders}}
35
35
  url = os.environ.get("{{envVarName}}")
36
36
  if url:
37
- {{#if (eq authType "AWS_IAM")}}
37
+ {{#if (eq authType "AWS_IAM")}}
38
38
  session = create_aws_session()
39
39
  auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
40
- toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(
40
+ toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(
41
41
  url=url,
42
42
  httpx_client_factory=lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)
43
43
  )))
44
- {{else if (eq authType "CUSTOM_JWT")}}
44
+ {{else if (eq authType "CUSTOM_JWT")}}
45
45
  token = _get_bearer_token_{{snakeCase name}}()
46
46
  headers = {"Authorization": f"Bearer {token}"} if token else None
47
- toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url, headers=headers)))
48
- {{else}}
49
- toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url)))
50
- {{/if}}
47
+ toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(url=url, headers=headers)))
48
+ {{else}}
49
+ toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(url=url)))
50
+ {{/if}}
51
51
  else:
52
52
  logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
53
53
  {{/each}}
@@ -11,7 +11,8 @@ requires-python = ">=3.10"
11
11
  dependencies = [
12
12
  "opentelemetry-distro",
13
13
  "opentelemetry-exporter-otlp",
14
- "google-adk >= 1.17.0",
14
+ "google-adk >= 1.35.0, < 2.0.0",
15
+ "google-genai >= 1.0.0, < 2.0.0",
15
16
  "bedrock-agentcore >= 1.0.3",
16
17
  "botocore[crt] >= 1.35.0",
17
18
  {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
@@ -1,7 +1,17 @@
1
+ {{#if needsOs}}
1
2
  import os
2
- from langchain_core.messages import HumanMessage
3
+ {{/if}}
4
+ from collections import OrderedDict
5
+ from typing import Any
6
+
7
+ from langchain_core.messages import HumanMessage{{#if hasConfigBundle}}, SystemMessage{{/if}}
8
+ from langgraph.checkpoint.memory import InMemorySaver
3
9
  from langgraph.prebuilt import create_react_agent
4
10
  from langchain.tools import tool
11
+ {{#if hasConfigBundle}}
12
+ from langchain_core.callbacks import BaseCallbackHandler
13
+ from bedrock_agentcore.runtime.context import BedrockAgentCoreContext
14
+ {{/if}}
5
15
  from opentelemetry.instrumentation.langchain import LangchainInstrumentor
6
16
  from bedrock_agentcore.runtime import BedrockAgentCoreApp
7
17
  from model.load import load_model
@@ -25,6 +35,17 @@ def get_or_create_model():
25
35
  return _llm
26
36
 
27
37
 
38
+ DEFAULT_SYSTEM_PROMPT = """
39
+ You are a helpful assistant. Use tools when appropriate.
40
+ {{#if needsOs}}
41
+ You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
42
+ {{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
43
+ {{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
44
+ {{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
45
+ {{/each}}{{/if}}
46
+ """
47
+
48
+
28
49
  # Define a simple function tool
29
50
  @tool
30
51
  def add_numbers(a: int, b: int) -> int:
@@ -35,19 +56,42 @@ def add_numbers(a: int, b: int) -> int:
35
56
  # Define a collection of tools used by the model
36
57
  tools = [add_numbers]
37
58
 
38
- {{#if sessionStorageMountPath}}
39
- SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
59
+ # Module-level checkpointer preserves conversation history across invocations.
60
+ # InMemorySaver keeps every thread_id (= session_id) checkpoint in memory
61
+ # forever, so we bound it to 128 active threads with LRU eviction (the
62
+ # least-recently-used thread is deleted and its history reset) to keep a
63
+ # long-running process from growing without limit. For durable history, swap in
64
+ # a persistent checkpointer (e.g. SqliteSaver/AsyncSqliteSaver with a file path).
65
+ _CHECKPOINT_LIMIT = 128
66
+ _checkpointer = InMemorySaver()
67
+ _thread_ids = OrderedDict()
68
+
69
+
70
+ def touch_thread(thread_id):
71
+ if thread_id in _thread_ids:
72
+ _thread_ids.move_to_end(thread_id)
73
+ return
74
+ while len(_thread_ids) >= _CHECKPOINT_LIMIT:
75
+ evicted, _ = _thread_ids.popitem(last=False)
76
+ _checkpointer.delete_thread(evicted)
77
+ _thread_ids[thread_id] = True
78
+
79
+ {{#if needsOs}}
80
+ _MOUNT_PATHS = [
81
+ {{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
82
+ {{#each efsMounts}}"{{mountPath}}",{{/each}}
83
+ {{#each s3Mounts}}"{{mountPath}}",{{/each}}
84
+ ]
40
85
 
41
86
  def _safe_resolve(path: str) -> str:
42
- """Resolve path safely within the storage boundary."""
43
- resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
44
- if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
45
- raise ValueError(f"Path '{path}' is outside the storage boundary")
87
+ resolved = os.path.realpath(path)
88
+ if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
89
+ raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
46
90
  return resolved
47
91
 
48
92
  @tool
49
93
  def file_read(path: str) -> str:
50
- """Read a file from persistent storage. The path is relative to the storage root."""
94
+ """Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
51
95
  try:
52
96
  full_path = _safe_resolve(path)
53
97
  with open(full_path) as f:
@@ -59,7 +103,7 @@ def file_read(path: str) -> str:
59
103
 
60
104
  @tool
61
105
  def file_write(path: str, content: str) -> str:
62
- """Write content to a file in persistent storage. The path is relative to the storage root."""
106
+ """Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
63
107
  try:
64
108
  full_path = _safe_resolve(path)
65
109
  parent = os.path.dirname(full_path)
@@ -74,27 +118,42 @@ def file_write(path: str, content: str) -> str:
74
118
  return f"Error writing '{path}': {e.strerror}"
75
119
 
76
120
  @tool
77
- def list_files(directory: str = "") -> str:
78
- """List files in persistent storage. The directory is relative to the storage root."""
121
+ def list_files(path: str) -> str:
122
+ """List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
79
123
  try:
80
- target = _safe_resolve(directory)
81
- entries = os.listdir(target)
124
+ full_path = _safe_resolve(path)
125
+ entries = os.listdir(full_path)
82
126
  return "\n".join(entries) if entries else "(empty directory)"
83
127
  except ValueError as e:
84
128
  return str(e)
85
129
  except OSError as e:
86
- return f"Error listing '{directory}': {e.strerror}"
130
+ return f"Error listing '{path}': {e.strerror}"
87
131
 
88
132
  tools.extend([file_read, file_write, list_files])
89
133
  {{/if}}
90
134
 
91
- SYSTEM_PROMPT = """
92
- You are a helpful assistant. Use tools when appropriate.
93
- {{#if sessionStorageMountPath}}
94
- You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
95
- {{/if}}
96
- """
135
+ {{#if hasConfigBundle}}
136
+
137
+ class ConfigBundleCallback(BaseCallbackHandler):
138
+ """Injects config bundle values into LangGraph agent at runtime.
97
139
 
140
+ BedrockAgentCoreContext.get_config_bundle() fetches the component configuration
141
+ for the current runtime ARN from the config bundle service. The SDK caches the
142
+ result and refreshes on bundle version changes.
143
+ """
144
+
145
+ def on_chain_start(self, serialized: dict, inputs: dict, **kwargs: Any) -> None:
146
+ config = BedrockAgentCoreContext.get_config_bundle()
147
+ prompt = config.get("systemPrompt", DEFAULT_SYSTEM_PROMPT)
148
+
149
+ messages = inputs.get("messages", [])
150
+ if messages and isinstance(messages[0], SystemMessage):
151
+ messages[0] = SystemMessage(content=prompt)
152
+ else:
153
+ messages.insert(0, SystemMessage(content=prompt))
154
+ inputs["messages"] = messages
155
+
156
+ {{/if}}
98
157
 
99
158
  @app.entrypoint
100
159
  async def invoke(payload, context):
@@ -112,15 +171,47 @@ async def invoke(payload, context):
112
171
  if mcp_client:
113
172
  mcp_tools = await mcp_client.get_tools()
114
173
 
115
- # Define the agent using create_react_agent
116
- graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=SYSTEM_PROMPT)
174
+ # Define the agent using create_react_agent (checkpointer is shared across invocations)
175
+ {{#if hasConfigBundle}}
176
+ graph = create_react_agent(
177
+ get_or_create_model(),
178
+ tools=mcp_tools + tools,
179
+ prompt=DEFAULT_SYSTEM_PROMPT,
180
+ checkpointer=_checkpointer,
181
+ )
182
+ callback = ConfigBundleCallback()
117
183
 
118
184
  # Process the user prompt
119
185
  prompt = payload.get("prompt", "What can you help me with?")
186
+ session_id = getattr(context, "session_id", "default-session")
187
+ touch_thread(session_id)
120
188
  log.info(f"Agent input: {prompt}")
121
189
 
122
- # Run the agent
123
- result = await graph.ainvoke({"messages": [HumanMessage(content=prompt)]})
190
+ # Run the agent with config bundle callback (checkpointer auto-loads/saves history per session)
191
+ result = await graph.ainvoke(
192
+ {"messages": [HumanMessage(content=prompt)]},
193
+ config={"callbacks": [callback], "configurable": {"thread_id": session_id}},
194
+ )
195
+ {{else}}
196
+ graph = create_react_agent(
197
+ get_or_create_model(),
198
+ tools=mcp_tools + tools,
199
+ prompt=DEFAULT_SYSTEM_PROMPT,
200
+ checkpointer=_checkpointer,
201
+ )
202
+
203
+ # Process the user prompt
204
+ prompt = payload.get("prompt", "What can you help me with?")
205
+ session_id = getattr(context, "session_id", "default-session")
206
+ touch_thread(session_id)
207
+ log.info(f"Agent input: {prompt}")
208
+
209
+ # Run the agent (checkpointer auto-loads/saves history per session)
210
+ result = await graph.ainvoke(
211
+ {"messages": [HumanMessage(content=prompt)]},
212
+ config={"configurable": {"thread_id": session_id}},
213
+ )
214
+ {{/if}}
124
215
 
125
216
  # Return result
126
217
  output = result["messages"][-1].content
@@ -32,23 +32,25 @@ def get_all_gateway_mcp_client() -> MultiServerMCPClient | None:
32
32
  {{#each gatewayProviders}}
33
33
  url = os.environ.get("{{envVarName}}")
34
34
  if url:
35
- {{#if (eq authType "AWS_IAM")}}
35
+ {{#if (eq authType "AWS_IAM")}}
36
36
  session = create_aws_session()
37
37
  auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
38
- servers["{{name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
39
- {{else if (eq authType "CUSTOM_JWT")}}
38
+ servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
39
+ {{else if (eq authType "CUSTOM_JWT")}}
40
40
  token = _get_bearer_token_{{snakeCase name}}()
41
41
  headers = {"Authorization": f"Bearer {token}"} if token else None
42
- servers["{{name}}"] = {"transport": "streamable_http", "url": url, "headers": headers}
43
- {{else}}
44
- servers["{{name}}"] = {"transport": "streamable_http", "url": url}
45
- {{/if}}
42
+ servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url, "headers": headers}
43
+ {{else}}
44
+ servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url}
45
+ {{/if}}
46
46
  else:
47
47
  logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
48
48
  {{/each}}
49
49
  if not servers:
50
50
  return None
51
- return MultiServerMCPClient(servers)
51
+ # tool_name_prefix namespaces each gateway's tools by server key so multiple
52
+ # gateways exposing the same tool (e.g. x_amz_bedrock_agentcore_search) don't collide.
53
+ return MultiServerMCPClient(servers, tool_name_prefix=True)
52
54
  {{else}}
53
55
  {{#if isVpc}}
54
56
  # VPC mode: external MCP endpoints are not reachable without a NAT gateway.
@@ -13,9 +13,9 @@ dependencies = [
13
13
  "opentelemetry-instrumentation-langchain >= 0.59.0",
14
14
  "langgraph >= 1.0.2",
15
15
  "mcp >= 1.19.0",
16
- "langchain-mcp-adapters >= 0.1.11",
16
+ "langchain-mcp-adapters >= 0.2.0",
17
17
  "langchain >= 1.0.3",
18
- "bedrock-agentcore >= 1.0.3",
18
+ "bedrock-agentcore >= 1.8.0",
19
19
  "botocore[crt] >= 1.35.0",
20
20
  {{#if (eq modelProvider "Bedrock")}}
21
21
  "langchain-aws >= 1.0.0",
@@ -28,6 +28,7 @@ dependencies = [
28
28
  {{/if}}
29
29
  {{#if (eq modelProvider "Gemini")}}
30
30
  "langchain-google-genai >= 3.0.3",
31
+ "google-genai >= 1.0.0, < 2.0.0",
31
32
  {{/if}}
32
33
  {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
33
34
  {{/if}}{{/if}}
@@ -1,5 +1,11 @@
1
+ {{#if needsOs}}
1
2
  import os
2
- from agents import Agent, Runner, function_tool
3
+ {{/if}}
4
+ {{#if hasGateway}}
5
+ from contextlib import AsyncExitStack
6
+ {{/if}}
7
+ from functools import lru_cache
8
+ from agents import Agent, Runner, SQLiteSession, function_tool
3
9
  from bedrock_agentcore.runtime import BedrockAgentCoreApp
4
10
  from model.load import load_model
5
11
  {{#if hasGateway}}
@@ -37,19 +43,22 @@ def add_numbers(a: int, b: int) -> int:
37
43
 
38
44
  tools = [add_numbers]
39
45
 
40
- {{#if sessionStorageMountPath}}
41
- SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
46
+ {{#if needsOs}}
47
+ _MOUNT_PATHS = [
48
+ {{#if sessionStorageMountPath}}"{{sessionStorageMountPath}}",{{/if}}
49
+ {{#each efsMounts}}"{{mountPath}}",{{/each}}
50
+ {{#each s3Mounts}}"{{mountPath}}",{{/each}}
51
+ ]
42
52
 
43
53
  def _safe_resolve(path: str) -> str:
44
- """Resolve path safely within the storage boundary."""
45
- resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
46
- if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
47
- raise ValueError(f"Path '{path}' is outside the storage boundary")
54
+ resolved = os.path.realpath(path)
55
+ if not any(resolved == os.path.realpath(m) or resolved.startswith(os.path.realpath(m) + os.sep) for m in _MOUNT_PATHS):
56
+ raise ValueError(f"Path '{path}' is not within any configured mount ({', '.join(_MOUNT_PATHS)})")
48
57
  return resolved
49
58
 
50
59
  @function_tool
51
60
  def file_read(path: str) -> str:
52
- """Read a file from persistent storage. The path is relative to the storage root."""
61
+ """Read a file from a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
53
62
  try:
54
63
  full_path = _safe_resolve(path)
55
64
  with open(full_path) as f:
@@ -61,7 +70,7 @@ def file_read(path: str) -> str:
61
70
 
62
71
  @function_tool
63
72
  def file_write(path: str, content: str) -> str:
64
- """Write content to a file in persistent storage. The path is relative to the storage root."""
73
+ """Write a file to a mounted filesystem. Use the absolute path (e.g. /mnt/tools/data.txt)."""
65
74
  try:
66
75
  full_path = _safe_resolve(path)
67
76
  parent = os.path.dirname(full_path)
@@ -76,42 +85,60 @@ def file_write(path: str, content: str) -> str:
76
85
  return f"Error writing '{path}': {e.strerror}"
77
86
 
78
87
  @function_tool
79
- def list_files(directory: str = "") -> str:
80
- """List files in persistent storage. The directory is relative to the storage root."""
88
+ def list_files(path: str) -> str:
89
+ """List files in a mounted filesystem directory. Use the absolute path (e.g. /mnt/tools)."""
81
90
  try:
82
- target = _safe_resolve(directory)
83
- entries = os.listdir(target)
91
+ full_path = _safe_resolve(path)
92
+ entries = os.listdir(full_path)
84
93
  return "\n".join(entries) if entries else "(empty directory)"
85
94
  except ValueError as e:
86
95
  return str(e)
87
96
  except OSError as e:
88
- return f"Error listing '{directory}': {e.strerror}"
97
+ return f"Error listing '{path}': {e.strerror}"
89
98
 
90
99
  tools.extend([file_read, file_write, list_files])
91
100
  {{/if}}
92
101
 
93
102
  INSTRUCTIONS = """
94
103
  You are a helpful assistant. Use tools when appropriate.
95
- {{#if sessionStorageMountPath}}
96
- You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
97
- {{/if}}
104
+ {{#if needsOs}}
105
+ You have access to the following mounted filesystems. Use file_read, file_write, and list_files with full absolute paths:
106
+ {{#if sessionStorageMountPath}}- {{sessionStorageMountPath}}: ephemeral session storage (lost when session ends)
107
+ {{/if}}{{#each efsMounts}}- {{mountPath}}: EFS persistent storage (persists across sessions and agent restarts)
108
+ {{/each}}{{#each s3Mounts}}- {{mountPath}}: S3 Files persistent storage (durable, backed by S3)
109
+ {{/each}}{{/if}}
98
110
  """
99
111
 
112
+ # Caches up to 128 active sessions; LRU eviction silently resets history for
113
+ # the oldest session. For production use, replace with a durable session store
114
+ # (e.g. SQLiteSession with a file path).
115
+ @lru_cache(maxsize=128)
116
+ def get_session(session_id):
117
+ return SQLiteSession(session_id)
118
+
119
+
100
120
  # Define the agent execution
101
- async def main(query):
121
+ async def main(query, session):
102
122
  ensure_credentials_loaded()
103
123
  try:
104
124
  {{#if hasGateway}}
105
125
  if mcp_servers:
106
- agent = Agent(
107
- name="{{ name }}",
108
- model="gpt-4.1",
109
- instructions=INSTRUCTIONS,
110
- mcp_servers=mcp_servers,
111
- tools=tools
112
- )
113
- result = await Runner.run(agent, query)
114
- return result
126
+ # Connect every gateway server before the run; include_server_in_tool_names
127
+ # namespaces each server's tools so multiple gateways exposing the same tool
128
+ # (e.g. x_amz_bedrock_agentcore_search) don't collide.
129
+ async with AsyncExitStack() as stack:
130
+ for server in mcp_servers:
131
+ await stack.enter_async_context(server)
132
+ agent = Agent(
133
+ name="{{ name }}",
134
+ model="gpt-4.1",
135
+ instructions=INSTRUCTIONS,
136
+ mcp_servers=mcp_servers,
137
+ tools=tools,
138
+ mcp_config={"include_server_in_tool_names": True},
139
+ )
140
+ result = await Runner.run(agent, query, session=session)
141
+ return result
115
142
  else:
116
143
  agent = Agent(
117
144
  name="{{ name }}",
@@ -120,7 +147,7 @@ async def main(query):
120
147
  mcp_servers=[],
121
148
  tools=tools
122
149
  )
123
- result = await Runner.run(agent, query)
150
+ result = await Runner.run(agent, query, session=session)
124
151
  return result
125
152
  {{else}}
126
153
  if mcp_servers:
@@ -133,7 +160,7 @@ async def main(query):
133
160
  mcp_servers=active_servers,
134
161
  tools=tools
135
162
  )
136
- result = await Runner.run(agent, query)
163
+ result = await Runner.run(agent, query, session=session)
137
164
  return result
138
165
  else:
139
166
  agent = Agent(
@@ -143,7 +170,7 @@ async def main(query):
143
170
  mcp_servers=[],
144
171
  tools=tools
145
172
  )
146
- result = await Runner.run(agent, query)
173
+ result = await Runner.run(agent, query, session=session)
147
174
  return result
148
175
  {{/if}}
149
176
  except Exception as e:
@@ -157,9 +184,11 @@ async def invoke(payload, context):
157
184
 
158
185
  # Process the user prompt
159
186
  prompt = payload.get("prompt", "What can you help me with?")
187
+ session_id = getattr(context, "session_id", "default-session")
188
+ session = get_session(session_id)
160
189
 
161
- # Run the agent
162
- result = await main(prompt)
190
+ # Run the agent (session automatically loads/saves conversation history)
191
+ result = await main(prompt, session)
163
192
 
164
193
  # Return result
165
194
  return {"result": result.final_output}
@@ -33,20 +33,20 @@ def get_all_gateway_mcp_servers() -> list[MCPServerStreamableHttp]:
33
33
  {{#each gatewayProviders}}
34
34
  url = os.environ.get("{{envVarName}}")
35
35
  if url:
36
- {{#if (eq authType "AWS_IAM")}}
36
+ {{#if (eq authType "AWS_IAM")}}
37
37
  session = create_aws_session()
38
38
  auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
39
39
  servers.append(MCPServerStreamableHttp(
40
40
  name="{{name}}",
41
41
  params={"url": url, "httpx_client_factory": lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)}
42
42
  ))
43
- {{else if (eq authType "CUSTOM_JWT")}}
43
+ {{else if (eq authType "CUSTOM_JWT")}}
44
44
  token = _get_bearer_token_{{snakeCase name}}()
45
45
  headers = {"Authorization": f"Bearer {token}"} if token else {}
46
46
  servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url, "headers": headers}))
47
- {{else}}
47
+ {{else}}
48
48
  servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url}))
49
- {{/if}}
49
+ {{/if}}
50
50
  else:
51
51
  logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
52
52
  {{/each}}
@@ -10,8 +10,8 @@ readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  dependencies = [
12
12
  "aws-opentelemetry-distro",
13
- "openai-agents >= 0.4.2",
14
- "bedrock-agentcore >= 1.0.3",
13
+ "openai-agents >= 0.16.0",
14
+ "bedrock-agentcore >= 1.8.0",
15
15
  "botocore[crt] >= 1.35.0",
16
16
  {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",
17
17
  {{/if}}{{/if}}