@aws/agentcore 0.8.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/agent-inspector/favicon.svg +60 -0
  2. package/dist/agent-inspector/index.css +1 -0
  3. package/dist/agent-inspector/index.html +14 -0
  4. package/dist/agent-inspector/index.js +274 -0
  5. package/dist/assets/README.md +56 -31
  6. package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +1669 -245
  7. package/dist/assets/__tests__/__snapshots__/dockerfile-render.test.ts.snap +77 -0
  8. package/dist/assets/__tests__/dockerfile-render.test.ts +24 -0
  9. package/dist/assets/agents/AGENTS.md +84 -55
  10. package/dist/assets/cdk/cdk.json +1 -1
  11. package/dist/assets/cdk/package.json +1 -1
  12. package/dist/assets/container/python/Dockerfile +4 -0
  13. package/dist/assets/evaluators/python-lambda/execution-role-policy.json +1 -1
  14. package/dist/assets/python/a2a/googleadk/base/main.py +65 -3
  15. package/dist/assets/python/a2a/langchain_langgraph/base/main.py +64 -1
  16. package/dist/assets/python/a2a/strands/base/main.py +65 -2
  17. package/dist/assets/python/agui/googleadk/base/README.md +30 -0
  18. package/dist/assets/python/agui/googleadk/base/gitignore.template +41 -0
  19. package/dist/assets/python/agui/googleadk/base/main.py +31 -0
  20. package/dist/assets/python/agui/googleadk/base/model/__init__.py +1 -0
  21. package/dist/assets/python/agui/googleadk/base/model/load.py +41 -0
  22. package/dist/assets/python/agui/googleadk/base/pyproject.toml +24 -0
  23. package/dist/assets/python/agui/langchain_langgraph/base/README.md +22 -0
  24. package/dist/assets/python/agui/langchain_langgraph/base/gitignore.template +41 -0
  25. package/dist/assets/python/agui/langchain_langgraph/base/main.py +74 -0
  26. package/dist/assets/python/agui/langchain_langgraph/base/model/__init__.py +1 -0
  27. package/dist/assets/python/agui/langchain_langgraph/base/model/load.py +123 -0
  28. package/dist/assets/python/agui/langchain_langgraph/base/pyproject.toml +30 -0
  29. package/dist/assets/python/agui/strands/base/README.md +22 -0
  30. package/dist/assets/python/agui/strands/base/gitignore.template +41 -0
  31. package/dist/assets/python/agui/strands/base/main.py +43 -0
  32. package/dist/assets/python/agui/strands/base/model/__init__.py +1 -0
  33. package/dist/assets/python/agui/strands/base/model/load.py +123 -0
  34. package/dist/assets/python/agui/strands/base/pyproject.toml +27 -0
  35. package/dist/assets/python/agui/strands/capabilities/memory/__init__.py +1 -0
  36. package/dist/assets/python/agui/strands/capabilities/memory/session.py +38 -0
  37. package/dist/assets/python/http/autogen/base/main.py +61 -1
  38. package/dist/assets/python/http/googleadk/base/main.py +62 -2
  39. package/dist/assets/python/http/langchain_langgraph/base/main.py +61 -1
  40. package/dist/assets/python/http/openaiagents/base/main.py +70 -4
  41. package/dist/assets/python/http/strands/base/main.py +64 -6
  42. package/dist/cli/index.mjs +480 -457
  43. package/dist/lib/errors/config.d.ts.map +1 -1
  44. package/dist/lib/errors/config.js +5 -2
  45. package/dist/lib/errors/config.js.map +1 -1
  46. package/dist/schema/constants.d.ts +1 -0
  47. package/dist/schema/constants.d.ts.map +1 -1
  48. package/dist/schema/constants.js +8 -1
  49. package/dist/schema/constants.js.map +1 -1
  50. package/dist/schema/schemas/agent-env.d.ts +20 -0
  51. package/dist/schema/schemas/agent-env.d.ts.map +1 -1
  52. package/dist/schema/schemas/agent-env.js +17 -2
  53. package/dist/schema/schemas/agent-env.js.map +1 -1
  54. package/dist/schema/schemas/agentcore-project.d.ts +6 -0
  55. package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
  56. package/dist/schema/schemas/aws-targets.d.ts +3 -0
  57. package/dist/schema/schemas/aws-targets.d.ts.map +1 -1
  58. package/dist/schema/schemas/aws-targets.js +1 -0
  59. package/dist/schema/schemas/aws-targets.js.map +1 -1
  60. package/dist/schema/schemas/primitives/evaluator.d.ts.map +1 -1
  61. package/dist/schema/schemas/primitives/evaluator.js +0 -1
  62. package/dist/schema/schemas/primitives/evaluator.js.map +1 -1
  63. package/package.json +4 -1
  64. package/scripts/bump-version.ts +7 -80
  65. package/scripts/copy-assets.mjs +14 -0
@@ -149,7 +149,7 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/cdk.json should match
149
149
  "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true,
150
150
  "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
151
151
  "@aws-cdk/core:checkSecretUsage": true,
152
- "@aws-cdk/core:target-partitions": ["aws", "aws-cn"],
152
+ "@aws-cdk/core:target-partitions": ["aws", "aws-cn", "aws-us-gov"],
153
153
  "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
154
154
  "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
155
155
  "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
@@ -357,7 +357,7 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/package.json should m
357
357
  "typescript": "~5.9.3"
358
358
  },
359
359
  "dependencies": {
360
- "@aws/agentcore-cdk": "0.1.0-alpha.19",
360
+ "@aws/agentcore-cdk": "^0.1.0-alpha.19",
361
361
  "aws-cdk-lib": "^2.248.0",
362
362
  "constructs": "^10.0.0"
363
363
  }
@@ -475,6 +475,26 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f
475
475
  "python/a2a/strands/base/pyproject.toml",
476
476
  "python/a2a/strands/capabilities/memory/__init__.py",
477
477
  "python/a2a/strands/capabilities/memory/session.py",
478
+ "python/agui/googleadk/base/README.md",
479
+ "python/agui/googleadk/base/gitignore.template",
480
+ "python/agui/googleadk/base/main.py",
481
+ "python/agui/googleadk/base/model/__init__.py",
482
+ "python/agui/googleadk/base/model/load.py",
483
+ "python/agui/googleadk/base/pyproject.toml",
484
+ "python/agui/langchain_langgraph/base/README.md",
485
+ "python/agui/langchain_langgraph/base/gitignore.template",
486
+ "python/agui/langchain_langgraph/base/main.py",
487
+ "python/agui/langchain_langgraph/base/model/__init__.py",
488
+ "python/agui/langchain_langgraph/base/model/load.py",
489
+ "python/agui/langchain_langgraph/base/pyproject.toml",
490
+ "python/agui/strands/base/README.md",
491
+ "python/agui/strands/base/gitignore.template",
492
+ "python/agui/strands/base/main.py",
493
+ "python/agui/strands/base/model/__init__.py",
494
+ "python/agui/strands/base/model/load.py",
495
+ "python/agui/strands/base/pyproject.toml",
496
+ "python/agui/strands/capabilities/memory/__init__.py",
497
+ "python/agui/strands/capabilities/memory/session.py",
478
498
  "python/http/autogen/base/README.md",
479
499
  "python/http/autogen/base/gitignore.template",
480
500
  "python/http/autogen/base/main.py",
@@ -968,7 +988,8 @@ Thumbs.db
968
988
  `;
969
989
 
970
990
  exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/main.py should match snapshot 1`] = `
971
- "from google.adk.agents import Agent
991
+ "import os
992
+ from google.adk.agents import Agent
972
993
  from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
973
994
  from google.adk.runners import Runner
974
995
  from google.adk.sessions import InMemorySessionService
@@ -976,55 +997,1058 @@ from a2a.types import AgentCapabilities, AgentCard, AgentSkill
976
997
  from bedrock_agentcore.runtime import serve_a2a
977
998
  from model.load import load_model
978
999
 
1000
+ load_model() # Sets GOOGLE_API_KEY env var (returns None)
1001
+
1002
+
1003
+ def add_numbers(a: int, b: int) -> int:
1004
+ """Return the sum of two numbers."""
1005
+ return a + b
1006
+
1007
+
1008
+ tools = [add_numbers]
1009
+
1010
+ {{#if sessionStorageMountPath}}
1011
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
1012
+
1013
+ def _safe_resolve(path: str) -> str:
1014
+ """Resolve path safely within the storage boundary."""
1015
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
1016
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
1017
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
1018
+ return resolved
1019
+
1020
+ def file_read(path: str) -> str:
1021
+ """Read a file from persistent storage. The path is relative to the storage root."""
1022
+ try:
1023
+ full_path = _safe_resolve(path)
1024
+ with open(full_path) as f:
1025
+ return f.read()
1026
+ except ValueError as e:
1027
+ return str(e)
1028
+ except OSError as e:
1029
+ return f"Error reading '{path}': {e.strerror}"
1030
+
1031
+ def file_write(path: str, content: str) -> str:
1032
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
1033
+ try:
1034
+ full_path = _safe_resolve(path)
1035
+ parent = os.path.dirname(full_path)
1036
+ if parent:
1037
+ os.makedirs(parent, exist_ok=True)
1038
+ with open(full_path, "w") as f:
1039
+ f.write(content)
1040
+ return f"Written to {path}"
1041
+ except ValueError as e:
1042
+ return str(e)
1043
+ except OSError as e:
1044
+ return f"Error writing '{path}': {e.strerror}"
1045
+
1046
+ def list_files(directory: str = "") -> str:
1047
+ """List files in persistent storage. The directory is relative to the storage root."""
1048
+ try:
1049
+ target = _safe_resolve(directory)
1050
+ entries = os.listdir(target)
1051
+ return "\\n".join(entries) if entries else "(empty directory)"
1052
+ except ValueError as e:
1053
+ return str(e)
1054
+ except OSError as e:
1055
+ return f"Error listing '{directory}': {e.strerror}"
1056
+
1057
+ tools.extend([file_read, file_write, list_files])
1058
+ {{/if}}
1059
+
1060
+ AGENT_INSTRUCTION = """
1061
+ You are a helpful assistant. Use tools when appropriate.
1062
+ {{#if sessionStorageMountPath}}
1063
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
1064
+ {{/if}}
1065
+ """
1066
+
1067
+ agent = Agent(
1068
+ model="gemini-2.5-flash",
1069
+ name="{{ name }}",
1070
+ description="A helpful assistant that can use tools.",
1071
+ instruction=AGENT_INSTRUCTION,
1072
+ tools=tools,
1073
+ )
1074
+
1075
+ runner = Runner(
1076
+ app_name=agent.name,
1077
+ agent=agent,
1078
+ session_service=InMemorySessionService(),
1079
+ )
1080
+
1081
+ card = AgentCard(
1082
+ name=agent.name,
1083
+ description=agent.description,
1084
+ url="http://localhost:9000/",
1085
+ version="0.1.0",
1086
+ capabilities=AgentCapabilities(streaming=True),
1087
+ skills=[
1088
+ AgentSkill(
1089
+ id="tools",
1090
+ name="tools",
1091
+ description="Use tools to help answer questions",
1092
+ tags=["tools"],
1093
+ )
1094
+ ],
1095
+ default_input_modes=["text"],
1096
+ default_output_modes=["text"],
1097
+ )
1098
+
1099
+ if __name__ == "__main__":
1100
+ serve_a2a(A2aAgentExecutor(runner=runner), card)
1101
+ "
1102
+ `;
1103
+
1104
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/model/__init__.py should match snapshot 1`] = `
1105
+ "# Package marker
1106
+ "
1107
+ `;
1108
+
1109
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/model/load.py should match snapshot 1`] = `
1110
+ "import os
1111
+ from bedrock_agentcore.identity.auth import requires_api_key
1112
+
1113
+ IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
1114
+ IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
1115
+
1116
+
1117
+ @requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
1118
+ def _agentcore_identity_api_key_provider(api_key: str) -> str:
1119
+ """Fetch API key from AgentCore Identity."""
1120
+ return api_key
1121
+
1122
+
1123
+ def _get_api_key() -> str:
1124
+ """
1125
+ Uses AgentCore Identity for API key management in deployed environments.
1126
+ For local development, run via 'agentcore dev' which loads agentcore/.env.
1127
+ """
1128
+ if os.getenv("LOCAL_DEV") == "1":
1129
+ api_key = os.getenv(IDENTITY_ENV_VAR)
1130
+ if not api_key:
1131
+ raise RuntimeError(
1132
+ f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
1133
+ )
1134
+ return api_key
1135
+ return _agentcore_identity_api_key_provider()
1136
+
1137
+
1138
+ def load_model() -> None:
1139
+ """
1140
+ Set up Gemini API key authentication.
1141
+ Uses AgentCore Identity for API key management in deployed environments,
1142
+ and falls back to .env file for local development.
1143
+ Sets the GOOGLE_API_KEY environment variable for the Google ADK.
1144
+ """
1145
+ api_key = _get_api_key()
1146
+ # Use Google AI Studios API Key Authentication.
1147
+ # https://google.github.io/adk-docs/agents/models/#google-ai-studio
1148
+ os.environ["GOOGLE_API_KEY"] = api_key
1149
+ # Set to TRUE is using Google Vertex AI, Set to FALSE for Google AI Studio
1150
+ os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "FALSE"
1151
+ "
1152
+ `;
1153
+
1154
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/pyproject.toml should match snapshot 1`] = `
1155
+ "[build-system]
1156
+ requires = ["hatchling"]
1157
+ build-backend = "hatchling.build"
1158
+
1159
+ [project]
1160
+ name = "{{ name }}"
1161
+ version = "0.1.0"
1162
+ description = "AgentCore A2A Agent using Google ADK"
1163
+ readme = "README.md"
1164
+ requires-python = ">=3.10"
1165
+ dependencies = [
1166
+ "a2a-sdk >= 0.2.0",
1167
+ "aws-opentelemetry-distro",
1168
+ "bedrock-agentcore[a2a] >= 1.0.3",
1169
+ "google-adk >= 1.0.0",
1170
+ "google-genai >= 1.0.0",
1171
+ ]
1172
+
1173
+ [tool.hatch.build.targets.wheel]
1174
+ packages = ["."]
1175
+ "
1176
+ `;
1177
+
1178
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/README.md should match snapshot 1`] = `
1179
+ "# {{ name }}
1180
+
1181
+ An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using LangChain + LangGraph.
1182
+
1183
+ ## Overview
1184
+
1185
+ This agent implements the A2A protocol using LangGraph, enabling agent-to-agent communication.
1186
+
1187
+ ## Local Development
1188
+
1189
+ \`\`\`bash
1190
+ uv sync
1191
+ uv run python main.py
1192
+ \`\`\`
1193
+
1194
+ The agent starts on port 9000.
1195
+
1196
+ ## Deploy
1197
+
1198
+ \`\`\`bash
1199
+ agentcore deploy
1200
+ \`\`\`
1201
+ "
1202
+ `;
1203
+
1204
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/gitignore.template should match snapshot 1`] = `
1205
+ "# Environment variables
1206
+ .env
1207
+
1208
+ # Python
1209
+ __pycache__/
1210
+ *.py[cod]
1211
+ *$py.class
1212
+ *.so
1213
+ .Python
1214
+ build/
1215
+ develop-eggs/
1216
+ dist/
1217
+ downloads/
1218
+ eggs/
1219
+ .eggs/
1220
+ lib/
1221
+ lib64/
1222
+ parts/
1223
+ sdist/
1224
+ var/
1225
+ wheels/
1226
+ *.egg-info/
1227
+ .installed.cfg
1228
+ *.egg
1229
+
1230
+ # Virtual environments
1231
+ .venv/
1232
+ venv/
1233
+ ENV/
1234
+ env/
1235
+
1236
+ # IDE
1237
+ .vscode/
1238
+ .idea/
1239
+ *.swp
1240
+ *.swo
1241
+ *~
1242
+
1243
+ # OS
1244
+ .DS_Store
1245
+ Thumbs.db
1246
+ "
1247
+ `;
1248
+
1249
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/main.py should match snapshot 1`] = `
1250
+ "import os
1251
+ from langchain_core.tools import tool
1252
+ from langgraph.prebuilt import create_react_agent
1253
+ from opentelemetry.instrumentation.langchain import LangchainInstrumentor
1254
+ from a2a.server.agent_execution import AgentExecutor, RequestContext
1255
+ from a2a.server.events import EventQueue
1256
+ from a2a.server.tasks import TaskUpdater
1257
+ from a2a.types import AgentCapabilities, AgentCard, AgentSkill, Part, TextPart
1258
+ from a2a.utils import new_task
1259
+ from bedrock_agentcore.runtime import serve_a2a
1260
+ from model.load import load_model
1261
+
1262
+ LangchainInstrumentor().instrument()
1263
+
1264
+
1265
+ @tool
1266
+ def add_numbers(a: int, b: int) -> int:
1267
+ """Return the sum of two numbers."""
1268
+ return a + b
1269
+
1270
+
1271
+ tools = [add_numbers]
1272
+
1273
+ {{#if sessionStorageMountPath}}
1274
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
1275
+
1276
+ def _safe_resolve(path: str) -> str:
1277
+ """Resolve path safely within the storage boundary."""
1278
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
1279
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
1280
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
1281
+ return resolved
1282
+
1283
+ @tool
1284
+ def file_read(path: str) -> str:
1285
+ """Read a file from persistent storage. The path is relative to the storage root."""
1286
+ try:
1287
+ full_path = _safe_resolve(path)
1288
+ with open(full_path) as f:
1289
+ return f.read()
1290
+ except ValueError as e:
1291
+ return str(e)
1292
+ except OSError as e:
1293
+ return f"Error reading '{path}': {e.strerror}"
1294
+
1295
+ @tool
1296
+ def file_write(path: str, content: str) -> str:
1297
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
1298
+ try:
1299
+ full_path = _safe_resolve(path)
1300
+ parent = os.path.dirname(full_path)
1301
+ if parent:
1302
+ os.makedirs(parent, exist_ok=True)
1303
+ with open(full_path, "w") as f:
1304
+ f.write(content)
1305
+ return f"Written to {path}"
1306
+ except ValueError as e:
1307
+ return str(e)
1308
+ except OSError as e:
1309
+ return f"Error writing '{path}': {e.strerror}"
1310
+
1311
+ @tool
1312
+ def list_files(directory: str = "") -> str:
1313
+ """List files in persistent storage. The directory is relative to the storage root."""
1314
+ try:
1315
+ target = _safe_resolve(directory)
1316
+ entries = os.listdir(target)
1317
+ return "\\n".join(entries) if entries else "(empty directory)"
1318
+ except ValueError as e:
1319
+ return str(e)
1320
+ except OSError as e:
1321
+ return f"Error listing '{directory}': {e.strerror}"
1322
+
1323
+ tools.extend([file_read, file_write, list_files])
1324
+ {{/if}}
1325
+
1326
+ SYSTEM_PROMPT = """
1327
+ You are a helpful assistant. Use tools when appropriate.
1328
+ {{#if sessionStorageMountPath}}
1329
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
1330
+ {{/if}}
1331
+ """
1332
+
1333
+ model = load_model()
1334
+ graph = create_react_agent(model, tools=tools, prompt=SYSTEM_PROMPT)
1335
+
1336
+
1337
+ class LangGraphA2AExecutor(AgentExecutor):
1338
+ """Wraps a LangGraph CompiledGraph as an a2a-sdk AgentExecutor."""
1339
+
1340
+ def __init__(self, graph):
1341
+ self.graph = graph
1342
+
1343
+ async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
1344
+ task = context.current_task or new_task(context.message)
1345
+ if not context.current_task:
1346
+ await event_queue.enqueue_event(task)
1347
+ updater = TaskUpdater(event_queue, task.id, task.context_id)
1348
+
1349
+ user_text = context.get_user_input()
1350
+ result = await self.graph.ainvoke({"messages": [("user", user_text)]})
1351
+ response = result["messages"][-1].content
1352
+
1353
+ await updater.add_artifact([Part(root=TextPart(text=response))])
1354
+ await updater.complete()
1355
+
1356
+ async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
1357
+ pass
1358
+
1359
+
1360
+ card = AgentCard(
1361
+ name="{{ name }}",
1362
+ description="A LangGraph agent on Bedrock AgentCore",
1363
+ url="http://localhost:9000/",
1364
+ version="0.1.0",
1365
+ capabilities=AgentCapabilities(streaming=True),
1366
+ skills=[
1367
+ AgentSkill(
1368
+ id="tools",
1369
+ name="tools",
1370
+ description="Use tools to help answer questions",
1371
+ tags=["tools"],
1372
+ )
1373
+ ],
1374
+ default_input_modes=["text"],
1375
+ default_output_modes=["text"],
1376
+ )
1377
+
1378
+ if __name__ == "__main__":
1379
+ serve_a2a(LangGraphA2AExecutor(graph), card)
1380
+ "
1381
+ `;
1382
+
1383
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/model/__init__.py should match snapshot 1`] = `
1384
+ "# Package marker
1385
+ "
1386
+ `;
1387
+
1388
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/model/load.py should match snapshot 1`] = `
1389
+ "{{#if (eq modelProvider "Bedrock")}}
1390
+ from langchain_aws import ChatBedrock
1391
+
1392
+ # Uses global inference profile for Claude Sonnet 4.5
1393
+ # https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html
1394
+ MODEL_ID = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
1395
+
1396
+
1397
+ def load_model() -> ChatBedrock:
1398
+ """Get Bedrock model client using IAM credentials."""
1399
+ return ChatBedrock(model_id=MODEL_ID)
1400
+ {{/if}}
1401
+ {{#if (eq modelProvider "Anthropic")}}
1402
+ import os
1403
+ from langchain_anthropic import ChatAnthropic
1404
+ from bedrock_agentcore.identity.auth import requires_api_key
1405
+
1406
+ IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
1407
+ IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
1408
+
1409
+
1410
+ @requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
1411
+ def _agentcore_identity_api_key_provider(api_key: str) -> str:
1412
+ """Fetch API key from AgentCore Identity."""
1413
+ return api_key
1414
+
1415
+
1416
+ def _get_api_key() -> str:
1417
+ """
1418
+ Uses AgentCore Identity for API key management in deployed environments.
1419
+ For local development, run via 'agentcore dev' which loads agentcore/.env.
1420
+ """
1421
+ if os.getenv("LOCAL_DEV") == "1":
1422
+ api_key = os.getenv(IDENTITY_ENV_VAR)
1423
+ if not api_key:
1424
+ raise RuntimeError(
1425
+ f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
1426
+ )
1427
+ return api_key
1428
+ return _agentcore_identity_api_key_provider()
1429
+
1430
+
1431
+ def load_model() -> ChatAnthropic:
1432
+ """Get authenticated Anthropic model client."""
1433
+ return ChatAnthropic(
1434
+ model="claude-sonnet-4-5-20250929",
1435
+ api_key=_get_api_key()
1436
+ )
1437
+ {{/if}}
1438
+ {{#if (eq modelProvider "OpenAI")}}
1439
+ import os
1440
+ from langchain_openai import ChatOpenAI
1441
+ from bedrock_agentcore.identity.auth import requires_api_key
1442
+
1443
+ IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
1444
+ IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
1445
+
1446
+
1447
+ @requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
1448
+ def _agentcore_identity_api_key_provider(api_key: str) -> str:
1449
+ """Fetch API key from AgentCore Identity."""
1450
+ return api_key
1451
+
1452
+
1453
+ def _get_api_key() -> str:
1454
+ """
1455
+ Uses AgentCore Identity for API key management in deployed environments.
1456
+ For local development, run via 'agentcore dev' which loads agentcore/.env.
1457
+ """
1458
+ if os.getenv("LOCAL_DEV") == "1":
1459
+ api_key = os.getenv(IDENTITY_ENV_VAR)
1460
+ if not api_key:
1461
+ raise RuntimeError(
1462
+ f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
1463
+ )
1464
+ return api_key
1465
+ return _agentcore_identity_api_key_provider()
1466
+
1467
+
1468
+ def load_model() -> ChatOpenAI:
1469
+ """Get authenticated OpenAI model client."""
1470
+ return ChatOpenAI(
1471
+ model="gpt-4.1",
1472
+ api_key=_get_api_key()
1473
+ )
1474
+ {{/if}}
1475
+ {{#if (eq modelProvider "Gemini")}}
1476
+ import os
1477
+ from langchain_google_genai import ChatGoogleGenerativeAI
1478
+ from bedrock_agentcore.identity.auth import requires_api_key
1479
+
1480
+ IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
1481
+ IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
1482
+
1483
+
1484
+ @requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
1485
+ def _agentcore_identity_api_key_provider(api_key: str) -> str:
1486
+ """Fetch API key from AgentCore Identity."""
1487
+ return api_key
1488
+
1489
+
1490
+ def _get_api_key() -> str:
1491
+ """
1492
+ Uses AgentCore Identity for API key management in deployed environments.
1493
+ For local development, run via 'agentcore dev' which loads agentcore/.env.
1494
+ """
1495
+ if os.getenv("LOCAL_DEV") == "1":
1496
+ api_key = os.getenv(IDENTITY_ENV_VAR)
1497
+ if not api_key:
1498
+ raise RuntimeError(
1499
+ f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
1500
+ )
1501
+ return api_key
1502
+ return _agentcore_identity_api_key_provider()
1503
+
1504
+
1505
+ def load_model() -> ChatGoogleGenerativeAI:
1506
+ """Get authenticated Gemini model client."""
1507
+ return ChatGoogleGenerativeAI(
1508
+ model="gemini-2.5-flash",
1509
+ api_key=_get_api_key()
1510
+ )
1511
+ {{/if}}
1512
+ "
1513
+ `;
1514
+
1515
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/pyproject.toml should match snapshot 1`] = `
1516
+ "[build-system]
1517
+ requires = ["hatchling"]
1518
+ build-backend = "hatchling.build"
1519
+
1520
+ [project]
1521
+ name = "{{ name }}"
1522
+ version = "0.1.0"
1523
+ description = "AgentCore A2A Agent using LangChain + LangGraph"
1524
+ readme = "README.md"
1525
+ requires-python = ">=3.10"
1526
+ dependencies = [
1527
+ "a2a-sdk >= 0.2.0",
1528
+ {{#if (eq modelProvider "Anthropic")}}"langchain-anthropic >= 0.3.0",
1529
+ {{/if}}{{#if (eq modelProvider "Bedrock")}}"langchain-aws >= 0.2.0",
1530
+ {{/if}}{{#if (eq modelProvider "Gemini")}}"langchain-google-genai >= 2.0.0",
1531
+ {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
1532
+ {{/if}}"aws-opentelemetry-distro",
1533
+ "opentelemetry-instrumentation-langchain >= 0.59.0",
1534
+ "bedrock-agentcore[a2a] >= 1.0.3",
1535
+ "botocore[crt] >= 1.35.0",
1536
+ "langgraph >= 0.2.0",
1537
+ ]
1538
+
1539
+ [tool.hatch.build.targets.wheel]
1540
+ packages = ["."]
1541
+ "
1542
+ `;
1543
+
1544
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/README.md should match snapshot 1`] = `
1545
+ "# {{ name }}
1546
+
1547
+ An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using Strands SDK.
1548
+
1549
+ ## Overview
1550
+
1551
+ This agent implements the A2A protocol, enabling agent-to-agent communication. Other agents can discover and interact with this agent via the \`/.well-known/agent-card.json\` endpoint.
1552
+
1553
+ ## Local Development
1554
+
1555
+ \`\`\`bash
1556
+ uv sync
1557
+ uv run python main.py
1558
+ \`\`\`
1559
+
1560
+ The agent starts on port 9000.
1561
+
1562
+ ## Deploy
1563
+
1564
+ \`\`\`bash
1565
+ agentcore deploy
1566
+ \`\`\`
1567
+ "
1568
+ `;
1569
+
1570
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/gitignore.template should match snapshot 1`] = `
1571
+ "# Environment variables
1572
+ .env
1573
+
1574
+ # Python
1575
+ __pycache__/
1576
+ *.py[cod]
1577
+ *$py.class
1578
+ *.so
1579
+ .Python
1580
+ build/
1581
+ develop-eggs/
1582
+ dist/
1583
+ downloads/
1584
+ eggs/
1585
+ .eggs/
1586
+ lib/
1587
+ lib64/
1588
+ parts/
1589
+ sdist/
1590
+ var/
1591
+ wheels/
1592
+ *.egg-info/
1593
+ .installed.cfg
1594
+ *.egg
1595
+
1596
+ # Virtual environments
1597
+ .venv/
1598
+ venv/
1599
+ ENV/
1600
+ env/
1601
+
1602
+ # IDE
1603
+ .vscode/
1604
+ .idea/
1605
+ *.swp
1606
+ *.swo
1607
+ *~
1608
+
1609
+ # OS
1610
+ .DS_Store
1611
+ Thumbs.db
1612
+ "
1613
+ `;
1614
+
1615
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/main.py should match snapshot 1`] = `
1616
+ "from strands import Agent, tool
1617
+ from strands.multiagent.a2a.executor import StrandsA2AExecutor
1618
+ from bedrock_agentcore.runtime import serve_a2a
1619
+ from model.load import load_model
1620
+ {{#if hasMemory}}
1621
+ from memory.session import get_memory_session_manager
1622
+ {{/if}}
1623
+ {{#if sessionStorageMountPath}}
1624
+ import os
1625
+ {{/if}}
1626
+
1627
+
1628
+ @tool
1629
+ def add_numbers(a: int, b: int) -> int:
1630
+ """Return the sum of two numbers."""
1631
+ return a + b
1632
+
1633
+
1634
+ tools = [add_numbers]
1635
+
1636
+ {{#if sessionStorageMountPath}}
1637
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
1638
+
1639
+ def _safe_resolve(path: str) -> str:
1640
+ """Resolve path safely within the storage boundary."""
1641
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
1642
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
1643
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
1644
+ return resolved
1645
+
1646
+ @tool
1647
+ def file_read(path: str) -> str:
1648
+ """Read a file from persistent storage. The path is relative to the storage root."""
1649
+ try:
1650
+ full_path = _safe_resolve(path)
1651
+ with open(full_path) as f:
1652
+ return f.read()
1653
+ except ValueError as e:
1654
+ return str(e)
1655
+ except OSError as e:
1656
+ return f"Error reading '{path}': {e.strerror}"
1657
+
1658
+ @tool
1659
+ def file_write(path: str, content: str) -> str:
1660
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
1661
+ try:
1662
+ full_path = _safe_resolve(path)
1663
+ parent = os.path.dirname(full_path)
1664
+ if parent:
1665
+ os.makedirs(parent, exist_ok=True)
1666
+ with open(full_path, "w") as f:
1667
+ f.write(content)
1668
+ return f"Written to {path}"
1669
+ except ValueError as e:
1670
+ return str(e)
1671
+ except OSError as e:
1672
+ return f"Error writing '{path}': {e.strerror}"
1673
+
1674
+ @tool
1675
+ def list_files(directory: str = "") -> str:
1676
+ """List files in persistent storage. The directory is relative to the storage root."""
1677
+ try:
1678
+ target = _safe_resolve(directory)
1679
+ entries = os.listdir(target)
1680
+ return "\\n".join(entries) if entries else "(empty directory)"
1681
+ except ValueError as e:
1682
+ return str(e)
1683
+ except OSError as e:
1684
+ return f"Error listing '{directory}': {e.strerror}"
1685
+
1686
+ tools.extend([file_read, file_write, list_files])
1687
+ {{/if}}
1688
+
1689
+ SYSTEM_PROMPT = """
1690
+ You are a helpful assistant. Use tools when appropriate.
1691
+ {{#if sessionStorageMountPath}}
1692
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
1693
+ {{/if}}
1694
+ """
1695
+
1696
+ {{#if hasMemory}}
1697
+ def agent_factory():
1698
+ cache = {}
1699
+ def get_or_create_agent(session_id, user_id):
1700
+ key = f"{session_id}/{user_id}"
1701
+ if key not in cache:
1702
+ cache[key] = Agent(
1703
+ model=load_model(),
1704
+ session_manager=get_memory_session_manager(session_id, user_id),
1705
+ system_prompt=SYSTEM_PROMPT,
1706
+ tools=tools,
1707
+ )
1708
+ return cache[key]
1709
+ return get_or_create_agent
1710
+
1711
+ get_or_create_agent = agent_factory()
1712
+ agent = get_or_create_agent("default-session", "default-user")
1713
+ {{else}}
1714
+ agent = Agent(
1715
+ model=load_model(),
1716
+ system_prompt=SYSTEM_PROMPT,
1717
+ tools=tools,
1718
+ )
1719
+ {{/if}}
1720
+
1721
+ if __name__ == "__main__":
1722
+ serve_a2a(StrandsA2AExecutor(agent))
1723
+ "
1724
+ `;
1725
+
1726
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/model/__init__.py should match snapshot 1`] = `
1727
+ "# Package marker
1728
+ "
1729
+ `;
1730
+
1731
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/model/load.py should match snapshot 1`] = `
1732
+ "{{#if (eq modelProvider "Bedrock")}}
1733
+ from strands.models.bedrock import BedrockModel
1734
+
1735
+
1736
+ def load_model() -> BedrockModel:
1737
+ """Get Bedrock model client using IAM credentials."""
1738
+ return BedrockModel(model_id="global.anthropic.claude-sonnet-4-5-20250929-v1:0")
1739
+ {{/if}}
1740
+ {{#if (eq modelProvider "Anthropic")}}
1741
+ import os
1742
+
1743
+ from strands.models.anthropic import AnthropicModel
1744
+ from bedrock_agentcore.identity.auth import requires_api_key
1745
+
1746
+ IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
1747
+ IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
1748
+
1749
+
1750
+ @requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
1751
+ def _agentcore_identity_api_key_provider(api_key: str) -> str:
1752
+ """Fetch API key from AgentCore Identity."""
1753
+ return api_key
1754
+
1755
+
1756
+ def _get_api_key() -> str:
1757
+ """
1758
+ Uses AgentCore Identity for API key management in deployed environments.
1759
+ For local development, run via 'agentcore dev' which loads agentcore/.env.
1760
+ """
1761
+ if os.getenv("LOCAL_DEV") == "1":
1762
+ api_key = os.getenv(IDENTITY_ENV_VAR)
1763
+ if not api_key:
1764
+ raise RuntimeError(
1765
+ f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
1766
+ )
1767
+ return api_key
1768
+ return _agentcore_identity_api_key_provider()
1769
+
1770
+
1771
+ def load_model() -> AnthropicModel:
1772
+ """Get authenticated Anthropic model client."""
1773
+ return AnthropicModel(
1774
+ client_args={"api_key": _get_api_key()},
1775
+ model_id="claude-sonnet-4-5-20250929",
1776
+ max_tokens=5000,
1777
+ )
1778
+ {{/if}}
1779
+ {{#if (eq modelProvider "OpenAI")}}
1780
+ import os
1781
+
1782
+ from strands.models.openai import OpenAIModel
1783
+ from bedrock_agentcore.identity.auth import requires_api_key
1784
+
1785
+ IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
1786
+ IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
1787
+
1788
+
1789
+ @requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
1790
+ def _agentcore_identity_api_key_provider(api_key: str) -> str:
1791
+ """Fetch API key from AgentCore Identity."""
1792
+ return api_key
1793
+
1794
+
1795
+ def _get_api_key() -> str:
1796
+ """
1797
+ Uses AgentCore Identity for API key management in deployed environments.
1798
+ For local development, run via 'agentcore dev' which loads agentcore/.env.
1799
+ """
1800
+ if os.getenv("LOCAL_DEV") == "1":
1801
+ api_key = os.getenv(IDENTITY_ENV_VAR)
1802
+ if not api_key:
1803
+ raise RuntimeError(
1804
+ f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
1805
+ )
1806
+ return api_key
1807
+ return _agentcore_identity_api_key_provider()
1808
+
1809
+
1810
+ def load_model() -> OpenAIModel:
1811
+ """Get authenticated OpenAI model client."""
1812
+ return OpenAIModel(
1813
+ client_args={"api_key": _get_api_key()},
1814
+ model_id="gpt-4.1",
1815
+ )
1816
+ {{/if}}
1817
+ {{#if (eq modelProvider "Gemini")}}
1818
+ import os
1819
+
1820
+ from strands.models.gemini import GeminiModel
1821
+ from bedrock_agentcore.identity.auth import requires_api_key
1822
+
1823
+ IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}"
1824
+ IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}"
1825
+
1826
+
1827
+ @requires_api_key(provider_name=IDENTITY_PROVIDER_NAME)
1828
+ def _agentcore_identity_api_key_provider(api_key: str) -> str:
1829
+ """Fetch API key from AgentCore Identity."""
1830
+ return api_key
1831
+
1832
+
1833
+ def _get_api_key() -> str:
1834
+ """
1835
+ Uses AgentCore Identity for API key management in deployed environments.
1836
+ For local development, run via 'agentcore dev' which loads agentcore/.env.
1837
+ """
1838
+ if os.getenv("LOCAL_DEV") == "1":
1839
+ api_key = os.getenv(IDENTITY_ENV_VAR)
1840
+ if not api_key:
1841
+ raise RuntimeError(
1842
+ f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local"
1843
+ )
1844
+ return api_key
1845
+ return _agentcore_identity_api_key_provider()
1846
+
1847
+
1848
+ def load_model() -> GeminiModel:
1849
+ """Get authenticated Gemini model client."""
1850
+ return GeminiModel(
1851
+ client_args={"api_key": _get_api_key()},
1852
+ model_id="gemini-2.5-flash",
1853
+ )
1854
+ {{/if}}
1855
+ "
1856
+ `;
1857
+
1858
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/pyproject.toml should match snapshot 1`] = `
1859
+ "[build-system]
1860
+ requires = ["hatchling"]
1861
+ build-backend = "hatchling.build"
1862
+
1863
+ [project]
1864
+ name = "{{ name }}"
1865
+ version = "0.1.0"
1866
+ description = "AgentCore A2A Agent using Strands SDK"
1867
+ readme = "README.md"
1868
+ requires-python = ">=3.10"
1869
+ dependencies = [
1870
+ {{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0",
1871
+ {{/if}}"a2a-sdk[all] >= 0.2.0",
1872
+ "aws-opentelemetry-distro",
1873
+ "bedrock-agentcore[a2a] >= 1.0.3",
1874
+ "botocore[crt] >= 1.35.0",
1875
+ {{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0",
1876
+ {{/if}}{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0",
1877
+ {{/if}}"strands-agents >= 1.13.0",
1878
+ ]
1879
+
1880
+ [tool.hatch.build.targets.wheel]
1881
+ packages = ["."]
1882
+ "
1883
+ `;
1884
+
1885
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/capabilities/memory/__init__.py should match snapshot 1`] = `
1886
+ "# Package marker
1887
+ "
1888
+ `;
1889
+
1890
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/capabilities/memory/session.py should match snapshot 1`] = `
1891
+ "import os
1892
+ from typing import Optional
1893
+
1894
+ from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig{{#if memoryProviders.[0].strategies.length}}, RetrievalConfig{{/if}}
1895
+ from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager
1896
+
1897
+ MEMORY_ID = os.getenv("{{memoryProviders.[0].envVarName}}")
1898
+ REGION = os.getenv("AWS_REGION")
1899
+
1900
+ def get_memory_session_manager(session_id: str, actor_id: str) -> Optional[AgentCoreMemorySessionManager]:
1901
+ if not MEMORY_ID:
1902
+ return None
1903
+
1904
+ {{#if memoryProviders.[0].strategies.length}}
1905
+ retrieval_config = {
1906
+ {{#if (includes memoryProviders.[0].strategies "SEMANTIC")}}
1907
+ f"/users/{actor_id}/facts": RetrievalConfig(top_k=3, relevance_score=0.5),
1908
+ {{/if}}
1909
+ {{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}}
1910
+ f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5),
1911
+ {{/if}}
1912
+ {{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}}
1913
+ f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
1914
+ {{/if}}
1915
+ }
1916
+ {{/if}}
1917
+
1918
+ return AgentCoreMemorySessionManager(
1919
+ AgentCoreMemoryConfig(
1920
+ memory_id=MEMORY_ID,
1921
+ session_id=session_id,
1922
+ actor_id=actor_id,
1923
+ {{#if memoryProviders.[0].strategies.length}}
1924
+ retrieval_config=retrieval_config,
1925
+ {{/if}}
1926
+ ),
1927
+ REGION
1928
+ )
1929
+ "
1930
+ `;
1931
+
1932
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/README.md should match snapshot 1`] = `
1933
+ "# {{ name }}
1934
+
1935
+ An AG-UI agent deployed on Amazon Bedrock AgentCore using Google ADK.
1936
+
1937
+ ## Overview
1938
+
1939
+ This agent implements the AG-UI protocol using Google's Agent Development Kit, enabling rich agent-user interaction via the AG-UI event stream.
1940
+
1941
+ ## Local Development
1942
+
1943
+ \`\`\`bash
1944
+ uv sync
1945
+ uv run python main.py
1946
+ \`\`\`
1947
+
1948
+ The agent starts on port 8080 and serves requests at \`/invocations\`.
1949
+
1950
+ ## Health Check
1951
+
1952
+ \`\`\`
1953
+ GET /ping
1954
+ \`\`\`
1955
+
1956
+ Returns \`{"status": "healthy"}\`.
1957
+
1958
+ ## Deploy
1959
+
1960
+ \`\`\`bash
1961
+ agentcore deploy
1962
+ \`\`\`
1963
+ "
1964
+ `;
1965
+
1966
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/gitignore.template should match snapshot 1`] = `
1967
+ "# Environment variables
1968
+ .env
1969
+
1970
+ # Python
1971
+ __pycache__/
1972
+ *.py[cod]
1973
+ *$py.class
1974
+ *.so
1975
+ .Python
1976
+ build/
1977
+ develop-eggs/
1978
+ dist/
1979
+ downloads/
1980
+ eggs/
1981
+ .eggs/
1982
+ lib/
1983
+ lib64/
1984
+ parts/
1985
+ sdist/
1986
+ var/
1987
+ wheels/
1988
+ *.egg-info/
1989
+ .installed.cfg
1990
+ *.egg
1991
+
1992
+ # Virtual environments
1993
+ .venv/
1994
+ venv/
1995
+ ENV/
1996
+ env/
1997
+
1998
+ # IDE
1999
+ .vscode/
2000
+ .idea/
2001
+ *.swp
2002
+ *.swo
2003
+ *~
979
2004
 
980
- def add_numbers(a: int, b: int) -> int:
981
- """Return the sum of two numbers."""
982
- return a + b
2005
+ # OS
2006
+ .DS_Store
2007
+ Thumbs.db
2008
+ "
2009
+ `;
2010
+
2011
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/main.py should match snapshot 1`] = `
2012
+ "import os
2013
+ import uvicorn
2014
+ from google.adk.agents import LlmAgent
2015
+ from ag_ui_adk import ADKAgent, AGUIToolset, create_adk_app
2016
+ from model.load import load_model
983
2017
 
2018
+ load_model()
984
2019
 
985
- agent = Agent(
986
- model=load_model(),
2020
+ agent = LlmAgent(
987
2021
  name="{{ name }}",
988
- description="A helpful assistant that can use tools.",
989
- instruction="You are a helpful assistant. Use tools when appropriate.",
990
- tools=[add_numbers],
2022
+ model="gemini-2.5-flash",
2023
+ instruction="You are a helpful assistant.",
2024
+ tools=[AGUIToolset()],
991
2025
  )
992
2026
 
993
- runner = Runner(
994
- app_name=agent.name,
995
- agent=agent,
996
- session_service=InMemorySessionService(),
2027
+ adk_agent = ADKAgent(
2028
+ adk_agent=agent,
2029
+ app_name="{{ name }}",
2030
+ use_in_memory_services=True,
997
2031
  )
998
2032
 
999
- card = AgentCard(
1000
- name=agent.name,
1001
- description=agent.description,
1002
- url="http://localhost:9000/",
1003
- version="0.1.0",
1004
- capabilities=AgentCapabilities(streaming=True),
1005
- skills=[
1006
- AgentSkill(
1007
- id="tools",
1008
- name="tools",
1009
- description="Use tools to help answer questions",
1010
- tags=["tools"],
1011
- )
1012
- ],
1013
- default_input_modes=["text"],
1014
- default_output_modes=["text"],
1015
- )
2033
+ app = create_adk_app(adk_agent, path="/invocations")
2034
+
2035
+
2036
+ @app.get("/ping")
2037
+ async def ping():
2038
+ return {"status": "healthy"}
2039
+
1016
2040
 
1017
2041
  if __name__ == "__main__":
1018
- serve_a2a(A2aAgentExecutor(runner=runner), card)
2042
+ uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080")))
1019
2043
  "
1020
2044
  `;
1021
2045
 
1022
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/model/__init__.py should match snapshot 1`] = `
2046
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/model/__init__.py should match snapshot 1`] = `
1023
2047
  "# Package marker
1024
2048
  "
1025
2049
  `;
1026
2050
 
1027
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/model/load.py should match snapshot 1`] = `
2051
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/model/load.py should match snapshot 1`] = `
1028
2052
  "import os
1029
2053
  from bedrock_agentcore.identity.auth import requires_api_key
1030
2054
 
@@ -1069,7 +2093,7 @@ def load_model() -> None:
1069
2093
  "
1070
2094
  `;
1071
2095
 
1072
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/pyproject.toml should match snapshot 1`] = `
2096
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/pyproject.toml should match snapshot 1`] = `
1073
2097
  "[build-system]
1074
2098
  requires = ["hatchling"]
1075
2099
  build-backend = "hatchling.build"
@@ -1077,15 +2101,19 @@ build-backend = "hatchling.build"
1077
2101
  [project]
1078
2102
  name = "{{ name }}"
1079
2103
  version = "0.1.0"
1080
- description = "AgentCore A2A Agent using Google ADK"
2104
+ description = "AgentCore AG-UI Agent using Google ADK"
1081
2105
  readme = "README.md"
1082
2106
  requires-python = ">=3.10"
1083
2107
  dependencies = [
1084
- "a2a-sdk >= 0.2.0",
1085
- "aws-opentelemetry-distro",
1086
- "bedrock-agentcore[a2a] >= 1.0.3",
1087
- "google-adk >= 1.0.0",
2108
+ "ag-ui-adk >= 0.6.0",
2109
+ "ag-ui-protocol >= 0.1.10",
2110
+ "bedrock-agentcore >= 1.0.3",
2111
+ "fastapi >= 0.115.12",
2112
+ "google-adk >= 1.16.0",
1088
2113
  "google-genai >= 1.0.0",
2114
+ "opentelemetry-distro",
2115
+ "opentelemetry-exporter-otlp",
2116
+ "uvicorn >= 0.34.3",
1089
2117
  ]
1090
2118
 
1091
2119
  [tool.hatch.build.targets.wheel]
@@ -1093,14 +2121,14 @@ packages = ["."]
1093
2121
  "
1094
2122
  `;
1095
2123
 
1096
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/README.md should match snapshot 1`] = `
2124
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/README.md should match snapshot 1`] = `
1097
2125
  "# {{ name }}
1098
2126
 
1099
- An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using LangChain + LangGraph.
2127
+ An AG-UI agent deployed on Amazon Bedrock AgentCore using LangChain + LangGraph.
1100
2128
 
1101
2129
  ## Overview
1102
2130
 
1103
- This agent implements the A2A protocol using LangGraph, enabling agent-to-agent communication.
2131
+ This agent implements the AG-UI protocol using LangGraph, enabling seamless frontend-to-agent communication with support for streaming, tool calls, and frontend-injected tools.
1104
2132
 
1105
2133
  ## Local Development
1106
2134
 
@@ -1109,7 +2137,7 @@ uv sync
1109
2137
  uv run python main.py
1110
2138
  \`\`\`
1111
2139
 
1112
- The agent starts on port 9000.
2140
+ The agent starts on port 8080.
1113
2141
 
1114
2142
  ## Deploy
1115
2143
 
@@ -1119,7 +2147,7 @@ agentcore deploy
1119
2147
  "
1120
2148
  `;
1121
2149
 
1122
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/gitignore.template should match snapshot 1`] = `
2150
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/gitignore.template should match snapshot 1`] = `
1123
2151
  "# Environment variables
1124
2152
  .env
1125
2153
 
@@ -1164,16 +2192,22 @@ Thumbs.db
1164
2192
  "
1165
2193
  `;
1166
2194
 
1167
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/main.py should match snapshot 1`] = `
1168
- "from langchain_core.tools import tool
1169
- from langgraph.prebuilt import create_react_agent
2195
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/main.py should match snapshot 1`] = `
2196
+ "import os
2197
+
2198
+ os.environ["LANGGRAPH_FAST_API"] = "true"
2199
+
2200
+ import uvicorn
2201
+ from typing import Any, List
2202
+ from fastapi import FastAPI
2203
+ from fastapi.middleware.cors import CORSMiddleware
2204
+ from langgraph.graph import StateGraph, START
2205
+ from langgraph.graph.message import MessagesState
2206
+ from langgraph.checkpoint.memory import MemorySaver
2207
+ from langgraph.prebuilt import ToolNode, tools_condition
2208
+ from langchain_core.tools import tool
1170
2209
  from opentelemetry.instrumentation.langchain import LangchainInstrumentor
1171
- from a2a.server.agent_execution import AgentExecutor, RequestContext
1172
- from a2a.server.events import EventQueue
1173
- from a2a.server.tasks import TaskUpdater
1174
- from a2a.types import AgentCapabilities, AgentCard, AgentSkill, Part, TextPart
1175
- from a2a.utils import new_task
1176
- from bedrock_agentcore.runtime import serve_a2a
2210
+ from ag_ui_langgraph import LangGraphAgent, add_langgraph_fastapi_endpoint
1177
2211
  from model.load import load_model
1178
2212
 
1179
2213
  LangchainInstrumentor().instrument()
@@ -1185,62 +2219,63 @@ def add_numbers(a: int, b: int) -> int:
1185
2219
  return a + b
1186
2220
 
1187
2221
 
2222
+ backend_tools = [add_numbers]
1188
2223
  model = load_model()
1189
- graph = create_react_agent(model, tools=[add_numbers])
1190
2224
 
1191
2225
 
1192
- class LangGraphA2AExecutor(AgentExecutor):
1193
- """Wraps a LangGraph CompiledGraph as an a2a-sdk AgentExecutor."""
1194
-
1195
- def __init__(self, graph):
1196
- self.graph = graph
1197
-
1198
- async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
1199
- task = context.current_task or new_task(context.message)
1200
- if not context.current_task:
1201
- await event_queue.enqueue_event(task)
1202
- updater = TaskUpdater(event_queue, task.id, task.context_id)
2226
+ class AgentState(MessagesState):
2227
+ tools: List[Any]
1203
2228
 
1204
- user_text = context.get_user_input()
1205
- result = await self.graph.ainvoke({"messages": [("user", user_text)]})
1206
- response = result["messages"][-1].content
1207
2229
 
1208
- await updater.add_artifact([Part(root=TextPart(text=response))])
1209
- await updater.complete()
2230
+ def chat_node(state: AgentState):
2231
+ bound_model = model.bind_tools(
2232
+ [*state.get("tools", []), *backend_tools],
2233
+ )
2234
+ response = bound_model.invoke(state["messages"])
2235
+ return {"messages": [response]}
1210
2236
 
1211
- async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
1212
- pass
1213
2237
 
2238
+ builder = StateGraph(AgentState)
2239
+ builder.add_node("chat", chat_node)
2240
+ builder.add_node("tools", ToolNode(tools=backend_tools))
2241
+ builder.add_edge(START, "chat")
2242
+ builder.add_conditional_edges("chat", tools_condition)
2243
+ builder.add_edge("tools", "chat")
2244
+ graph = builder.compile(checkpointer=MemorySaver())
1214
2245
 
1215
- card = AgentCard(
2246
+ agent = LangGraphAgent(
1216
2247
  name="{{ name }}",
1217
- description="A LangGraph agent on Bedrock AgentCore",
1218
- url="http://localhost:9000/",
1219
- version="0.1.0",
1220
- capabilities=AgentCapabilities(streaming=True),
1221
- skills=[
1222
- AgentSkill(
1223
- id="tools",
1224
- name="tools",
1225
- description="Use tools to help answer questions",
1226
- tags=["tools"],
1227
- )
1228
- ],
1229
- default_input_modes=["text"],
1230
- default_output_modes=["text"],
2248
+ graph=graph,
2249
+ description="A helpful assistant",
2250
+ )
2251
+
2252
+ app = FastAPI()
2253
+ app.add_middleware(
2254
+ CORSMiddleware,
2255
+ allow_origins=["*"],
2256
+ allow_methods=["*"],
2257
+ allow_headers=["*"],
1231
2258
  )
1232
2259
 
2260
+ add_langgraph_fastapi_endpoint(app=app, agent=agent, path="/invocations")
2261
+
2262
+
2263
+ @app.get("/ping")
2264
+ async def ping():
2265
+ return {"status": "healthy"}
2266
+
2267
+
1233
2268
  if __name__ == "__main__":
1234
- serve_a2a(LangGraphA2AExecutor(graph), card)
2269
+ uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080")))
1235
2270
  "
1236
2271
  `;
1237
2272
 
1238
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/model/__init__.py should match snapshot 1`] = `
2273
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/model/__init__.py should match snapshot 1`] = `
1239
2274
  "# Package marker
1240
2275
  "
1241
2276
  `;
1242
2277
 
1243
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/model/load.py should match snapshot 1`] = `
2278
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/model/load.py should match snapshot 1`] = `
1244
2279
  "{{#if (eq modelProvider "Bedrock")}}
1245
2280
  from langchain_aws import ChatBedrock
1246
2281
 
@@ -1367,7 +2402,7 @@ def load_model() -> ChatGoogleGenerativeAI:
1367
2402
  "
1368
2403
  `;
1369
2404
 
1370
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/pyproject.toml should match snapshot 1`] = `
2405
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/pyproject.toml should match snapshot 1`] = `
1371
2406
  "[build-system]
1372
2407
  requires = ["hatchling"]
1373
2408
  build-backend = "hatchling.build"
@@ -1375,20 +2410,25 @@ build-backend = "hatchling.build"
1375
2410
  [project]
1376
2411
  name = "{{ name }}"
1377
2412
  version = "0.1.0"
1378
- description = "AgentCore A2A Agent using LangChain + LangGraph"
2413
+ description = "AgentCore AG-UI Agent using LangChain + LangGraph"
1379
2414
  readme = "README.md"
1380
2415
  requires-python = ">=3.10"
1381
2416
  dependencies = [
1382
- "a2a-sdk >= 0.2.0",
2417
+ "ag-ui-langgraph >= 0.0.31",
2418
+ "ag-ui-protocol >= 0.1.10",
1383
2419
  {{#if (eq modelProvider "Anthropic")}}"langchain-anthropic >= 0.3.0",
1384
2420
  {{/if}}{{#if (eq modelProvider "Bedrock")}}"langchain-aws >= 0.2.0",
1385
2421
  {{/if}}{{#if (eq modelProvider "Gemini")}}"langchain-google-genai >= 2.0.0",
1386
2422
  {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
1387
2423
  {{/if}}"aws-opentelemetry-distro",
1388
2424
  "opentelemetry-instrumentation-langchain >= 0.59.0",
1389
- "bedrock-agentcore[a2a] >= 1.0.3",
2425
+ "bedrock-agentcore >= 1.0.3",
1390
2426
  "botocore[crt] >= 1.35.0",
1391
- "langgraph >= 0.2.0",
2427
+ "langgraph >= 0.3.25",
2428
+ "langchain >= 0.3.0",
2429
+ "langchain-core >= 0.3.0",
2430
+ "fastapi >= 0.115.12",
2431
+ "uvicorn >= 0.34.3",
1392
2432
  ]
1393
2433
 
1394
2434
  [tool.hatch.build.targets.wheel]
@@ -1396,14 +2436,14 @@ packages = ["."]
1396
2436
  "
1397
2437
  `;
1398
2438
 
1399
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/README.md should match snapshot 1`] = `
2439
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/README.md should match snapshot 1`] = `
1400
2440
  "# {{ name }}
1401
2441
 
1402
- An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using Strands SDK.
2442
+ An AG-UI agent deployed on Amazon Bedrock AgentCore using Strands SDK.
1403
2443
 
1404
2444
  ## Overview
1405
2445
 
1406
- This agent implements the A2A protocol, enabling agent-to-agent communication. Other agents can discover and interact with this agent via the \`/.well-known/agent-card.json\` endpoint.
2446
+ This agent implements the AG-UI protocol, enabling streaming agent-to-UI communication. The agent exposes an \`/invocations\` endpoint that accepts AG-UI protocol requests and streams responses back to the client.
1407
2447
 
1408
2448
  ## Local Development
1409
2449
 
@@ -1412,7 +2452,7 @@ uv sync
1412
2452
  uv run python main.py
1413
2453
  \`\`\`
1414
2454
 
1415
- The agent starts on port 9000.
2455
+ The agent starts on port 8080.
1416
2456
 
1417
2457
  ## Deploy
1418
2458
 
@@ -1422,7 +2462,7 @@ agentcore deploy
1422
2462
  "
1423
2463
  `;
1424
2464
 
1425
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/gitignore.template should match snapshot 1`] = `
2465
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/gitignore.template should match snapshot 1`] = `
1426
2466
  "# Environment variables
1427
2467
  .env
1428
2468
 
@@ -1467,10 +2507,16 @@ Thumbs.db
1467
2507
  "
1468
2508
  `;
1469
2509
 
1470
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/main.py should match snapshot 1`] = `
1471
- "from strands import Agent, tool
1472
- from strands.multiagent.a2a.executor import StrandsA2AExecutor
1473
- from bedrock_agentcore.runtime import serve_a2a
2510
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/main.py should match snapshot 1`] = `
2511
+ "import os
2512
+
2513
+ # Suppress OpenTelemetry warnings during local development; remove for production
2514
+ if os.getenv("LOCAL_DEV") == "1":
2515
+ os.environ["OTEL_SDK_DISABLED"] = "true"
2516
+
2517
+ import uvicorn
2518
+ from strands import Agent, tool
2519
+ from ag_ui_strands import StrandsAgent, StrandsAgentConfig, create_strands_app
1474
2520
  from model.load import load_model
1475
2521
  {{#if hasMemory}}
1476
2522
  from memory.session import get_memory_session_manager
@@ -1485,42 +2531,35 @@ def add_numbers(a: int, b: int) -> int:
1485
2531
 
1486
2532
  tools = [add_numbers]
1487
2533
 
1488
- {{#if hasMemory}}
1489
- def agent_factory():
1490
- cache = {}
1491
- def get_or_create_agent(session_id, user_id):
1492
- key = f"{session_id}/{user_id}"
1493
- if key not in cache:
1494
- cache[key] = Agent(
1495
- model=load_model(),
1496
- session_manager=get_memory_session_manager(session_id, user_id),
1497
- system_prompt="You are a helpful assistant. Use tools when appropriate.",
1498
- tools=tools,
1499
- )
1500
- return cache[key]
1501
- return get_or_create_agent
1502
-
1503
- get_or_create_agent = agent_factory()
1504
- agent = get_or_create_agent("default-session", "default-user")
1505
- {{else}}
1506
2534
  agent = Agent(
1507
2535
  model=load_model(),
1508
2536
  system_prompt="You are a helpful assistant. Use tools when appropriate.",
1509
2537
  tools=tools,
1510
2538
  )
2539
+
2540
+ {{#if hasMemory}}
2541
+ def session_manager_provider(input_data):
2542
+ return get_memory_session_manager(input_data.thread_id, "default-user")
2543
+
2544
+ config = StrandsAgentConfig(session_manager_provider=session_manager_provider)
2545
+ {{else}}
2546
+ config = StrandsAgentConfig()
1511
2547
  {{/if}}
1512
2548
 
2549
+ agui_agent = StrandsAgent(agent=agent, name="{{ name }}", description="A helpful assistant", config=config)
2550
+ app = create_strands_app(agui_agent, path="/invocations", ping_path="/ping")
2551
+
1513
2552
  if __name__ == "__main__":
1514
- serve_a2a(StrandsA2AExecutor(agent))
2553
+ uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8080")))
1515
2554
  "
1516
2555
  `;
1517
2556
 
1518
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/model/__init__.py should match snapshot 1`] = `
2557
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/model/__init__.py should match snapshot 1`] = `
1519
2558
  "# Package marker
1520
2559
  "
1521
2560
  `;
1522
2561
 
1523
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/model/load.py should match snapshot 1`] = `
2562
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/model/load.py should match snapshot 1`] = `
1524
2563
  "{{#if (eq modelProvider "Bedrock")}}
1525
2564
  from strands.models.bedrock import BedrockModel
1526
2565
 
@@ -1647,7 +2686,7 @@ def load_model() -> GeminiModel:
1647
2686
  "
1648
2687
  `;
1649
2688
 
1650
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/pyproject.toml should match snapshot 1`] = `
2689
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/pyproject.toml should match snapshot 1`] = `
1651
2690
  "[build-system]
1652
2691
  requires = ["hatchling"]
1653
2692
  build-backend = "hatchling.build"
@@ -1655,18 +2694,22 @@ build-backend = "hatchling.build"
1655
2694
  [project]
1656
2695
  name = "{{ name }}"
1657
2696
  version = "0.1.0"
1658
- description = "AgentCore A2A Agent using Strands SDK"
2697
+ description = "AgentCore AG-UI Agent using Strands SDK"
1659
2698
  readme = "README.md"
1660
- requires-python = ">=3.10"
2699
+ requires-python = ">=3.12"
1661
2700
  dependencies = [
1662
2701
  {{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0",
1663
- {{/if}}"a2a-sdk[all] >= 0.2.0",
2702
+ {{/if}}"ag-ui-strands >= 0.1.7",
2703
+ "ag-ui-protocol >= 0.1.10",
1664
2704
  "aws-opentelemetry-distro",
1665
- "bedrock-agentcore[a2a] >= 1.0.3",
2705
+ "bedrock-agentcore >= 1.0.3",
1666
2706
  "botocore[crt] >= 1.35.0",
2707
+ "fastapi >= 0.115.12",
1667
2708
  {{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0",
1668
2709
  {{/if}}{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0",
1669
- {{/if}}"strands-agents >= 1.13.0",
2710
+ {{/if}}"strands-agents >= 1.15.0",
2711
+ "strands-agents-tools >= 0.2.14",
2712
+ "uvicorn >= 0.34.3",
1670
2713
  ]
1671
2714
 
1672
2715
  [tool.hatch.build.targets.wheel]
@@ -1674,12 +2717,12 @@ packages = ["."]
1674
2717
  "
1675
2718
  `;
1676
2719
 
1677
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/capabilities/memory/__init__.py should match snapshot 1`] = `
2720
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/capabilities/memory/__init__.py should match snapshot 1`] = `
1678
2721
  "# Package marker
1679
2722
  "
1680
2723
  `;
1681
2724
 
1682
- exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/capabilities/memory/session.py should match snapshot 1`] = `
2725
+ exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/capabilities/memory/session.py should match snapshot 1`] = `
1683
2726
  "import os
1684
2727
  from typing import Optional
1685
2728
 
@@ -1834,6 +2877,66 @@ add_numbers_tool = FunctionTool(
1834
2877
  # Define a collection of tools used by the model
1835
2878
  tools = [add_numbers_tool]
1836
2879
 
2880
+ {{#if sessionStorageMountPath}}
2881
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
2882
+
2883
+ def _safe_resolve(path: str) -> str:
2884
+ """Resolve path safely within the storage boundary."""
2885
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
2886
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
2887
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
2888
+ return resolved
2889
+
2890
+ def file_read(path: str) -> str:
2891
+ """Read a file from persistent storage. The path is relative to the storage root."""
2892
+ try:
2893
+ full_path = _safe_resolve(path)
2894
+ with open(full_path) as f:
2895
+ return f.read()
2896
+ except ValueError as e:
2897
+ return str(e)
2898
+ except OSError as e:
2899
+ return f"Error reading '{path}': {e.strerror}"
2900
+
2901
+ def file_write(path: str, content: str) -> str:
2902
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
2903
+ try:
2904
+ full_path = _safe_resolve(path)
2905
+ parent = os.path.dirname(full_path)
2906
+ if parent:
2907
+ os.makedirs(parent, exist_ok=True)
2908
+ with open(full_path, "w") as f:
2909
+ f.write(content)
2910
+ return f"Written to {path}"
2911
+ except ValueError as e:
2912
+ return str(e)
2913
+ except OSError as e:
2914
+ return f"Error writing '{path}': {e.strerror}"
2915
+
2916
+ def list_files(directory: str = "") -> str:
2917
+ """List files in persistent storage. The directory is relative to the storage root."""
2918
+ try:
2919
+ target = _safe_resolve(directory)
2920
+ entries = os.listdir(target)
2921
+ return "\\n".join(entries) if entries else "(empty directory)"
2922
+ except ValueError as e:
2923
+ return str(e)
2924
+ except OSError as e:
2925
+ return f"Error listing '{directory}': {e.strerror}"
2926
+
2927
+ tools.extend([
2928
+ FunctionTool(file_read, description="Read a file from persistent storage. The path is relative to the storage root."),
2929
+ FunctionTool(file_write, description="Write content to a file in persistent storage. The path is relative to the storage root."),
2930
+ FunctionTool(list_files, description="List files in persistent storage. The directory is relative to the storage root."),
2931
+ ])
2932
+ {{/if}}
2933
+
2934
+ SYSTEM_MESSAGE = """
2935
+ You are a helpful assistant. Use tools when appropriate.
2936
+ {{#if sessionStorageMountPath}}
2937
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
2938
+ {{/if}}
2939
+ """
1837
2940
 
1838
2941
  @app.entrypoint
1839
2942
  async def invoke(payload, context):
@@ -1847,7 +2950,7 @@ async def invoke(payload, context):
1847
2950
  name="{{ name }}",
1848
2951
  model_client=load_model(),
1849
2952
  tools=tools + mcp_tools,
1850
- system_message="You are a helpful assistant. Use tools when appropriate.",
2953
+ system_message=SYSTEM_MESSAGE,
1851
2954
  )
1852
2955
 
1853
2956
  # Process the user prompt
@@ -2202,6 +3305,66 @@ def add_numbers(a: int, b: int) -> int:
2202
3305
  return a + b
2203
3306
 
2204
3307
 
3308
+ # Define a collection of tools used by the model
3309
+ tools = [add_numbers]
3310
+
3311
+ {{#if sessionStorageMountPath}}
3312
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
3313
+
3314
+ def _safe_resolve(path: str) -> str:
3315
+ """Resolve path safely within the storage boundary."""
3316
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
3317
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
3318
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
3319
+ return resolved
3320
+
3321
+ def file_read(path: str) -> str:
3322
+ """Read a file from persistent storage. The path is relative to the storage root."""
3323
+ try:
3324
+ full_path = _safe_resolve(path)
3325
+ with open(full_path) as f:
3326
+ return f.read()
3327
+ except ValueError as e:
3328
+ return str(e)
3329
+ except OSError as e:
3330
+ return f"Error reading '{path}': {e.strerror}"
3331
+
3332
+ def file_write(path: str, content: str) -> str:
3333
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
3334
+ try:
3335
+ full_path = _safe_resolve(path)
3336
+ parent = os.path.dirname(full_path)
3337
+ if parent:
3338
+ os.makedirs(parent, exist_ok=True)
3339
+ with open(full_path, "w") as f:
3340
+ f.write(content)
3341
+ return f"Written to {path}"
3342
+ except ValueError as e:
3343
+ return str(e)
3344
+ except OSError as e:
3345
+ return f"Error writing '{path}': {e.strerror}"
3346
+
3347
+ def list_files(directory: str = "") -> str:
3348
+ """List files in persistent storage. The directory is relative to the storage root."""
3349
+ try:
3350
+ target = _safe_resolve(directory)
3351
+ entries = os.listdir(target)
3352
+ return "\\n".join(entries) if entries else "(empty directory)"
3353
+ except ValueError as e:
3354
+ return str(e)
3355
+ except OSError as e:
3356
+ return f"Error listing '{directory}': {e.strerror}"
3357
+
3358
+ tools.extend([file_read, file_write, list_files])
3359
+ {{/if}}
3360
+
3361
+ AGENT_INSTRUCTION = """
3362
+ I can answer your questions using the knowledge I have!
3363
+ {{#if sessionStorageMountPath}}
3364
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
3365
+ {{/if}}
3366
+ """
3367
+
2205
3368
  # Get MCP Toolset
2206
3369
  {{#if hasGateway}}
2207
3370
  mcp_toolset = get_all_gateway_mcp_toolsets()
@@ -2224,8 +3387,8 @@ agent = Agent(
2224
3387
  model=MODEL_ID,
2225
3388
  name="{{ name }}",
2226
3389
  description="Agent to answer questions",
2227
- instruction="I can answer your questions using the knowledge I have!",
2228
- tools=mcp_toolset + [add_numbers],
3390
+ instruction=AGENT_INSTRUCTION,
3391
+ tools=mcp_toolset + tools,
2229
3392
  )
2230
3393
 
2231
3394
 
@@ -2563,6 +3726,66 @@ def add_numbers(a: int, b: int) -> int:
2563
3726
  # Define a collection of tools used by the model
2564
3727
  tools = [add_numbers]
2565
3728
 
3729
+ {{#if sessionStorageMountPath}}
3730
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
3731
+
3732
+ def _safe_resolve(path: str) -> str:
3733
+ """Resolve path safely within the storage boundary."""
3734
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
3735
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
3736
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
3737
+ return resolved
3738
+
3739
+ @tool
3740
+ def file_read(path: str) -> str:
3741
+ """Read a file from persistent storage. The path is relative to the storage root."""
3742
+ try:
3743
+ full_path = _safe_resolve(path)
3744
+ with open(full_path) as f:
3745
+ return f.read()
3746
+ except ValueError as e:
3747
+ return str(e)
3748
+ except OSError as e:
3749
+ return f"Error reading '{path}': {e.strerror}"
3750
+
3751
+ @tool
3752
+ def file_write(path: str, content: str) -> str:
3753
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
3754
+ try:
3755
+ full_path = _safe_resolve(path)
3756
+ parent = os.path.dirname(full_path)
3757
+ if parent:
3758
+ os.makedirs(parent, exist_ok=True)
3759
+ with open(full_path, "w") as f:
3760
+ f.write(content)
3761
+ return f"Written to {path}"
3762
+ except ValueError as e:
3763
+ return str(e)
3764
+ except OSError as e:
3765
+ return f"Error writing '{path}': {e.strerror}"
3766
+
3767
+ @tool
3768
+ def list_files(directory: str = "") -> str:
3769
+ """List files in persistent storage. The directory is relative to the storage root."""
3770
+ try:
3771
+ target = _safe_resolve(directory)
3772
+ entries = os.listdir(target)
3773
+ return "\\n".join(entries) if entries else "(empty directory)"
3774
+ except ValueError as e:
3775
+ return str(e)
3776
+ except OSError as e:
3777
+ return f"Error listing '{directory}': {e.strerror}"
3778
+
3779
+ tools.extend([file_read, file_write, list_files])
3780
+ {{/if}}
3781
+
3782
+ SYSTEM_PROMPT = """
3783
+ You are a helpful assistant. Use tools when appropriate.
3784
+ {{#if sessionStorageMountPath}}
3785
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
3786
+ {{/if}}
3787
+ """
3788
+
2566
3789
 
2567
3790
  @app.entrypoint
2568
3791
  async def invoke(payload, context):
@@ -2581,7 +3804,7 @@ async def invoke(payload, context):
2581
3804
  mcp_tools = await mcp_client.get_tools()
2582
3805
 
2583
3806
  # Define the agent using create_react_agent
2584
- graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools)
3807
+ graph = create_react_agent(get_or_create_model(), tools=mcp_tools + tools, prompt=SYSTEM_PROMPT)
2585
3808
 
2586
3809
  # Process the user prompt
2587
3810
  prompt = payload.get("prompt", "What can you help me with?")
@@ -2986,6 +4209,68 @@ def add_numbers(a: int, b: int) -> int:
2986
4209
  return a + b
2987
4210
 
2988
4211
 
4212
+ tools = [add_numbers]
4213
+
4214
+ {{#if sessionStorageMountPath}}
4215
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
4216
+
4217
+ def _safe_resolve(path: str) -> str:
4218
+ """Resolve path safely within the storage boundary."""
4219
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
4220
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
4221
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
4222
+ return resolved
4223
+
4224
+ @function_tool
4225
+ def file_read(path: str) -> str:
4226
+ """Read a file from persistent storage. The path is relative to the storage root."""
4227
+ try:
4228
+ full_path = _safe_resolve(path)
4229
+ with open(full_path) as f:
4230
+ return f.read()
4231
+ except ValueError as e:
4232
+ return str(e)
4233
+ except OSError as e:
4234
+ return f"Error reading '{path}': {e.strerror}"
4235
+
4236
+ @function_tool
4237
+ def file_write(path: str, content: str) -> str:
4238
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
4239
+ try:
4240
+ full_path = _safe_resolve(path)
4241
+ parent = os.path.dirname(full_path)
4242
+ if parent:
4243
+ os.makedirs(parent, exist_ok=True)
4244
+ with open(full_path, "w") as f:
4245
+ f.write(content)
4246
+ return f"Written to {path}"
4247
+ except ValueError as e:
4248
+ return str(e)
4249
+ except OSError as e:
4250
+ return f"Error writing '{path}': {e.strerror}"
4251
+
4252
+ @function_tool
4253
+ def list_files(directory: str = "") -> str:
4254
+ """List files in persistent storage. The directory is relative to the storage root."""
4255
+ try:
4256
+ target = _safe_resolve(directory)
4257
+ entries = os.listdir(target)
4258
+ return "\\n".join(entries) if entries else "(empty directory)"
4259
+ except ValueError as e:
4260
+ return str(e)
4261
+ except OSError as e:
4262
+ return f"Error listing '{directory}': {e.strerror}"
4263
+
4264
+ tools.extend([file_read, file_write, list_files])
4265
+ {{/if}}
4266
+
4267
+ INSTRUCTIONS = """
4268
+ You are a helpful assistant. Use tools when appropriate.
4269
+ {{#if sessionStorageMountPath}}
4270
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
4271
+ {{/if}}
4272
+ """
4273
+
2989
4274
  # Define the agent execution
2990
4275
  async def main(query):
2991
4276
  ensure_credentials_loaded()
@@ -2995,8 +4280,9 @@ async def main(query):
2995
4280
  agent = Agent(
2996
4281
  name="{{ name }}",
2997
4282
  model="gpt-4.1",
4283
+ instructions=INSTRUCTIONS,
2998
4284
  mcp_servers=mcp_servers,
2999
- tools=[add_numbers]
4285
+ tools=tools
3000
4286
  )
3001
4287
  result = await Runner.run(agent, query)
3002
4288
  return result
@@ -3004,8 +4290,9 @@ async def main(query):
3004
4290
  agent = Agent(
3005
4291
  name="{{ name }}",
3006
4292
  model="gpt-4.1",
4293
+ instructions=INSTRUCTIONS,
3007
4294
  mcp_servers=[],
3008
- tools=[add_numbers]
4295
+ tools=tools
3009
4296
  )
3010
4297
  result = await Runner.run(agent, query)
3011
4298
  return result
@@ -3016,8 +4303,9 @@ async def main(query):
3016
4303
  agent = Agent(
3017
4304
  name="{{ name }}",
3018
4305
  model="gpt-4.1",
4306
+ instructions=INSTRUCTIONS,
3019
4307
  mcp_servers=active_servers,
3020
- tools=[add_numbers]
4308
+ tools=tools
3021
4309
  )
3022
4310
  result = await Runner.run(agent, query)
3023
4311
  return result
@@ -3025,8 +4313,9 @@ async def main(query):
3025
4313
  agent = Agent(
3026
4314
  name="{{ name }}",
3027
4315
  model="gpt-4.1",
4316
+ instructions=INSTRUCTIONS,
3028
4317
  mcp_servers=[],
3029
- tools=[add_numbers]
4318
+ tools=tools
3030
4319
  )
3031
4320
  result = await Runner.run(agent, query)
3032
4321
  return result
@@ -3308,6 +4597,9 @@ from mcp_client.client import get_streamable_http_mcp_client
3308
4597
  {{#if hasMemory}}
3309
4598
  from memory.session import get_memory_session_manager
3310
4599
  {{/if}}
4600
+ {{#if sessionStorageMountPath}}
4601
+ import os
4602
+ {{/if}}
3311
4603
 
3312
4604
  app = BedrockAgentCoreApp()
3313
4605
  log = app.logger
@@ -3329,11 +4621,70 @@ def add_numbers(a: int, b: int) -> int:
3329
4621
  return a+b
3330
4622
  tools.append(add_numbers)
3331
4623
 
4624
+ {{#if sessionStorageMountPath}}
4625
+ SESSION_STORAGE_PATH = "{{sessionStorageMountPath}}"
4626
+
4627
+ def _safe_resolve(path: str) -> str:
4628
+ """Resolve path safely within the storage boundary."""
4629
+ resolved = os.path.realpath(os.path.join(SESSION_STORAGE_PATH, path.lstrip("/")))
4630
+ if not resolved.startswith(os.path.realpath(SESSION_STORAGE_PATH)):
4631
+ raise ValueError(f"Path '{path}' is outside the storage boundary")
4632
+ return resolved
4633
+
4634
+ @tool
4635
+ def file_read(path: str) -> str:
4636
+ """Read a file from persistent storage. The path is relative to the storage root."""
4637
+ try:
4638
+ full_path = _safe_resolve(path)
4639
+ with open(full_path) as f:
4640
+ return f.read()
4641
+ except ValueError as e:
4642
+ return str(e)
4643
+ except OSError as e:
4644
+ return f"Error reading '{path}': {e.strerror}"
4645
+
4646
+ @tool
4647
+ def file_write(path: str, content: str) -> str:
4648
+ """Write content to a file in persistent storage. The path is relative to the storage root."""
4649
+ try:
4650
+ full_path = _safe_resolve(path)
4651
+ parent = os.path.dirname(full_path)
4652
+ if parent:
4653
+ os.makedirs(parent, exist_ok=True)
4654
+ with open(full_path, "w") as f:
4655
+ f.write(content)
4656
+ return f"Written to {path}"
4657
+ except ValueError as e:
4658
+ return str(e)
4659
+ except OSError as e:
4660
+ return f"Error writing '{path}': {e.strerror}"
4661
+
4662
+ @tool
4663
+ def list_files(directory: str = "") -> str:
4664
+ """List files in persistent storage. The directory is relative to the storage root."""
4665
+ try:
4666
+ target = _safe_resolve(directory)
4667
+ entries = os.listdir(target)
4668
+ return "\\n".join(entries) if entries else "(empty directory)"
4669
+ except ValueError as e:
4670
+ return str(e)
4671
+ except OSError as e:
4672
+ return f"Error listing '{directory}': {e.strerror}"
4673
+
4674
+ tools.extend([file_read, file_write, list_files])
4675
+ {{/if}}
4676
+
3332
4677
  # Add MCP client to tools if available
3333
4678
  for mcp_client in mcp_clients:
3334
4679
  if mcp_client:
3335
4680
  tools.append(mcp_client)
3336
4681
 
4682
+ SYSTEM_PROMPT = """
4683
+ You are a helpful assistant. Use tools when appropriate.
4684
+ {{#if sessionStorageMountPath}}
4685
+ You have persistent storage at {{sessionStorageMountPath}}. Use file tools to read and write files. Data persists across sessions.
4686
+ {{/if}}
4687
+ """
3337
4688
 
3338
4689
  {{#if hasMemory}}
3339
4690
  def agent_factory():
@@ -3345,9 +4696,7 @@ def agent_factory():
3345
4696
  cache[key] = Agent(
3346
4697
  model=load_model(),
3347
4698
  session_manager=get_memory_session_manager(session_id, user_id),
3348
- system_prompt="""
3349
- You are a helpful assistant. Use tools when appropriate.
3350
- """,
4699
+ system_prompt=SYSTEM_PROMPT,
3351
4700
  tools=tools
3352
4701
  )
3353
4702
  return cache[key]
@@ -3361,9 +4710,7 @@ def get_or_create_agent():
3361
4710
  if _agent is None:
3362
4711
  _agent = Agent(
3363
4712
  model=load_model(),
3364
- system_prompt="""
3365
- You are a helpful assistant. Use tools when appropriate.
3366
- """,
4713
+ system_prompt=SYSTEM_PROMPT,
3367
4714
  tools=tools
3368
4715
  )
3369
4716
  return _agent
@@ -3826,27 +5173,47 @@ exports[`Assets Directory Snapshots > Root-level assets > AGENTS.md should match
3826
5173
 
3827
5174
  This directory stores:
3828
5175
 
3829
- - Template assets for agents written in different Languages, SDKs and having different configurations
5176
+ - Template assets for agents written in different languages, SDKs, and configurations
3830
5177
  - Container templates (\`container/python/\`) with \`Dockerfile\` and \`.dockerignore\` for Container build agents
5178
+ - Vended documentation (\`README.md\`, \`agents/AGENTS.md\`) copied into user projects at create time
5179
+ - CDK project template (\`cdk/\`) using \`@aws/agentcore-cdk\` L3 constructs
5180
+ - Evaluator templates (\`evaluators/\`) for code-based evaluators
5181
+ - MCP tool templates (\`mcp/\`) for Lambda and AgentCoreRuntime compute
3831
5182
 
3832
5183
  ### Directory Layout
3833
5184
 
3834
5185
  \`\`\`
3835
5186
  assets/
3836
- ├── python/ # Framework templates (one per SDK)
3837
- ├── strands/
3838
- ├── langchain_langgraph/
3839
- ├── googleadk/
3840
- ├── openaiagents/
3841
- └── autogen/
5187
+ ├── README.md # Vended to project root as project README
5188
+ ├── AGENTS.md # This file — internal dev context
5189
+ ├── agents/
5190
+ └── AGENTS.md # Vended to project root for AI coding assistants
5191
+ ├── python/ # Framework templates (one per SDK per protocol)
5192
+ ├── http/ # HTTP protocol agents
5193
+ │ │ ├── strands/
5194
+ │ │ ├── langchain_langgraph/
5195
+ │ │ ├── googleadk/
5196
+ │ │ ├── openaiagents/
5197
+ │ │ └── autogen/
5198
+ │ ├── mcp/ # MCP protocol agents
5199
+ │ │ └── standalone/
5200
+ │ └── a2a/ # A2A protocol agents
5201
+ │ ├── strands/
5202
+ │ ├── langchain_langgraph/
5203
+ │ └── googleadk/
5204
+ ├── typescript/ # TypeScript agent templates
3842
5205
  ├── container/ # Container build templates
3843
5206
  │ └── python/
3844
5207
  │ ├── Dockerfile
3845
5208
  │ └── dockerignore.template
3846
- └── agents/ # AGENTS.md vended to user projects
5209
+ ├── cdk/ # CDK project template (@aws/agentcore-cdk)
5210
+ ├── evaluators/ # Code-based evaluator templates
5211
+ └── mcp/ # MCP tool templates (Lambda + AgentCoreRuntime)
5212
+ ├── python/
5213
+ └── python-lambda/
3847
5214
  \`\`\`
3848
5215
 
3849
- The rendering logic is rooted in the \`AgentEnvSpec\` and must ALWAYS respect the configuration in the Spec.
5216
+ The rendering logic is rooted in the \`AgentEnvSpec\` and must ALWAYS respect the configuration in the spec.
3850
5217
 
3851
5218
  For Container builds, \`BaseRenderer.render()\` automatically copies the \`container/<language>/\` templates (Dockerfile,
3852
5219
  .dockerignore) into the agent directory when \`buildType === 'Container'\`.
@@ -3855,10 +5222,13 @@ For Container builds, \`BaseRenderer.render()\` automatically copies the \`conta
3855
5222
 
3856
5223
  - Always make sure the templates are as close to working code as possible
3857
5224
  - AVOID as much as possible using any conditionals within the templates
5225
+ - Test template rendering with \`agentcore add agent\` for each framework/protocol combination
3858
5226
 
3859
5227
  ## How to use the assets in this directory
3860
5228
 
3861
- - These assets are rendered by the CLI's template renderer in \`src/cli/templates/\`.
5229
+ - These assets are rendered by the CLI's template renderer in \`src/cli/templates/\`
5230
+ - The \`README.md\` and \`agents/AGENTS.md\` are copied verbatim (no template rendering) during project creation
5231
+ - The \`.llm-context/\` files are sourced from \`src/schema/llm-compacted/\` and written during init
3862
5232
  "
3863
5233
  `;
3864
5234
 
@@ -3870,14 +5240,19 @@ This project was created with the [AgentCore CLI](https://github.com/aws/agentco
3870
5240
  ## Project Structure
3871
5241
 
3872
5242
  \`\`\`
3873
- .
3874
5243
  my-project/
5244
+ ├── AGENTS.md # AI coding assistant context
3875
5245
  ├── agentcore/
3876
- │ ├── .env.local # API keys (gitignored)
3877
- │ ├── agentcore.json # Resource specifications
3878
- │ ├── aws-targets.json # Deployment targets
3879
- └── cdk/ # CDK infrastructure
3880
- ├── app/ # Application code
5246
+ │ ├── agentcore.json # Project config (agents, memories, credentials, gateways, evaluators)
5247
+ │ ├── aws-targets.json # Deployment targets (account + region)
5248
+ │ ├── .env.local # Secrets — API keys (gitignored)
5249
+ ├── .llm-context/ # TypeScript type definitions for AI assistants
5250
+ │ │ ├── agentcore.ts # AgentCoreProjectSpec types
5251
+ │ │ ├── aws-targets.ts # Deployment target types
5252
+ │ │ └── mcp.ts # Gateway and MCP tool types
5253
+ │ └── cdk/ # CDK infrastructure (@aws/agentcore-cdk)
5254
+ ├── app/ # Agent application code
5255
+ └── evaluators/ # Custom evaluator code (if any)
3881
5256
  \`\`\`
3882
5257
 
3883
5258
  ## Getting Started
@@ -3885,7 +5260,9 @@ my-project/
3885
5260
  ### Prerequisites
3886
5261
 
3887
5262
  - **Node.js** 20.x or later
3888
- - **uv** for Python agents ([install](https://docs.astral.sh/uv/getting-started/installation/))
5263
+ - **Python 3.10+** and **uv** for Python agents ([install uv](https://docs.astral.sh/uv/getting-started/installation/))
5264
+ - **AWS credentials** configured (\`aws configure\` or environment variables)
5265
+ - **Docker** (only for Container build agents)
3889
5266
 
3890
5267
  ### Development
3891
5268
 
@@ -3903,44 +5280,62 @@ Deploy to AWS:
3903
5280
  agentcore deploy
3904
5281
  \`\`\`
3905
5282
 
3906
- Or use CDK directly:
5283
+ ## Commands
3907
5284
 
3908
- \`\`\`bash
3909
- cd agentcore/cdk
3910
- npx cdk deploy
3911
- \`\`\`
5285
+ | Command | Description |
5286
+ | --- | --- |
5287
+ | \`agentcore create\` | Create a new AgentCore project |
5288
+ | \`agentcore add\` | Add resources (agent, memory, credential, gateway, evaluator, policy) |
5289
+ | \`agentcore remove\` | Remove resources |
5290
+ | \`agentcore dev\` | Run agent locally with hot-reload |
5291
+ | \`agentcore deploy\` | Deploy to AWS via CDK |
5292
+ | \`agentcore status\` | Show deployment status |
5293
+ | \`agentcore invoke\` | Invoke agent (local or deployed) |
5294
+ | \`agentcore logs\` | View agent logs |
5295
+ | \`agentcore traces\` | View agent traces |
5296
+ | \`agentcore eval\` | Run evaluations |
5297
+ | \`agentcore package\` | Package agent artifacts |
5298
+ | \`agentcore validate\` | Validate configuration |
5299
+ | \`agentcore pause\` | Pause a deployed agent |
5300
+ | \`agentcore resume\` | Resume a paused agent |
5301
+ | \`agentcore fetch\` | Fetch remote resource definitions |
5302
+ | \`agentcore import\` | Import existing resources |
5303
+ | \`agentcore update\` | Check for CLI updates |
3912
5304
 
3913
5305
  ## Configuration
3914
5306
 
3915
- Edit the JSON files in \`agentcore/\` to configure your agents, memory, and credentials. See \`agentcore/.llm-context/\` for
3916
- type definitions and validation constraints.
5307
+ Edit the JSON files in \`agentcore/\` to configure your project. See \`agentcore/.llm-context/\` for type definitions and validation constraints.
3917
5308
 
3918
- The project uses a **flat resource model** where agents, memories, and credentials are top-level arrays in
3919
- \`agentcore.json\`.
5309
+ The project uses a **flat resource model** agents, memories, credentials, gateways, evaluators, and policies are top-level arrays in \`agentcore.json\`. Resources are independent; agents discover memories and credentials at runtime via environment variables or SDK calls.
3920
5310
 
3921
- ## Commands
5311
+ ## Resources
3922
5312
 
3923
- | Command | Description |
3924
- | -------------------- | ----------------------------------------------- |
3925
- | \`agentcore create\` | Create a new AgentCore project |
3926
- | \`agentcore add\` | Add resources (agent, memory, credential, target) |
3927
- | \`agentcore remove\` | Remove resources |
3928
- | \`agentcore dev\` | Run agent locally |
3929
- | \`agentcore deploy\` | Deploy to AWS |
3930
- | \`agentcore status\` | Show deployment status |
3931
- | \`agentcore invoke\` | Invoke agent (local or deployed) |
3932
- | \`agentcore package\` | Package agent artifacts |
3933
- | \`agentcore validate\` | Validate configuration |
3934
- | \`agentcore update\` | Check for CLI updates |
5313
+ | Resource | Purpose |
5314
+ | --- | --- |
5315
+ | Agent (runtime) | HTTP, MCP, or A2A agent deployed to AgentCore Runtime |
5316
+ | Memory | Persistent context storage with configurable strategies |
5317
+ | Credential | API key or OAuth credential providers |
5318
+ | Gateway | MCP gateway that routes tool calls to targets |
5319
+ | Gateway Target | Tool implementation (Lambda, MCP server, OpenAPI, Smithy, API Gateway) |
5320
+ | Evaluator | Custom LLM-as-a-Judge or code-based evaluation |
5321
+ | Online Eval Config | Continuous evaluation pipeline for deployed agents |
5322
+ | Policy | Cedar authorization policies for gateway tools |
3935
5323
 
3936
5324
  ### Agent Types
3937
5325
 
3938
- - **Template agents**: Created from framework templates (Strands, LangChain_LangGraph, CrewAI, GoogleADK, OpenAIAgents)
5326
+ - **Template agents**: Created from framework templates (Strands, LangChain/LangGraph, GoogleADK, OpenAI Agents, Autogen)
3939
5327
  - **BYO agents**: Bring your own code with \`agentcore add agent --type byo\`
5328
+ - **Import agents**: Import existing Bedrock agents with \`agentcore import\`
5329
+
5330
+ ### Build Types
5331
+
5332
+ - **CodeZip**: Python source packaged as a zip and deployed directly to AgentCore Runtime
5333
+ - **Container**: Docker image built via CodeBuild (ARM64), pushed to ECR, and deployed to AgentCore Runtime
3940
5334
 
3941
5335
  ## Documentation
3942
5336
 
3943
- - [AgentCore CLI Documentation](https://github.com/aws/agentcore-cli)
5337
+ - [AgentCore CLI](https://github.com/aws/agentcore-cli)
5338
+ - [AgentCore CDK Constructs](https://github.com/aws/agentcore-l3-cdk-constructs)
3944
5339
  - [Amazon Bedrock AgentCore](https://aws.amazon.com/bedrock/agentcore/)
3945
5340
  "
3946
5341
  `;
@@ -3950,103 +5345,114 @@ exports[`Assets Directory Snapshots > Root-level assets > agents/AGENTS.md shoul
3950
5345
 
3951
5346
  This project contains configuration and infrastructure for an Amazon Bedrock AgentCore application.
3952
5347
 
3953
- The \`agentcore/\` directory serves as a declarative model of an AgentCore project along with a concrete implementation
3954
- through the \`agentcore/cdk/\` project which is modeled to take the configs as input. The project uses a **flat resource
3955
- model** where agents, memories, and credentials are top-level arrays.
5348
+ The \`agentcore/\` directory is a declarative model of the project. The \`agentcore/cdk/\` subdirectory uses the
5349
+ \`@aws/agentcore-cdk\` L3 constructs to deploy the configuration to AWS.
3956
5350
 
3957
5351
  ## Mental Model
3958
5352
 
3959
- The project uses a **flat resource model**. Agents, memories, and credentials are independent top-level arrays in
3960
- \`agentcore.json\`. There is no binding or attachment between resources in the schema — each resource is provisioned
3961
- independently. To use a memory or credential from an agent, the application code discovers the resource at runtime
3962
- (e.g., via environment variables or SDK calls). Tags defined in \`agentcore.json\` flow through to deployed CloudFormation resources.
5353
+ The project uses a **flat resource model**. Agents, memories, credentials, gateways, evaluators, and policies are
5354
+ independent top-level arrays in \`agentcore.json\`. There is no binding between resources in the schema — each resource is
5355
+ provisioned independently. Agents discover memories and credentials at runtime via environment variables or SDK calls.
5356
+ Tags defined in \`agentcore.json\` flow through to deployed CloudFormation resources.
3963
5357
 
3964
5358
  ## Critical Invariants
3965
5359
 
3966
- 1. **Schema-First Authority:** The \`.json\` files are the absolute source of truth. Do not attempt to modify agent
3967
- behavior by editing the generated CDK code in \`cdk/\`.
3968
- 2. **Resource Identity:** The \`name\` field in the schema determines the CloudFormation Logical ID.
3969
- - **Renaming** an agent or target will **destroy and recreate** that resource.
3970
- - **Modifying** other fields (descriptions, config) will update the resource **in-place**.
3971
- 3. **1:1 Validation:** The schema maps directly to valid CloudFormation. If your JSON conforms to the types in
3972
- \`.llm-context/\`, it will deploy successfully.
3973
- 4. **Resource Removal:** To remove all resources, use \`agentcore remove all\`. To tear down deployed infrastructure, run
3974
- \`agentcore deploy\` after removal — it will detect the empty state and offer a teardown flow.
5360
+ 1. **Schema-First Authority:** The \`.json\` files are the source of truth. Do not modify agent behavior by editing
5361
+ generated CDK code in \`cdk/\`.
5362
+ 2. **Resource Identity:** The \`name\` field determines the CloudFormation Logical ID.
5363
+ - **Renaming** a resource will **destroy and recreate** it.
5364
+ - **Modifying** other fields will update the resource **in-place**.
5365
+ 3. **Schema Validation:** If your JSON conforms to the types in \`.llm-context/\`, it will deploy successfully. Run
5366
+ \`agentcore validate\` to check.
5367
+ 4. **Resource Removal:** Use \`agentcore remove\` to remove resources. Run \`agentcore deploy\` after removal to tear down
5368
+ deployed infrastructure.
3975
5369
 
3976
5370
  ## Directory Structure
3977
5371
 
3978
5372
  \`\`\`
3979
- myNewProject/
3980
- ├── AGENTS.md # This file - AI coding assistant context
3981
- ├── agentcore/ # AgentCore configuration directory
5373
+ myProject/
5374
+ ├── AGENTS.md # This file AI coding assistant context
5375
+ ├── agentcore/
3982
5376
  │ ├── agentcore.json # Main project config (AgentCoreProjectSpec)
3983
- │ ├── aws-targets.json # Deployment targets
3984
- │ ├── .llm-context/ # TypeScript type definitions for AI coding assistants
3985
- ├── README.md # Guide to using the schema files
5377
+ │ ├── aws-targets.json # Deployment targets (account + region)
5378
+ │ ├── .env.local # Secrets API keys (gitignored)
5379
+ │ ├── .llm-context/ # TypeScript type definitions for AI assistants
5380
+ │ │ ├── README.md # Guide to using schema files
3986
5381
  │ │ ├── agentcore.ts # AgentCoreProjectSpec types
3987
- │ │ └── aws-targets.ts # AWS deployment target types
3988
- │ └── cdk/ # AWS CDK project for deployment
3989
- └── app/ # Application code (if agents were created)
5382
+ │ │ ├── aws-targets.ts # AWS deployment target types
5383
+ └── mcp.ts # Gateway and MCP tool types
5384
+ └── cdk/ # AWS CDK project (@aws/agentcore-cdk L3 constructs)
5385
+ ├── app/ # Agent application code
5386
+ └── evaluators/ # Custom evaluator code (if any)
3990
5387
  \`\`\`
3991
5388
 
3992
5389
  ## Schema Reference
3993
5390
 
3994
5391
  The \`agentcore/.llm-context/\` directory contains TypeScript type definitions optimized for AI coding assistants. Each
3995
- file maps to a JSON config file and includes validation constraints as comments.
5392
+ file maps to a JSON config file and includes validation constraints as comments (\`@regex\`, \`@min\`, \`@max\`).
3996
5393
 
3997
- | JSON Config | Schema File | Root Type |
3998
- | ---------------------------- | --------------------------------------- | ----------------------- |
3999
- | \`agentcore/agentcore.json\` | \`agentcore/.llm-context/agentcore.ts\` | \`AgentCoreProjectSpec\` |
4000
- | \`agentcore/aws-targets.json\` | \`agentcore/.llm-context/aws-targets.ts\` | \`AWSDeploymentTarget[]\` |
5394
+ | JSON Config | Schema File | Root Type |
5395
+ | --- | --- | --- |
5396
+ | \`agentcore/agentcore.json\` | \`agentcore/.llm-context/agentcore.ts\` | \`AgentCoreProjectSpec\` |
5397
+ | \`agentcore/agentcore.json\` (gateways) | \`agentcore/.llm-context/mcp.ts\` | \`AgentCoreMcpSpec\` |
5398
+ | \`agentcore/aws-targets.json\` | \`agentcore/.llm-context/aws-targets.ts\` | \`AwsDeploymentTarget[]\` |
4001
5399
 
4002
5400
  ### Key Types
4003
5401
 
4004
- - **AgentCoreProjectSpec**: Root project configuration with \`agents\`, \`memories\`, \`credentials\` arrays
4005
- - **AgentEnvSpec**: Agent configuration (runtime, entrypoint, code location)
4006
- - **Memory**: Memory resource with strategies and expiry
4007
- - **Credential**: API key credential provider
5402
+ - **AgentCoreProjectSpec**: Root config with \`runtimes\`, \`memories\`, \`credentials\`, \`agentCoreGateways\`, \`evaluators\`, \`onlineEvalConfigs\`, \`policyEngines\` arrays
5403
+ - **AgentEnvSpec**: Agent configuration (build type, entrypoint, code location, runtime version, network mode)
5404
+ - **Memory**: Memory resource with strategies (SEMANTIC, SUMMARIZATION, USER_PREFERENCE, EPISODIC) and expiry
5405
+ - **Credential**: API key or OAuth credential provider
5406
+ - **AgentCoreGateway**: MCP gateway with targets (Lambda, MCP server, OpenAPI, Smithy, API Gateway)
5407
+ - **Evaluator**: LLM-as-a-Judge or code-based evaluator
5408
+ - **OnlineEvalConfig**: Continuous evaluation pipeline bound to an agent
4008
5409
 
4009
5410
  ### Common Enum Values
4010
5411
 
4011
5412
  - **BuildType**: \`'CodeZip'\` | \`'Container'\`
4012
- - **NetworkMode**: \`'PUBLIC'\`
4013
- - **RuntimeVersion**: \`'PYTHON_3_10'\` | \`'PYTHON_3_11'\` | \`'PYTHON_3_12'\` | \`'PYTHON_3_13'\` | \`'PYTHON_3_14'\`
5413
+ - **NetworkMode**: \`'PUBLIC'\` | \`'VPC'\`
5414
+ - **RuntimeVersion**: \`'PYTHON_3_10'\` | \`'PYTHON_3_11'\` | \`'PYTHON_3_12'\` | \`'PYTHON_3_13'\` | \`'PYTHON_3_14'\` | \`'NODE_18'\` | \`'NODE_20'\` | \`'NODE_22'\`
4014
5415
  - **MemoryStrategyType**: \`'SEMANTIC'\` | \`'SUMMARIZATION'\` | \`'USER_PREFERENCE'\` | \`'EPISODIC'\`
5416
+ - **GatewayTargetType**: \`'lambda'\` | \`'mcpServer'\` | \`'openApiSchema'\` | \`'smithyModel'\` | \`'apiGateway'\` | \`'lambdaFunctionArn'\`
5417
+ - **ModelProvider**: \`'Bedrock'\` | \`'Gemini'\` | \`'OpenAI'\` | \`'Anthropic'\`
4015
5418
 
4016
5419
  ### Build Types
4017
5420
 
4018
- - **CodeZip**: Python source is packaged as a zip artifact and deployed directly to AgentCore Runtime.
4019
- - **Container**: Agent code is built as a Docker container image. Requires a \`Dockerfile\` in the agent's \`codeLocation\`
4020
- directory. At deploy time, the source is uploaded to S3, built in CodeBuild (ARM64), pushed to a per-agent ECR
4021
- repository, and the container URI is provided to the AgentCore Runtime. For local development (\`agentcore dev\`), the
4022
- container is built and run locally with volume-mounted hot-reload.
5421
+ - **CodeZip**: Python source packaged as a zip and deployed directly to AgentCore Runtime.
5422
+ - **Container**: Docker image built in CodeBuild (ARM64), pushed to a per-agent ECR repository. Requires a \`Dockerfile\`
5423
+ in the agent's \`codeLocation\` directory. For local development (\`agentcore dev\`), the container is built and run
5424
+ locally with volume-mounted hot-reload.
4023
5425
 
4024
5426
  ### Supported Frameworks (for template agents)
4025
5427
 
4026
- - **Strands** - Works with Bedrock, Anthropic, OpenAI, Gemini
4027
- - **LangChain_LangGraph** - Works with Bedrock, Anthropic, OpenAI, Gemini
4028
- - **GoogleADK** - Gemini only
4029
- - **OpenAIAgents** - OpenAI only
5428
+ - **Strands** Bedrock, Anthropic, OpenAI, Gemini
5429
+ - **LangChain/LangGraph** Bedrock, Anthropic, OpenAI, Gemini
5430
+ - **GoogleADK** Gemini
5431
+ - **OpenAI Agents** OpenAI
5432
+ - **Autogen** — Bedrock, Anthropic, OpenAI, Gemini
4030
5433
 
5434
+ ### Protocols
4031
5435
 
4032
- ### Specific Context
4033
-
4034
- Directory pathing to local projects is required for runtimes. Both CodeZip (Python zip) and Container (Docker image)
4035
- deployment options are available.
5436
+ - **HTTP** — Standard HTTP agent endpoint
5437
+ - **MCP** — Model Context Protocol server
5438
+ - **A2A** — Agent-to-Agent protocol (Google A2A)
4036
5439
 
4037
5440
  ## Deployment
4038
5441
 
4039
- The \`agentcore/cdk/\` subdirectory contains an AWS CDK node project.
5442
+ Deployments are orchestrated through the CLI:
4040
5443
 
4041
- Deployments of this project are primarily intended to be orchestrated through the \`agentcore deploy\` command in the CLI.
5444
+ \`\`\`bash
5445
+ agentcore deploy # Synthesizes CDK and deploys to AWS
5446
+ agentcore status # Shows deployment status
5447
+ \`\`\`
4042
5448
 
4043
- Alternatively, the project can be deployed directly as a traditional CDK project:
5449
+ Alternatively, deploy directly via CDK:
4044
5450
 
4045
5451
  \`\`\`bash
4046
5452
  cd agentcore/cdk
4047
5453
  npm install
4048
- npx cdk synth # Preview CloudFormation template
4049
- npx cdk deploy # Deploy to AWS
5454
+ npx cdk synth
5455
+ npx cdk deploy
4050
5456
  \`\`\`
4051
5457
 
4052
5458
  ## Editing Schemas
@@ -4057,7 +5463,25 @@ When modifying JSON config files:
4057
5463
  2. Check validation constraint comments (\`@regex\`, \`@min\`, \`@max\`)
4058
5464
  3. Use exact enum values as string literals
4059
5465
  4. Use CloudFormation-safe names (alphanumeric, start with letter)
4060
- 5. Run \`agentcore validate\` command to verify changes.
5466
+ 5. Run \`agentcore validate\` to verify changes
5467
+
5468
+ ## CLI Commands
5469
+
5470
+ | Command | Description |
5471
+ | --- | --- |
5472
+ | \`agentcore create\` | Create a new project |
5473
+ | \`agentcore add <resource>\` | Add agent, memory, credential, gateway, evaluator, policy |
5474
+ | \`agentcore remove <resource>\` | Remove a resource |
5475
+ | \`agentcore dev\` | Run agent locally with hot-reload |
5476
+ | \`agentcore deploy\` | Deploy to AWS |
5477
+ | \`agentcore status\` | Show deployment status |
5478
+ | \`agentcore invoke\` | Invoke agent (local or deployed) |
5479
+ | \`agentcore logs\` | View agent logs |
5480
+ | \`agentcore traces\` | View agent traces |
5481
+ | \`agentcore eval\` | Run evaluations against an agent |
5482
+ | \`agentcore package\` | Package agent artifacts |
5483
+ | \`agentcore validate\` | Validate configuration |
5484
+ | \`agentcore pause\` / \`resume\` | Pause or resume a deployed agent |
4061
5485
  "
4062
5486
  `;
4063
5487