From 0caa31fea9027195fcc5d7a65f568d1680c2775a Mon Sep 17 00:00:00 2001 From: Tejas Kashinath Date: Mon, 16 Mar 2026 14:41:53 -0400 Subject: [PATCH 1/8] feat: add protocol mode support (HTTP, MCP, A2A, AGUI) Add the protocol dimension to all agent creation flows: non-interactive CLI, TUI wizard, and BYO agent. Each protocol mode routes to the correct template directory under a new protocol-first layout (python/{protocol}/{framework}/base/). Key changes: - Schema: ProtocolModeSchema, PROTOCOL_FRAMEWORK_MATRIX, helpers - Templates: restructure under http/, add mcp/, a2a/, agui/ dirs - Rendering: BaseRenderer uses protocol in template path, new McpRenderer - CLI: --protocol flag on add agent and create commands with validation - TUI: protocol step in wizard, conditional framework/model filtering - Schema mapper: protocolMode passthrough, MCP skips model/memory/creds - Tests: unit tests for schema, validation, rendering, and mapping --- .../assets.snapshot.test.ts.snap | 1845 ++++++++++++++++- .../python/a2a/googleadk/base/README.md | 22 + .../googleadk}/base/gitignore.template | 0 src/assets/python/a2a/googleadk/base/main.py | 22 + .../{ => a2a}/googleadk/base/model/load.py | 0 .../python/a2a/googleadk/base/pyproject.toml | 20 + .../a2a/langchain_langgraph/base/README.md | 22 + .../base/gitignore.template | 0 .../a2a/langchain_langgraph/base/main.py | 20 + .../langchain_langgraph/base/model/load.py | 0 .../langchain_langgraph/base/pyproject.toml | 25 + src/assets/python/a2a/strands/base/README.md | 22 + .../strands}/base/gitignore.template | 0 src/assets/python/a2a/strands/base/main.py | 46 + .../{ => a2a}/strands/base/model/load.py | 0 .../python/a2a/strands/base/pyproject.toml | 23 + .../strands/capabilities/memory}/__init__.py | 0 .../strands/capabilities/memory/session.py | 38 + .../python/agui/googleadk/base/README.md | 22 + .../googleadk}/base/gitignore.template | 0 src/assets/python/agui/googleadk/base/main.py | 22 + .../python/agui/googleadk/base/model/load.py | 41 + .../python/agui/googleadk/base/pyproject.toml | 21 + .../agui/langchain_langgraph/base/README.md | 22 + .../base/gitignore.template | 0 .../agui/langchain_langgraph/base/main.py | 19 + .../langchain_langgraph/base/model/load.py | 123 ++ .../langchain_langgraph/base/pyproject.toml | 25 + src/assets/python/agui/strands/base/README.md | 22 + .../agui/strands/base/gitignore.template | 41 + src/assets/python/agui/strands/base/main.py | 46 + .../python/agui/strands/base/model/load.py | 123 ++ .../python/agui/strands/base/pyproject.toml | 24 + .../strands/capabilities/memory}/__init__.py | 0 .../strands/capabilities/memory/session.py | 38 + .../python/{ => http}/autogen/base/README.md | 0 .../http/autogen/base/gitignore.template | 41 + .../python/{ => http}/autogen/base/main.py | 0 .../autogen/base/mcp_client}/__init__.py | 0 .../autogen/base/mcp_client/client.py | 0 .../autogen/base/model}/__init__.py | 0 .../{ => http}/autogen/base/model/load.py | 0 .../{ => http}/autogen/base/pyproject.toml | 0 .../python/{ => http}/crewai/base/README.md | 0 .../http/crewai/base/gitignore.template | 41 + .../python/{ => http}/crewai/base/main.py | 0 .../crewai}/base/model/__init__.py | 0 .../{ => http}/crewai/base/model/load.py | 0 .../{ => http}/crewai/base/pyproject.toml | 0 .../{ => http}/googleadk/base/README.md | 0 .../http/googleadk/base/gitignore.template | 41 + .../python/{ => http}/googleadk/base/main.py | 0 .../googleadk}/base/mcp_client/__init__.py | 0 .../googleadk/base/mcp_client/client.py | 0 .../googleadk}/base/model/__init__.py | 0 .../python/http/googleadk/base/model/load.py | 41 + .../{ => http}/googleadk/base/pyproject.toml | 0 .../langchain_langgraph/base/README.md | 0 .../base/gitignore.template | 41 + .../langchain_langgraph/base/main.py | 0 .../base/mcp_client/__init__.py | 0 .../base/mcp_client/client.py | 0 .../base/model/__init__.py | 0 .../langchain_langgraph/base/model/load.py | 123 ++ .../langchain_langgraph/base/pyproject.toml | 0 .../{ => http}/openaiagents/base/README.md | 0 .../http/openaiagents/base/gitignore.template | 41 + .../{ => http}/openaiagents/base/main.py | 0 .../openaiagents}/base/mcp_client/__init__.py | 0 .../openaiagents/base/mcp_client/client.py | 0 .../openaiagents}/base/model/__init__.py | 0 .../openaiagents/base/model/load.py | 0 .../openaiagents/base/pyproject.toml | 0 .../python/{ => http}/strands/base/README.md | 0 .../strands/base/gitignore.template | 0 .../python/{ => http}/strands/base/main.py | 0 .../strands/base/mcp_client}/__init__.py | 0 .../strands/base/mcp_client/client.py | 0 .../http/strands/base/model/__init__.py | 1 + .../python/http/strands/base/model/load.py | 123 ++ .../{ => http}/strands/base/pyproject.toml | 0 .../strands/capabilities/memory/__init__.py | 1 + .../strands/capabilities/memory/session.py | 0 .../python/mcp/standalone/base/README.md | 36 + .../mcp/standalone/base/gitignore.template | 41 + src/assets/python/mcp/standalone/base/main.py | 24 + .../python/mcp/standalone/base/pyproject.toml | 19 + .../commands/add/__tests__/validate.test.ts | 136 ++ src/cli/commands/add/types.ts | 3 +- src/cli/commands/add/validate.ts | 53 +- src/cli/commands/create/action.ts | 8 +- src/cli/commands/create/command.tsx | 4 +- src/cli/commands/create/types.ts | 1 + src/cli/commands/create/validate.ts | 34 + .../generate/__tests__/schema-mapper.test.ts | 33 + .../__tests__/write-agent-to-project.test.ts | 1 + .../agent/generate/schema-mapper.ts | 16 +- src/cli/primitives/AgentPrimitive.tsx | 16 +- src/cli/templates/AutoGenRenderer.ts | 2 +- src/cli/templates/BaseRenderer.ts | 6 +- src/cli/templates/CrewAIRenderer.ts | 2 +- src/cli/templates/GoogleADKRenderer.ts | 2 +- src/cli/templates/LangGraphRenderer.ts | 2 +- src/cli/templates/McpRenderer.ts | 42 + src/cli/templates/OpenAIAgentsRenderer.ts | 2 +- src/cli/templates/StrandsRenderer.ts | 2 +- .../templates/__tests__/BaseRenderer.test.ts | 33 +- src/cli/templates/index.ts | 7 + src/cli/templates/types.ts | 4 +- src/cli/tui/screens/agent/useAddAgent.ts | 1 + src/cli/tui/screens/create/useCreateFlow.ts | 1 + .../tui/screens/generate/GenerateWizardUI.tsx | 61 +- src/cli/tui/screens/generate/types.ts | 25 +- .../tui/screens/generate/useGenerateWizard.ts | 40 +- src/schema/__tests__/constants.test.ts | 79 + src/schema/constants.ts | 32 + .../schemas/__tests__/agent-env.test.ts | 17 + src/schema/schemas/agent-env.ts | 5 +- 118 files changed, 3816 insertions(+), 162 deletions(-) create mode 100644 src/assets/python/a2a/googleadk/base/README.md rename src/assets/python/{autogen => a2a/googleadk}/base/gitignore.template (100%) create mode 100644 src/assets/python/a2a/googleadk/base/main.py rename src/assets/python/{ => a2a}/googleadk/base/model/load.py (100%) create mode 100644 src/assets/python/a2a/googleadk/base/pyproject.toml create mode 100644 src/assets/python/a2a/langchain_langgraph/base/README.md rename src/assets/python/{crewai => a2a/langchain_langgraph}/base/gitignore.template (100%) create mode 100644 src/assets/python/a2a/langchain_langgraph/base/main.py rename src/assets/python/{ => a2a}/langchain_langgraph/base/model/load.py (100%) create mode 100644 src/assets/python/a2a/langchain_langgraph/base/pyproject.toml create mode 100644 src/assets/python/a2a/strands/base/README.md rename src/assets/python/{googleadk => a2a/strands}/base/gitignore.template (100%) create mode 100644 src/assets/python/a2a/strands/base/main.py rename src/assets/python/{ => a2a}/strands/base/model/load.py (100%) create mode 100644 src/assets/python/a2a/strands/base/pyproject.toml rename src/assets/python/{autogen/base/mcp_client => a2a/strands/capabilities/memory}/__init__.py (100%) create mode 100644 src/assets/python/a2a/strands/capabilities/memory/session.py create mode 100644 src/assets/python/agui/googleadk/base/README.md rename src/assets/python/{langchain_langgraph => agui/googleadk}/base/gitignore.template (100%) create mode 100644 src/assets/python/agui/googleadk/base/main.py create mode 100644 src/assets/python/agui/googleadk/base/model/load.py create mode 100644 src/assets/python/agui/googleadk/base/pyproject.toml create mode 100644 src/assets/python/agui/langchain_langgraph/base/README.md rename src/assets/python/{openaiagents => agui/langchain_langgraph}/base/gitignore.template (100%) create mode 100644 src/assets/python/agui/langchain_langgraph/base/main.py create mode 100644 src/assets/python/agui/langchain_langgraph/base/model/load.py create mode 100644 src/assets/python/agui/langchain_langgraph/base/pyproject.toml create mode 100644 src/assets/python/agui/strands/base/README.md create mode 100644 src/assets/python/agui/strands/base/gitignore.template create mode 100644 src/assets/python/agui/strands/base/main.py create mode 100644 src/assets/python/agui/strands/base/model/load.py create mode 100644 src/assets/python/agui/strands/base/pyproject.toml rename src/assets/python/{autogen/base/model => agui/strands/capabilities/memory}/__init__.py (100%) create mode 100644 src/assets/python/agui/strands/capabilities/memory/session.py rename src/assets/python/{ => http}/autogen/base/README.md (100%) create mode 100644 src/assets/python/http/autogen/base/gitignore.template rename src/assets/python/{ => http}/autogen/base/main.py (100%) rename src/assets/python/{crewai/base/model => http/autogen/base/mcp_client}/__init__.py (100%) rename src/assets/python/{ => http}/autogen/base/mcp_client/client.py (100%) rename src/assets/python/{googleadk/base/mcp_client => http/autogen/base/model}/__init__.py (100%) rename src/assets/python/{ => http}/autogen/base/model/load.py (100%) rename src/assets/python/{ => http}/autogen/base/pyproject.toml (100%) rename src/assets/python/{ => http}/crewai/base/README.md (100%) create mode 100644 src/assets/python/http/crewai/base/gitignore.template rename src/assets/python/{ => http}/crewai/base/main.py (100%) rename src/assets/python/{googleadk => http/crewai}/base/model/__init__.py (100%) rename src/assets/python/{ => http}/crewai/base/model/load.py (100%) rename src/assets/python/{ => http}/crewai/base/pyproject.toml (100%) rename src/assets/python/{ => http}/googleadk/base/README.md (100%) create mode 100644 src/assets/python/http/googleadk/base/gitignore.template rename src/assets/python/{ => http}/googleadk/base/main.py (100%) rename src/assets/python/{langchain_langgraph => http/googleadk}/base/mcp_client/__init__.py (100%) rename src/assets/python/{ => http}/googleadk/base/mcp_client/client.py (100%) rename src/assets/python/{langchain_langgraph => http/googleadk}/base/model/__init__.py (100%) create mode 100644 src/assets/python/http/googleadk/base/model/load.py rename src/assets/python/{ => http}/googleadk/base/pyproject.toml (100%) rename src/assets/python/{ => http}/langchain_langgraph/base/README.md (100%) create mode 100644 src/assets/python/http/langchain_langgraph/base/gitignore.template rename src/assets/python/{ => http}/langchain_langgraph/base/main.py (100%) rename src/assets/python/{openaiagents => http/langchain_langgraph}/base/mcp_client/__init__.py (100%) rename src/assets/python/{ => http}/langchain_langgraph/base/mcp_client/client.py (100%) rename src/assets/python/{openaiagents => http/langchain_langgraph}/base/model/__init__.py (100%) create mode 100644 src/assets/python/http/langchain_langgraph/base/model/load.py rename src/assets/python/{ => http}/langchain_langgraph/base/pyproject.toml (100%) rename src/assets/python/{ => http}/openaiagents/base/README.md (100%) create mode 100644 src/assets/python/http/openaiagents/base/gitignore.template rename src/assets/python/{ => http}/openaiagents/base/main.py (100%) rename src/assets/python/{strands => http/openaiagents}/base/mcp_client/__init__.py (100%) rename src/assets/python/{ => http}/openaiagents/base/mcp_client/client.py (100%) rename src/assets/python/{strands => http/openaiagents}/base/model/__init__.py (100%) rename src/assets/python/{ => http}/openaiagents/base/model/load.py (100%) rename src/assets/python/{ => http}/openaiagents/base/pyproject.toml (100%) rename src/assets/python/{ => http}/strands/base/README.md (100%) rename src/assets/python/{ => http}/strands/base/gitignore.template (100%) rename src/assets/python/{ => http}/strands/base/main.py (100%) rename src/assets/python/{strands/capabilities/memory => http/strands/base/mcp_client}/__init__.py (100%) rename src/assets/python/{ => http}/strands/base/mcp_client/client.py (100%) create mode 100644 src/assets/python/http/strands/base/model/__init__.py create mode 100644 src/assets/python/http/strands/base/model/load.py rename src/assets/python/{ => http}/strands/base/pyproject.toml (100%) create mode 100644 src/assets/python/http/strands/capabilities/memory/__init__.py rename src/assets/python/{ => http}/strands/capabilities/memory/session.py (100%) create mode 100644 src/assets/python/mcp/standalone/base/README.md create mode 100644 src/assets/python/mcp/standalone/base/gitignore.template create mode 100644 src/assets/python/mcp/standalone/base/main.py create mode 100644 src/assets/python/mcp/standalone/base/pyproject.toml create mode 100644 src/cli/templates/McpRenderer.ts diff --git a/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap b/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap index 0e2f5950..893e08db 100644 --- a/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +++ b/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap @@ -438,54 +438,92 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f "mcp/python/README.md", "mcp/python/pyproject.toml", "mcp/python/server.py", - "python/autogen/base/README.md", - "python/autogen/base/gitignore.template", - "python/autogen/base/main.py", - "python/autogen/base/mcp_client/__init__.py", - "python/autogen/base/mcp_client/client.py", - "python/autogen/base/model/__init__.py", - "python/autogen/base/model/load.py", - "python/autogen/base/pyproject.toml", - "python/crewai/base/README.md", - "python/crewai/base/gitignore.template", - "python/crewai/base/main.py", - "python/crewai/base/model/__init__.py", - "python/crewai/base/model/load.py", - "python/crewai/base/pyproject.toml", - "python/googleadk/base/README.md", - "python/googleadk/base/gitignore.template", - "python/googleadk/base/main.py", - "python/googleadk/base/mcp_client/__init__.py", - "python/googleadk/base/mcp_client/client.py", - "python/googleadk/base/model/__init__.py", - "python/googleadk/base/model/load.py", - "python/googleadk/base/pyproject.toml", - "python/langchain_langgraph/base/README.md", - "python/langchain_langgraph/base/gitignore.template", - "python/langchain_langgraph/base/main.py", - "python/langchain_langgraph/base/mcp_client/__init__.py", - "python/langchain_langgraph/base/mcp_client/client.py", - "python/langchain_langgraph/base/model/__init__.py", - "python/langchain_langgraph/base/model/load.py", - "python/langchain_langgraph/base/pyproject.toml", - "python/openaiagents/base/README.md", - "python/openaiagents/base/gitignore.template", - "python/openaiagents/base/main.py", - "python/openaiagents/base/mcp_client/__init__.py", - "python/openaiagents/base/mcp_client/client.py", - "python/openaiagents/base/model/__init__.py", - "python/openaiagents/base/model/load.py", - "python/openaiagents/base/pyproject.toml", - "python/strands/base/README.md", - "python/strands/base/gitignore.template", - "python/strands/base/main.py", - "python/strands/base/mcp_client/__init__.py", - "python/strands/base/mcp_client/client.py", - "python/strands/base/model/__init__.py", - "python/strands/base/model/load.py", - "python/strands/base/pyproject.toml", - "python/strands/capabilities/memory/__init__.py", - "python/strands/capabilities/memory/session.py", + "python/a2a/googleadk/base/README.md", + "python/a2a/googleadk/base/gitignore.template", + "python/a2a/googleadk/base/main.py", + "python/a2a/googleadk/base/model/load.py", + "python/a2a/googleadk/base/pyproject.toml", + "python/a2a/langchain_langgraph/base/README.md", + "python/a2a/langchain_langgraph/base/gitignore.template", + "python/a2a/langchain_langgraph/base/main.py", + "python/a2a/langchain_langgraph/base/model/load.py", + "python/a2a/langchain_langgraph/base/pyproject.toml", + "python/a2a/strands/base/README.md", + "python/a2a/strands/base/gitignore.template", + "python/a2a/strands/base/main.py", + "python/a2a/strands/base/model/load.py", + "python/a2a/strands/base/pyproject.toml", + "python/a2a/strands/capabilities/memory/__init__.py", + "python/a2a/strands/capabilities/memory/session.py", + "python/agui/googleadk/base/README.md", + "python/agui/googleadk/base/gitignore.template", + "python/agui/googleadk/base/main.py", + "python/agui/googleadk/base/model/load.py", + "python/agui/googleadk/base/pyproject.toml", + "python/agui/langchain_langgraph/base/README.md", + "python/agui/langchain_langgraph/base/gitignore.template", + "python/agui/langchain_langgraph/base/main.py", + "python/agui/langchain_langgraph/base/model/load.py", + "python/agui/langchain_langgraph/base/pyproject.toml", + "python/agui/strands/base/README.md", + "python/agui/strands/base/gitignore.template", + "python/agui/strands/base/main.py", + "python/agui/strands/base/model/load.py", + "python/agui/strands/base/pyproject.toml", + "python/agui/strands/capabilities/memory/__init__.py", + "python/agui/strands/capabilities/memory/session.py", + "python/http/autogen/base/README.md", + "python/http/autogen/base/gitignore.template", + "python/http/autogen/base/main.py", + "python/http/autogen/base/mcp_client/__init__.py", + "python/http/autogen/base/mcp_client/client.py", + "python/http/autogen/base/model/__init__.py", + "python/http/autogen/base/model/load.py", + "python/http/autogen/base/pyproject.toml", + "python/http/crewai/base/README.md", + "python/http/crewai/base/gitignore.template", + "python/http/crewai/base/main.py", + "python/http/crewai/base/model/__init__.py", + "python/http/crewai/base/model/load.py", + "python/http/crewai/base/pyproject.toml", + "python/http/googleadk/base/README.md", + "python/http/googleadk/base/gitignore.template", + "python/http/googleadk/base/main.py", + "python/http/googleadk/base/mcp_client/__init__.py", + "python/http/googleadk/base/mcp_client/client.py", + "python/http/googleadk/base/model/__init__.py", + "python/http/googleadk/base/model/load.py", + "python/http/googleadk/base/pyproject.toml", + "python/http/langchain_langgraph/base/README.md", + "python/http/langchain_langgraph/base/gitignore.template", + "python/http/langchain_langgraph/base/main.py", + "python/http/langchain_langgraph/base/mcp_client/__init__.py", + "python/http/langchain_langgraph/base/mcp_client/client.py", + "python/http/langchain_langgraph/base/model/__init__.py", + "python/http/langchain_langgraph/base/model/load.py", + "python/http/langchain_langgraph/base/pyproject.toml", + "python/http/openaiagents/base/README.md", + "python/http/openaiagents/base/gitignore.template", + "python/http/openaiagents/base/main.py", + "python/http/openaiagents/base/mcp_client/__init__.py", + "python/http/openaiagents/base/mcp_client/client.py", + "python/http/openaiagents/base/model/__init__.py", + "python/http/openaiagents/base/model/load.py", + "python/http/openaiagents/base/pyproject.toml", + "python/http/strands/base/README.md", + "python/http/strands/base/gitignore.template", + "python/http/strands/base/main.py", + "python/http/strands/base/mcp_client/__init__.py", + "python/http/strands/base/mcp_client/client.py", + "python/http/strands/base/model/__init__.py", + "python/http/strands/base/model/load.py", + "python/http/strands/base/pyproject.toml", + "python/http/strands/capabilities/memory/__init__.py", + "python/http/strands/capabilities/memory/session.py", + "python/mcp/standalone/base/README.md", + "python/mcp/standalone/base/gitignore.template", + "python/mcp/standalone/base/main.py", + "python/mcp/standalone/base/pyproject.toml", "typescript/.gitkeep", ] `; @@ -861,7 +899,1486 @@ packages = ["."] " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/README.md should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/README.md should match snapshot 1`] = ` +"# {{ name }} + +An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using Google ADK. + +## Overview + +This agent implements the A2A protocol using Google's Agent Development Kit, enabling agent-to-agent communication. + +## Local Development + +\`\`\`bash +uv sync +uv run python main.py +\`\`\` + +The agent starts on port 9000. + +## Deploy + +\`\`\`bash +agentcore deploy +\`\`\` +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/gitignore.template should match snapshot 1`] = ` +"# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/main.py should match snapshot 1`] = ` +"import uvicorn +from google.adk.agents import Agent +from google.adk.a2a import A2AServer +from model.load import load_model + + +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +agent = Agent( + model=load_model(), + name="{{ name }}", + instruction="You are a helpful assistant. Use tools when appropriate.", + tools=[add_numbers], +) + +a2a_server = A2AServer(agent) + +if __name__ == "__main__": + uvicorn.run(a2a_server.app, host="0.0.0.0", port=9000) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/model/load.py should match snapshot 1`] = ` +"import os +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> None: + """ + Set up Gemini API key authentication. + Uses AgentCore Identity for API key management in deployed environments, + and falls back to .env file for local development. + Sets the GOOGLE_API_KEY environment variable for the Google ADK. + """ + api_key = _get_api_key() + # Use Google AI Studios API Key Authentication. + # https://google.github.io/adk-docs/agents/models/#google-ai-studio + os.environ["GOOGLE_API_KEY"] = api_key + # Set to TRUE is using Google Vertex AI, Set to FALSE for Google AI Studio + os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "FALSE" +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/googleadk/base/pyproject.toml should match snapshot 1`] = ` +"[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore A2A Agent using Google ADK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "google-adk[a2a] >= 1.0.0", + "google-genai >= 1.0.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/README.md should match snapshot 1`] = ` +"# {{ name }} + +An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using LangChain + LangGraph. + +## Overview + +This agent implements the A2A protocol using LangGraph, enabling agent-to-agent communication. + +## Local Development + +\`\`\`bash +uv sync +uv run python main.py +\`\`\` + +The agent starts on port 9000. + +## Deploy + +\`\`\`bash +agentcore deploy +\`\`\` +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/gitignore.template should match snapshot 1`] = ` +"# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/main.py should match snapshot 1`] = ` +"import uvicorn +from langchain_core.tools import tool +from langgraph.prebuilt import create_react_agent +from copilotkit.langgraph import copilotkit_messages_to_langchain +from langgraph_a2a import LangGraphA2AServer +from model.load import load_model + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +model = load_model() +agent = create_react_agent(model, tools=[add_numbers]) +a2a_server = LangGraphA2AServer(agent) + +if __name__ == "__main__": + uvicorn.run(a2a_server.app, host="0.0.0.0", port=9000) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/model/load.py should match snapshot 1`] = ` +"{{#if (eq modelProvider "Bedrock")}} +from langchain_aws import ChatBedrock + +# Uses global inference profile for Claude Sonnet 4.5 +# https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html +MODEL_ID = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" + + +def load_model() -> ChatBedrock: + """Get Bedrock model client using IAM credentials.""" + return ChatBedrock(model_id=MODEL_ID) +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os +from langchain_anthropic import ChatAnthropic +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatAnthropic: + """Get authenticated Anthropic model client.""" + return ChatAnthropic( + model="claude-sonnet-4-5-20250929", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os +from langchain_openai import ChatOpenAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatOpenAI: + """Get authenticated OpenAI model client.""" + return ChatOpenAI( + model="gpt-4.1", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os +from langchain_google_genai import ChatGoogleGenerativeAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatGoogleGenerativeAI: + """Get authenticated Gemini model client.""" + return ChatGoogleGenerativeAI( + model="gemini-2.5-flash", + api_key=_get_api_key() + ) +{{/if}} +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/langchain_langgraph/base/pyproject.toml should match snapshot 1`] = ` +"[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore A2A Agent using LangChain + LangGraph" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"langchain-anthropic >= 0.3.0", + {{/if}}{{#if (eq modelProvider "Bedrock")}}"langchain-aws >= 0.2.0", + {{/if}}{{#if (eq modelProvider "Gemini")}}"langchain-google-genai >= 2.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", + {{/if}}"aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + "langgraph >= 0.2.0", + "langgraph-a2a >= 0.1.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/README.md should match snapshot 1`] = ` +"# {{ name }} + +An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using Strands SDK. + +## Overview + +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. + +## Local Development + +\`\`\`bash +uv sync +uv run python main.py +\`\`\` + +The agent starts on port 9000. + +## Deploy + +\`\`\`bash +agentcore deploy +\`\`\` +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/gitignore.template should match snapshot 1`] = ` +"# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/main.py should match snapshot 1`] = ` +"from strands import Agent, tool +from strands.agent.a2a import A2AAgent +from model.load import load_model +{{#if hasMemory}} +from memory.session import get_memory_session_manager +{{/if}} + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +tools = [add_numbers] + +{{#if hasMemory}} +def agent_factory(): + cache = {} + def get_or_create_agent(session_id, user_id): + key = f"{session_id}/{user_id}" + if key not in cache: + cache[key] = Agent( + model=load_model(), + session_manager=get_memory_session_manager(session_id, user_id), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, + ) + return cache[key] + return get_or_create_agent + +get_or_create_agent = agent_factory() +agent = get_or_create_agent("default-session", "default-user") +{{else}} +agent = Agent( + model=load_model(), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, +) +{{/if}} + +a2a_agent = A2AAgent(agent) + +if __name__ == "__main__": + import uvicorn + uvicorn.run(a2a_agent.app, host="0.0.0.0", port=9000) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/model/load.py should match snapshot 1`] = ` +"{{#if (eq modelProvider "Bedrock")}} +from strands.models.bedrock import BedrockModel + + +def load_model() -> BedrockModel: + """Get Bedrock model client using IAM credentials.""" + return BedrockModel(model_id="global.anthropic.claude-sonnet-4-5-20250929-v1:0") +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os + +from strands.models.anthropic import AnthropicModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> AnthropicModel: + """Get authenticated Anthropic model client.""" + return AnthropicModel( + client_args={"api_key": _get_api_key()}, + model_id="claude-sonnet-4-5-20250929", + max_tokens=5000, + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os + +from strands.models.openai import OpenAIModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> OpenAIModel: + """Get authenticated OpenAI model client.""" + return OpenAIModel( + client_args={"api_key": _get_api_key()}, + model_id="gpt-4.1", + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os + +from strands.models.gemini import GeminiModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> GeminiModel: + """Get authenticated Gemini model client.""" + return GeminiModel( + client_args={"api_key": _get_api_key()}, + model_id="gemini-2.5-flash", + ) +{{/if}} +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/base/pyproject.toml should match snapshot 1`] = ` +"[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore A2A Agent using Strands SDK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0", + {{/if}}"aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + {{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0", + {{/if}}"strands-agents[a2a] >= 1.13.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/capabilities/memory/__init__.py should match snapshot 1`] = ` +"# Package marker +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/a2a/strands/capabilities/memory/session.py should match snapshot 1`] = ` +"import os +from typing import Optional + +from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig{{#if memoryProviders.[0].strategies.length}}, RetrievalConfig{{/if}} +from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager + +MEMORY_ID = os.getenv("{{memoryProviders.[0].envVarName}}") +REGION = os.getenv("AWS_REGION") + +def get_memory_session_manager(session_id: str, actor_id: str) -> Optional[AgentCoreMemorySessionManager]: + if not MEMORY_ID: + return None + +{{#if memoryProviders.[0].strategies.length}} + retrieval_config = { +{{#if (includes memoryProviders.[0].strategies "SEMANTIC")}} + f"/users/{actor_id}/facts": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}} + f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}} + f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} + } +{{/if}} + + return AgentCoreMemorySessionManager( + AgentCoreMemoryConfig( + memory_id=MEMORY_ID, + session_id=session_id, + actor_id=actor_id, +{{#if memoryProviders.[0].strategies.length}} + retrieval_config=retrieval_config, +{{/if}} + ), + REGION + ) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/README.md should match snapshot 1`] = ` +"# {{ name }} + +An AG-UI agent deployed on Amazon Bedrock AgentCore using Google ADK. + +## Overview + +This agent implements the AG-UI protocol for rich frontend integrations with SSE event streaming. + +## Local Development + +\`\`\`bash +uv sync +uv run python main.py +\`\`\` + +The agent starts on port 8080. + +## Deploy + +\`\`\`bash +agentcore deploy +\`\`\` +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/gitignore.template should match snapshot 1`] = ` +"# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/main.py should match snapshot 1`] = ` +"import uvicorn +from google.adk.agents import Agent +from ag_ui_google_adk import GoogleADKAGUIServer +from model.load import load_model + + +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +agent = Agent( + model=load_model(), + name="{{ name }}", + instruction="You are a helpful assistant. Use tools when appropriate.", + tools=[add_numbers], +) + +agui_server = GoogleADKAGUIServer(agent) + +if __name__ == "__main__": + uvicorn.run(agui_server.app, host="0.0.0.0", port=8080) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/model/load.py should match snapshot 1`] = ` +"import os +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> None: + """ + Set up Gemini API key authentication. + Uses AgentCore Identity for API key management in deployed environments, + and falls back to .env file for local development. + Sets the GOOGLE_API_KEY environment variable for the Google ADK. + """ + api_key = _get_api_key() + # Use Google AI Studios API Key Authentication. + # https://google.github.io/adk-docs/agents/models/#google-ai-studio + os.environ["GOOGLE_API_KEY"] = api_key + # Set to TRUE is using Google Vertex AI, Set to FALSE for Google AI Studio + os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "FALSE" +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/googleadk/base/pyproject.toml should match snapshot 1`] = ` +"[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore AG-UI Agent using Google ADK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "ag-ui-google-adk", + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "google-adk >= 1.0.0", + "google-genai >= 1.0.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/README.md should match snapshot 1`] = ` +"# {{ name }} + +An AG-UI agent deployed on Amazon Bedrock AgentCore using LangChain + LangGraph. + +## Overview + +This agent implements the AG-UI protocol for rich frontend integrations with SSE event streaming. + +## Local Development + +\`\`\`bash +uv sync +uv run python main.py +\`\`\` + +The agent starts on port 8080. + +## Deploy + +\`\`\`bash +agentcore deploy +\`\`\` +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/gitignore.template should match snapshot 1`] = ` +"# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/main.py should match snapshot 1`] = ` +"import uvicorn +from langchain_core.tools import tool +from langgraph.prebuilt import create_react_agent +from ag_ui_langgraph import LangGraphAGUIServer +from model.load import load_model + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +model = load_model() +agent = create_react_agent(model, tools=[add_numbers]) +agui_server = LangGraphAGUIServer(agent) + +if __name__ == "__main__": + uvicorn.run(agui_server.app, host="0.0.0.0", port=8080) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/model/load.py should match snapshot 1`] = ` +"{{#if (eq modelProvider "Bedrock")}} +from langchain_aws import ChatBedrock + +# Uses global inference profile for Claude Sonnet 4.5 +# https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html +MODEL_ID = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" + + +def load_model() -> ChatBedrock: + """Get Bedrock model client using IAM credentials.""" + return ChatBedrock(model_id=MODEL_ID) +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os +from langchain_anthropic import ChatAnthropic +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatAnthropic: + """Get authenticated Anthropic model client.""" + return ChatAnthropic( + model="claude-sonnet-4-5-20250929", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os +from langchain_openai import ChatOpenAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatOpenAI: + """Get authenticated OpenAI model client.""" + return ChatOpenAI( + model="gpt-4.1", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os +from langchain_google_genai import ChatGoogleGenerativeAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatGoogleGenerativeAI: + """Get authenticated Gemini model client.""" + return ChatGoogleGenerativeAI( + model="gemini-2.5-flash", + api_key=_get_api_key() + ) +{{/if}} +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/langchain_langgraph/base/pyproject.toml should match snapshot 1`] = ` +"[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore AG-UI Agent using LangChain + LangGraph" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"langchain-anthropic >= 0.3.0", + {{/if}}{{#if (eq modelProvider "Bedrock")}}"langchain-aws >= 0.2.0", + {{/if}}{{#if (eq modelProvider "Gemini")}}"langchain-google-genai >= 2.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", + {{/if}}"ag-ui-langgraph", + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + "langgraph >= 0.2.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/README.md should match snapshot 1`] = ` +"# {{ name }} + +An AG-UI agent deployed on Amazon Bedrock AgentCore using Strands SDK. + +## Overview + +This agent implements the AG-UI protocol, enabling rich frontend integrations with SSE event streaming (RUN_STARTED, TEXT_MESSAGE_CONTENT, RUN_FINISHED). + +## Local Development + +\`\`\`bash +uv sync +uv run python main.py +\`\`\` + +The agent starts on port 8080. + +## Deploy + +\`\`\`bash +agentcore deploy +\`\`\` +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/gitignore.template should match snapshot 1`] = ` +"# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/main.py should match snapshot 1`] = ` +"from strands import Agent, tool +from ag_ui_strands import StrandsA2AServer +from model.load import load_model +{{#if hasMemory}} +from memory.session import get_memory_session_manager +{{/if}} + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +tools = [add_numbers] + +{{#if hasMemory}} +def agent_factory(): + cache = {} + def get_or_create_agent(session_id, user_id): + key = f"{session_id}/{user_id}" + if key not in cache: + cache[key] = Agent( + model=load_model(), + session_manager=get_memory_session_manager(session_id, user_id), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, + ) + return cache[key] + return get_or_create_agent + +get_or_create_agent = agent_factory() +agent = get_or_create_agent("default-session", "default-user") +{{else}} +agent = Agent( + model=load_model(), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, +) +{{/if}} + +agui_server = StrandsA2AServer(agent) + +if __name__ == "__main__": + import uvicorn + uvicorn.run(agui_server.app, host="0.0.0.0", port=8080) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/model/load.py should match snapshot 1`] = ` +"{{#if (eq modelProvider "Bedrock")}} +from strands.models.bedrock import BedrockModel + + +def load_model() -> BedrockModel: + """Get Bedrock model client using IAM credentials.""" + return BedrockModel(model_id="global.anthropic.claude-sonnet-4-5-20250929-v1:0") +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os + +from strands.models.anthropic import AnthropicModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> AnthropicModel: + """Get authenticated Anthropic model client.""" + return AnthropicModel( + client_args={"api_key": _get_api_key()}, + model_id="claude-sonnet-4-5-20250929", + max_tokens=5000, + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os + +from strands.models.openai import OpenAIModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> OpenAIModel: + """Get authenticated OpenAI model client.""" + return OpenAIModel( + client_args={"api_key": _get_api_key()}, + model_id="gpt-4.1", + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os + +from strands.models.gemini import GeminiModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> GeminiModel: + """Get authenticated Gemini model client.""" + return GeminiModel( + client_args={"api_key": _get_api_key()}, + model_id="gemini-2.5-flash", + ) +{{/if}} +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/base/pyproject.toml should match snapshot 1`] = ` +"[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore AG-UI Agent using Strands SDK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0", + {{/if}}"ag-ui-strands", + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + {{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0", + {{/if}}"strands-agents >= 1.13.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/capabilities/memory/__init__.py should match snapshot 1`] = ` +"# Package marker +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/agui/strands/capabilities/memory/session.py should match snapshot 1`] = ` +"import os +from typing import Optional + +from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig{{#if memoryProviders.[0].strategies.length}}, RetrievalConfig{{/if}} +from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager + +MEMORY_ID = os.getenv("{{memoryProviders.[0].envVarName}}") +REGION = os.getenv("AWS_REGION") + +def get_memory_session_manager(session_id: str, actor_id: str) -> Optional[AgentCoreMemorySessionManager]: + if not MEMORY_ID: + return None + +{{#if memoryProviders.[0].strategies.length}} + retrieval_config = { +{{#if (includes memoryProviders.[0].strategies "SEMANTIC")}} + f"/users/{actor_id}/facts": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}} + f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}} + f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} + } +{{/if}} + + return AgentCoreMemorySessionManager( + AgentCoreMemoryConfig( + memory_id=MEMORY_ID, + session_id=session_id, + actor_id=actor_id, +{{#if memoryProviders.[0].strategies.length}} + retrieval_config=retrieval_config, +{{/if}} + ), + REGION + ) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/README.md should match snapshot 1`] = ` "This is a project generated by the agentcore create CLI tool! # Layout @@ -904,7 +2421,7 @@ Use \`agentcore invoke\` to invoke your deployed agent. " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/gitignore.template should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/gitignore.template should match snapshot 1`] = ` "# Environment variables .env @@ -949,7 +2466,7 @@ Thumbs.db " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/main.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/main.py should match snapshot 1`] = ` "import os from autogen_agentchat.agents import AssistantAgent from autogen_core.tools import FunctionTool @@ -1005,12 +2522,12 @@ if __name__ == "__main__": " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/mcp_client/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/mcp_client/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/mcp_client/client.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/mcp_client/client.py should match snapshot 1`] = ` "from typing import List from autogen_ext.tools.mcp import ( StreamableHttpMcpToolAdapter, @@ -1032,12 +2549,12 @@ async def get_streamable_http_mcp_tools() -> List[StreamableHttpMcpToolAdapter]: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/model/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/model/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/model/load.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/model/load.py should match snapshot 1`] = ` "{{#if (eq modelProvider "Bedrock")}} import os from autogen_ext.models.anthropic import AnthropicBedrockChatCompletionClient @@ -1177,7 +2694,7 @@ def load_model() -> OpenAIChatCompletionClient: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/autogen/base/pyproject.toml should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/autogen/base/pyproject.toml should match snapshot 1`] = ` "[build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -1215,7 +2732,7 @@ packages = ["."] " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/crewai/base/README.md should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/crewai/base/README.md should match snapshot 1`] = ` "This is a project generated by the agentcore create CLI tool! # Layout @@ -1258,7 +2775,7 @@ Use \`agentcore invoke\` to invoke your deployed agent. " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/crewai/base/gitignore.template should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/crewai/base/gitignore.template should match snapshot 1`] = ` "# Environment variables .env @@ -1303,7 +2820,7 @@ Thumbs.db " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/crewai/base/main.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/crewai/base/main.py should match snapshot 1`] = ` "from crewai import Agent, Crew, Task, Process from crewai.tools import tool from bedrock_agentcore.runtime import BedrockAgentCoreApp @@ -1362,12 +2879,12 @@ if __name__ == "__main__": " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/crewai/base/model/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/crewai/base/model/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/crewai/base/model/load.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/crewai/base/model/load.py should match snapshot 1`] = ` "{{#if (eq modelProvider "Bedrock")}} from crewai import LLM @@ -1504,7 +3021,7 @@ def load_model() -> LLM: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/crewai/base/pyproject.toml should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/crewai/base/pyproject.toml should match snapshot 1`] = ` "[build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -1539,7 +3056,7 @@ packages = ["."] " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/README.md should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/README.md should match snapshot 1`] = ` "This is a project generated by the agentcore create CLI tool! # Layout @@ -1582,7 +3099,7 @@ Use \`agentcore invoke\` to invoke your deployed agent. " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/gitignore.template should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/gitignore.template should match snapshot 1`] = ` "# Environment variables .env @@ -1627,7 +3144,7 @@ Thumbs.db " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/main.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/main.py should match snapshot 1`] = ` "import os from google.adk.agents import Agent from google.adk.runners import Runner @@ -1731,12 +3248,12 @@ if __name__ == "__main__": " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/mcp_client/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/mcp_client/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/mcp_client/client.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/mcp_client/client.py should match snapshot 1`] = ` "import os import logging from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset @@ -1806,12 +3323,12 @@ def get_streamable_http_mcp_client() -> MCPToolset: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/model/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/model/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/model/load.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/model/load.py should match snapshot 1`] = ` "import os from bedrock_agentcore.identity.auth import requires_api_key @@ -1856,7 +3373,7 @@ def load_model() -> None: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/googleadk/base/pyproject.toml should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/googleadk/base/pyproject.toml should match snapshot 1`] = ` "[build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -1882,7 +3399,7 @@ packages = ["."] " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/README.md should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/README.md should match snapshot 1`] = ` "This is a project generated by the agentcore create CLI tool! # Layout @@ -1925,7 +3442,7 @@ Use \`agentcore invoke\` to invoke your deployed agent. " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/gitignore.template should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/gitignore.template should match snapshot 1`] = ` "# Environment variables .env @@ -1970,7 +3487,7 @@ Thumbs.db " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/main.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/main.py should match snapshot 1`] = ` "import os from langchain_core.messages import HumanMessage from langgraph.prebuilt import create_react_agent @@ -2040,12 +3557,12 @@ if __name__ == "__main__": " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/mcp_client/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/mcp_client/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/mcp_client/client.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/mcp_client/client.py should match snapshot 1`] = ` "import os import logging from langchain_mcp_adapters.client import MultiServerMCPClient @@ -2117,12 +3634,12 @@ def get_streamable_http_mcp_client() -> MultiServerMCPClient: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/model/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/model/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/model/load.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/model/load.py should match snapshot 1`] = ` "{{#if (eq modelProvider "Bedrock")}} from langchain_aws import ChatBedrock @@ -2249,7 +3766,7 @@ def load_model() -> ChatGoogleGenerativeAI: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/langchain_langgraph/base/pyproject.toml should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/langchain_langgraph/base/pyproject.toml should match snapshot 1`] = ` "[build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -2290,7 +3807,7 @@ packages = ["."] " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/README.md should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/README.md should match snapshot 1`] = ` "This is a project generated by the agentcore create CLI tool! # Layout @@ -2333,7 +3850,7 @@ Use \`agentcore invoke\` to invoke your deployed agent. " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/gitignore.template should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/gitignore.template should match snapshot 1`] = ` "# Environment variables .env @@ -2378,7 +3895,7 @@ Thumbs.db " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/main.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/main.py should match snapshot 1`] = ` "import os from agents import Agent, Runner, function_tool from bedrock_agentcore.runtime import BedrockAgentCoreApp @@ -2485,12 +4002,12 @@ if __name__ == "__main__": " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/mcp_client/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/mcp_client/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/mcp_client/client.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/mcp_client/client.py should match snapshot 1`] = ` "import os import logging from agents.mcp import MCPServerStreamableHttp @@ -2559,12 +4076,12 @@ def get_streamable_http_mcp_client() -> MCPServerStreamableHttp: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/model/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/model/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/model/load.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/model/load.py should match snapshot 1`] = ` "import os from bedrock_agentcore.identity.auth import requires_api_key @@ -2605,7 +4122,7 @@ def load_model() -> None: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/openaiagents/base/pyproject.toml should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/openaiagents/base/pyproject.toml should match snapshot 1`] = ` "[build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -2630,7 +4147,7 @@ packages = ["."] " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/README.md should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/README.md should match snapshot 1`] = ` "This is a project generated by the AgentCore CLI! # Layout @@ -2673,7 +4190,7 @@ Use \`agentcore invoke\` to invoke your deployed agent. " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/gitignore.template should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/gitignore.template should match snapshot 1`] = ` "# Environment variables .env @@ -2717,7 +4234,7 @@ env/ Thumbs.db" `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/main.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/main.py should match snapshot 1`] = ` "from strands import Agent, tool from bedrock_agentcore.runtime import BedrockAgentCoreApp from model.load import load_model @@ -2817,12 +4334,12 @@ if __name__ == "__main__": " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/mcp_client/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/mcp_client/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/mcp_client/client.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/mcp_client/client.py should match snapshot 1`] = ` "import os import logging from mcp.client.streamable_http import streamablehttp_client @@ -2890,12 +4407,12 @@ def get_streamable_http_mcp_client() -> MCPClient: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/model/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/model/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/model/load.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/model/load.py should match snapshot 1`] = ` "{{#if (eq modelProvider "Bedrock")}} from strands.models.bedrock import BedrockModel @@ -3022,7 +4539,7 @@ def load_model() -> GeminiModel: " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/base/pyproject.toml should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/base/pyproject.toml should match snapshot 1`] = ` "[build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -3051,12 +4568,12 @@ packages = ["."] " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/capabilities/memory/__init__.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/capabilities/memory/__init__.py should match snapshot 1`] = ` "# Package marker " `; -exports[`Assets Directory Snapshots > Python framework assets > python/python/strands/capabilities/memory/session.py should match snapshot 1`] = ` +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/capabilities/memory/session.py should match snapshot 1`] = ` "import os from typing import Optional @@ -3099,6 +4616,142 @@ def get_memory_session_manager(session_id: str, actor_id: str) -> Optional[Agent " `; +exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/README.md should match snapshot 1`] = ` +"# {{ name }} + +An MCP (Model Context Protocol) server deployed on Amazon Bedrock AgentCore. + +## Overview + +This project implements an MCP server using FastMCP. MCP servers expose tools that can be consumed by MCP clients (other agents or applications). + +## Local Development + +\`\`\`bash +# Install dependencies +uv sync + +# Run the MCP server locally +uv run python main.py +\`\`\` + +The server starts on port 8000 with Streamable HTTP transport. + +## Adding Tools + +Define tools using the \`@mcp.tool()\` decorator in \`main.py\`: + +\`\`\`python +@mcp.tool() +def my_tool(param: str) -> str: + """Description of what the tool does.""" + return f"Result: {param}" +\`\`\` + +## Deploy + +\`\`\`bash +agentcore deploy +\`\`\` +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/gitignore.template should match snapshot 1`] = ` +"# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/main.py should match snapshot 1`] = ` +"from mcp.server.fastmcp import FastMCP +import uvicorn + +mcp = FastMCP("{{ name }}") + + +@mcp.tool() +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +@mcp.tool() +def greet(name: str) -> str: + """Return a greeting for the given name.""" + return f"Hello, {name}!" + + +if __name__ == "__main__": + uvicorn.run( + mcp.streamable_http_app(), + host="0.0.0.0", + port=8000, + ) +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/pyproject.toml should match snapshot 1`] = ` +"[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore MCP Server" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "mcp >= 1.19.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] +" +`; + exports[`Assets Directory Snapshots > Root-level assets > AGENTS.md should match snapshot 1`] = ` "## AgentCore Templates diff --git a/src/assets/python/a2a/googleadk/base/README.md b/src/assets/python/a2a/googleadk/base/README.md new file mode 100644 index 00000000..03da54b6 --- /dev/null +++ b/src/assets/python/a2a/googleadk/base/README.md @@ -0,0 +1,22 @@ +# {{ name }} + +An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using Google ADK. + +## Overview + +This agent implements the A2A protocol using Google's Agent Development Kit, enabling agent-to-agent communication. + +## Local Development + +```bash +uv sync +uv run python main.py +``` + +The agent starts on port 9000. + +## Deploy + +```bash +agentcore deploy +``` diff --git a/src/assets/python/autogen/base/gitignore.template b/src/assets/python/a2a/googleadk/base/gitignore.template similarity index 100% rename from src/assets/python/autogen/base/gitignore.template rename to src/assets/python/a2a/googleadk/base/gitignore.template diff --git a/src/assets/python/a2a/googleadk/base/main.py b/src/assets/python/a2a/googleadk/base/main.py new file mode 100644 index 00000000..d5ab25fa --- /dev/null +++ b/src/assets/python/a2a/googleadk/base/main.py @@ -0,0 +1,22 @@ +import uvicorn +from google.adk.agents import Agent +from google.adk.a2a import A2AServer +from model.load import load_model + + +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +agent = Agent( + model=load_model(), + name="{{ name }}", + instruction="You are a helpful assistant. Use tools when appropriate.", + tools=[add_numbers], +) + +a2a_server = A2AServer(agent) + +if __name__ == "__main__": + uvicorn.run(a2a_server.app, host="0.0.0.0", port=9000) diff --git a/src/assets/python/googleadk/base/model/load.py b/src/assets/python/a2a/googleadk/base/model/load.py similarity index 100% rename from src/assets/python/googleadk/base/model/load.py rename to src/assets/python/a2a/googleadk/base/model/load.py diff --git a/src/assets/python/a2a/googleadk/base/pyproject.toml b/src/assets/python/a2a/googleadk/base/pyproject.toml new file mode 100644 index 00000000..43d37d39 --- /dev/null +++ b/src/assets/python/a2a/googleadk/base/pyproject.toml @@ -0,0 +1,20 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore A2A Agent using Google ADK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "google-adk[a2a] >= 1.0.0", + "google-genai >= 1.0.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] diff --git a/src/assets/python/a2a/langchain_langgraph/base/README.md b/src/assets/python/a2a/langchain_langgraph/base/README.md new file mode 100644 index 00000000..16476262 --- /dev/null +++ b/src/assets/python/a2a/langchain_langgraph/base/README.md @@ -0,0 +1,22 @@ +# {{ name }} + +An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using LangChain + LangGraph. + +## Overview + +This agent implements the A2A protocol using LangGraph, enabling agent-to-agent communication. + +## Local Development + +```bash +uv sync +uv run python main.py +``` + +The agent starts on port 9000. + +## Deploy + +```bash +agentcore deploy +``` diff --git a/src/assets/python/crewai/base/gitignore.template b/src/assets/python/a2a/langchain_langgraph/base/gitignore.template similarity index 100% rename from src/assets/python/crewai/base/gitignore.template rename to src/assets/python/a2a/langchain_langgraph/base/gitignore.template diff --git a/src/assets/python/a2a/langchain_langgraph/base/main.py b/src/assets/python/a2a/langchain_langgraph/base/main.py new file mode 100644 index 00000000..8bb39d7d --- /dev/null +++ b/src/assets/python/a2a/langchain_langgraph/base/main.py @@ -0,0 +1,20 @@ +import uvicorn +from langchain_core.tools import tool +from langgraph.prebuilt import create_react_agent +from copilotkit.langgraph import copilotkit_messages_to_langchain +from langgraph_a2a import LangGraphA2AServer +from model.load import load_model + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +model = load_model() +agent = create_react_agent(model, tools=[add_numbers]) +a2a_server = LangGraphA2AServer(agent) + +if __name__ == "__main__": + uvicorn.run(a2a_server.app, host="0.0.0.0", port=9000) diff --git a/src/assets/python/langchain_langgraph/base/model/load.py b/src/assets/python/a2a/langchain_langgraph/base/model/load.py similarity index 100% rename from src/assets/python/langchain_langgraph/base/model/load.py rename to src/assets/python/a2a/langchain_langgraph/base/model/load.py diff --git a/src/assets/python/a2a/langchain_langgraph/base/pyproject.toml b/src/assets/python/a2a/langchain_langgraph/base/pyproject.toml new file mode 100644 index 00000000..15cd6a46 --- /dev/null +++ b/src/assets/python/a2a/langchain_langgraph/base/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore A2A Agent using LangChain + LangGraph" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"langchain-anthropic >= 0.3.0", + {{/if}}{{#if (eq modelProvider "Bedrock")}}"langchain-aws >= 0.2.0", + {{/if}}{{#if (eq modelProvider "Gemini")}}"langchain-google-genai >= 2.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", + {{/if}}"aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + "langgraph >= 0.2.0", + "langgraph-a2a >= 0.1.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] diff --git a/src/assets/python/a2a/strands/base/README.md b/src/assets/python/a2a/strands/base/README.md new file mode 100644 index 00000000..a9d30cbb --- /dev/null +++ b/src/assets/python/a2a/strands/base/README.md @@ -0,0 +1,22 @@ +# {{ name }} + +An A2A (Agent-to-Agent) agent deployed on Amazon Bedrock AgentCore using Strands SDK. + +## Overview + +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. + +## Local Development + +```bash +uv sync +uv run python main.py +``` + +The agent starts on port 9000. + +## Deploy + +```bash +agentcore deploy +``` diff --git a/src/assets/python/googleadk/base/gitignore.template b/src/assets/python/a2a/strands/base/gitignore.template similarity index 100% rename from src/assets/python/googleadk/base/gitignore.template rename to src/assets/python/a2a/strands/base/gitignore.template diff --git a/src/assets/python/a2a/strands/base/main.py b/src/assets/python/a2a/strands/base/main.py new file mode 100644 index 00000000..873f5e7f --- /dev/null +++ b/src/assets/python/a2a/strands/base/main.py @@ -0,0 +1,46 @@ +from strands import Agent, tool +from strands.agent.a2a import A2AAgent +from model.load import load_model +{{#if hasMemory}} +from memory.session import get_memory_session_manager +{{/if}} + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +tools = [add_numbers] + +{{#if hasMemory}} +def agent_factory(): + cache = {} + def get_or_create_agent(session_id, user_id): + key = f"{session_id}/{user_id}" + if key not in cache: + cache[key] = Agent( + model=load_model(), + session_manager=get_memory_session_manager(session_id, user_id), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, + ) + return cache[key] + return get_or_create_agent + +get_or_create_agent = agent_factory() +agent = get_or_create_agent("default-session", "default-user") +{{else}} +agent = Agent( + model=load_model(), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, +) +{{/if}} + +a2a_agent = A2AAgent(agent) + +if __name__ == "__main__": + import uvicorn + uvicorn.run(a2a_agent.app, host="0.0.0.0", port=9000) diff --git a/src/assets/python/strands/base/model/load.py b/src/assets/python/a2a/strands/base/model/load.py similarity index 100% rename from src/assets/python/strands/base/model/load.py rename to src/assets/python/a2a/strands/base/model/load.py diff --git a/src/assets/python/a2a/strands/base/pyproject.toml b/src/assets/python/a2a/strands/base/pyproject.toml new file mode 100644 index 00000000..97ef0f97 --- /dev/null +++ b/src/assets/python/a2a/strands/base/pyproject.toml @@ -0,0 +1,23 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore A2A Agent using Strands SDK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0", + {{/if}}"aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + {{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0", + {{/if}}"strands-agents[a2a] >= 1.13.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] diff --git a/src/assets/python/autogen/base/mcp_client/__init__.py b/src/assets/python/a2a/strands/capabilities/memory/__init__.py similarity index 100% rename from src/assets/python/autogen/base/mcp_client/__init__.py rename to src/assets/python/a2a/strands/capabilities/memory/__init__.py diff --git a/src/assets/python/a2a/strands/capabilities/memory/session.py b/src/assets/python/a2a/strands/capabilities/memory/session.py new file mode 100644 index 00000000..9661243b --- /dev/null +++ b/src/assets/python/a2a/strands/capabilities/memory/session.py @@ -0,0 +1,38 @@ +import os +from typing import Optional + +from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig{{#if memoryProviders.[0].strategies.length}}, RetrievalConfig{{/if}} +from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager + +MEMORY_ID = os.getenv("{{memoryProviders.[0].envVarName}}") +REGION = os.getenv("AWS_REGION") + +def get_memory_session_manager(session_id: str, actor_id: str) -> Optional[AgentCoreMemorySessionManager]: + if not MEMORY_ID: + return None + +{{#if memoryProviders.[0].strategies.length}} + retrieval_config = { +{{#if (includes memoryProviders.[0].strategies "SEMANTIC")}} + f"/users/{actor_id}/facts": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}} + f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}} + f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} + } +{{/if}} + + return AgentCoreMemorySessionManager( + AgentCoreMemoryConfig( + memory_id=MEMORY_ID, + session_id=session_id, + actor_id=actor_id, +{{#if memoryProviders.[0].strategies.length}} + retrieval_config=retrieval_config, +{{/if}} + ), + REGION + ) diff --git a/src/assets/python/agui/googleadk/base/README.md b/src/assets/python/agui/googleadk/base/README.md new file mode 100644 index 00000000..fd6c753f --- /dev/null +++ b/src/assets/python/agui/googleadk/base/README.md @@ -0,0 +1,22 @@ +# {{ name }} + +An AG-UI agent deployed on Amazon Bedrock AgentCore using Google ADK. + +## Overview + +This agent implements the AG-UI protocol for rich frontend integrations with SSE event streaming. + +## Local Development + +```bash +uv sync +uv run python main.py +``` + +The agent starts on port 8080. + +## Deploy + +```bash +agentcore deploy +``` diff --git a/src/assets/python/langchain_langgraph/base/gitignore.template b/src/assets/python/agui/googleadk/base/gitignore.template similarity index 100% rename from src/assets/python/langchain_langgraph/base/gitignore.template rename to src/assets/python/agui/googleadk/base/gitignore.template diff --git a/src/assets/python/agui/googleadk/base/main.py b/src/assets/python/agui/googleadk/base/main.py new file mode 100644 index 00000000..180d1959 --- /dev/null +++ b/src/assets/python/agui/googleadk/base/main.py @@ -0,0 +1,22 @@ +import uvicorn +from google.adk.agents import Agent +from ag_ui_google_adk import GoogleADKAGUIServer +from model.load import load_model + + +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +agent = Agent( + model=load_model(), + name="{{ name }}", + instruction="You are a helpful assistant. Use tools when appropriate.", + tools=[add_numbers], +) + +agui_server = GoogleADKAGUIServer(agent) + +if __name__ == "__main__": + uvicorn.run(agui_server.app, host="0.0.0.0", port=8080) diff --git a/src/assets/python/agui/googleadk/base/model/load.py b/src/assets/python/agui/googleadk/base/model/load.py new file mode 100644 index 00000000..7c74e1ce --- /dev/null +++ b/src/assets/python/agui/googleadk/base/model/load.py @@ -0,0 +1,41 @@ +import os +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> None: + """ + Set up Gemini API key authentication. + Uses AgentCore Identity for API key management in deployed environments, + and falls back to .env file for local development. + Sets the GOOGLE_API_KEY environment variable for the Google ADK. + """ + api_key = _get_api_key() + # Use Google AI Studios API Key Authentication. + # https://google.github.io/adk-docs/agents/models/#google-ai-studio + os.environ["GOOGLE_API_KEY"] = api_key + # Set to TRUE is using Google Vertex AI, Set to FALSE for Google AI Studio + os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "FALSE" diff --git a/src/assets/python/agui/googleadk/base/pyproject.toml b/src/assets/python/agui/googleadk/base/pyproject.toml new file mode 100644 index 00000000..e120da41 --- /dev/null +++ b/src/assets/python/agui/googleadk/base/pyproject.toml @@ -0,0 +1,21 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore AG-UI Agent using Google ADK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "ag-ui-google-adk", + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "google-adk >= 1.0.0", + "google-genai >= 1.0.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] diff --git a/src/assets/python/agui/langchain_langgraph/base/README.md b/src/assets/python/agui/langchain_langgraph/base/README.md new file mode 100644 index 00000000..57af681b --- /dev/null +++ b/src/assets/python/agui/langchain_langgraph/base/README.md @@ -0,0 +1,22 @@ +# {{ name }} + +An AG-UI agent deployed on Amazon Bedrock AgentCore using LangChain + LangGraph. + +## Overview + +This agent implements the AG-UI protocol for rich frontend integrations with SSE event streaming. + +## Local Development + +```bash +uv sync +uv run python main.py +``` + +The agent starts on port 8080. + +## Deploy + +```bash +agentcore deploy +``` diff --git a/src/assets/python/openaiagents/base/gitignore.template b/src/assets/python/agui/langchain_langgraph/base/gitignore.template similarity index 100% rename from src/assets/python/openaiagents/base/gitignore.template rename to src/assets/python/agui/langchain_langgraph/base/gitignore.template diff --git a/src/assets/python/agui/langchain_langgraph/base/main.py b/src/assets/python/agui/langchain_langgraph/base/main.py new file mode 100644 index 00000000..eb84f2f1 --- /dev/null +++ b/src/assets/python/agui/langchain_langgraph/base/main.py @@ -0,0 +1,19 @@ +import uvicorn +from langchain_core.tools import tool +from langgraph.prebuilt import create_react_agent +from ag_ui_langgraph import LangGraphAGUIServer +from model.load import load_model + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +model = load_model() +agent = create_react_agent(model, tools=[add_numbers]) +agui_server = LangGraphAGUIServer(agent) + +if __name__ == "__main__": + uvicorn.run(agui_server.app, host="0.0.0.0", port=8080) diff --git a/src/assets/python/agui/langchain_langgraph/base/model/load.py b/src/assets/python/agui/langchain_langgraph/base/model/load.py new file mode 100644 index 00000000..b8f2d71e --- /dev/null +++ b/src/assets/python/agui/langchain_langgraph/base/model/load.py @@ -0,0 +1,123 @@ +{{#if (eq modelProvider "Bedrock")}} +from langchain_aws import ChatBedrock + +# Uses global inference profile for Claude Sonnet 4.5 +# https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html +MODEL_ID = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" + + +def load_model() -> ChatBedrock: + """Get Bedrock model client using IAM credentials.""" + return ChatBedrock(model_id=MODEL_ID) +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os +from langchain_anthropic import ChatAnthropic +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatAnthropic: + """Get authenticated Anthropic model client.""" + return ChatAnthropic( + model="claude-sonnet-4-5-20250929", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os +from langchain_openai import ChatOpenAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatOpenAI: + """Get authenticated OpenAI model client.""" + return ChatOpenAI( + model="gpt-4.1", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os +from langchain_google_genai import ChatGoogleGenerativeAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatGoogleGenerativeAI: + """Get authenticated Gemini model client.""" + return ChatGoogleGenerativeAI( + model="gemini-2.5-flash", + api_key=_get_api_key() + ) +{{/if}} diff --git a/src/assets/python/agui/langchain_langgraph/base/pyproject.toml b/src/assets/python/agui/langchain_langgraph/base/pyproject.toml new file mode 100644 index 00000000..fd3bfcb2 --- /dev/null +++ b/src/assets/python/agui/langchain_langgraph/base/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore AG-UI Agent using LangChain + LangGraph" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"langchain-anthropic >= 0.3.0", + {{/if}}{{#if (eq modelProvider "Bedrock")}}"langchain-aws >= 0.2.0", + {{/if}}{{#if (eq modelProvider "Gemini")}}"langchain-google-genai >= 2.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", + {{/if}}"ag-ui-langgraph", + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + "langgraph >= 0.2.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] diff --git a/src/assets/python/agui/strands/base/README.md b/src/assets/python/agui/strands/base/README.md new file mode 100644 index 00000000..d8b81872 --- /dev/null +++ b/src/assets/python/agui/strands/base/README.md @@ -0,0 +1,22 @@ +# {{ name }} + +An AG-UI agent deployed on Amazon Bedrock AgentCore using Strands SDK. + +## Overview + +This agent implements the AG-UI protocol, enabling rich frontend integrations with SSE event streaming (RUN_STARTED, TEXT_MESSAGE_CONTENT, RUN_FINISHED). + +## Local Development + +```bash +uv sync +uv run python main.py +``` + +The agent starts on port 8080. + +## Deploy + +```bash +agentcore deploy +``` diff --git a/src/assets/python/agui/strands/base/gitignore.template b/src/assets/python/agui/strands/base/gitignore.template new file mode 100644 index 00000000..fa1c60ae --- /dev/null +++ b/src/assets/python/agui/strands/base/gitignore.template @@ -0,0 +1,41 @@ +# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/src/assets/python/agui/strands/base/main.py b/src/assets/python/agui/strands/base/main.py new file mode 100644 index 00000000..f5313ac7 --- /dev/null +++ b/src/assets/python/agui/strands/base/main.py @@ -0,0 +1,46 @@ +from strands import Agent, tool +from ag_ui_strands import StrandsA2AServer +from model.load import load_model +{{#if hasMemory}} +from memory.session import get_memory_session_manager +{{/if}} + + +@tool +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +tools = [add_numbers] + +{{#if hasMemory}} +def agent_factory(): + cache = {} + def get_or_create_agent(session_id, user_id): + key = f"{session_id}/{user_id}" + if key not in cache: + cache[key] = Agent( + model=load_model(), + session_manager=get_memory_session_manager(session_id, user_id), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, + ) + return cache[key] + return get_or_create_agent + +get_or_create_agent = agent_factory() +agent = get_or_create_agent("default-session", "default-user") +{{else}} +agent = Agent( + model=load_model(), + system_prompt="You are a helpful assistant. Use tools when appropriate.", + tools=tools, +) +{{/if}} + +agui_server = StrandsA2AServer(agent) + +if __name__ == "__main__": + import uvicorn + uvicorn.run(agui_server.app, host="0.0.0.0", port=8080) diff --git a/src/assets/python/agui/strands/base/model/load.py b/src/assets/python/agui/strands/base/model/load.py new file mode 100644 index 00000000..8954269e --- /dev/null +++ b/src/assets/python/agui/strands/base/model/load.py @@ -0,0 +1,123 @@ +{{#if (eq modelProvider "Bedrock")}} +from strands.models.bedrock import BedrockModel + + +def load_model() -> BedrockModel: + """Get Bedrock model client using IAM credentials.""" + return BedrockModel(model_id="global.anthropic.claude-sonnet-4-5-20250929-v1:0") +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os + +from strands.models.anthropic import AnthropicModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> AnthropicModel: + """Get authenticated Anthropic model client.""" + return AnthropicModel( + client_args={"api_key": _get_api_key()}, + model_id="claude-sonnet-4-5-20250929", + max_tokens=5000, + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os + +from strands.models.openai import OpenAIModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> OpenAIModel: + """Get authenticated OpenAI model client.""" + return OpenAIModel( + client_args={"api_key": _get_api_key()}, + model_id="gpt-4.1", + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os + +from strands.models.gemini import GeminiModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> GeminiModel: + """Get authenticated Gemini model client.""" + return GeminiModel( + client_args={"api_key": _get_api_key()}, + model_id="gemini-2.5-flash", + ) +{{/if}} diff --git a/src/assets/python/agui/strands/base/pyproject.toml b/src/assets/python/agui/strands/base/pyproject.toml new file mode 100644 index 00000000..55615558 --- /dev/null +++ b/src/assets/python/agui/strands/base/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore AG-UI Agent using Strands SDK" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + {{#if (eq modelProvider "Anthropic")}}"anthropic >= 0.30.0", + {{/if}}"ag-ui-strands", + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "botocore[crt] >= 1.35.0", + {{#if (eq modelProvider "Gemini")}}"google-genai >= 1.0.0", + {{/if}}{{#if (eq modelProvider "OpenAI")}}"openai >= 1.0.0", + {{/if}}"strands-agents >= 1.13.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] diff --git a/src/assets/python/autogen/base/model/__init__.py b/src/assets/python/agui/strands/capabilities/memory/__init__.py similarity index 100% rename from src/assets/python/autogen/base/model/__init__.py rename to src/assets/python/agui/strands/capabilities/memory/__init__.py diff --git a/src/assets/python/agui/strands/capabilities/memory/session.py b/src/assets/python/agui/strands/capabilities/memory/session.py new file mode 100644 index 00000000..9661243b --- /dev/null +++ b/src/assets/python/agui/strands/capabilities/memory/session.py @@ -0,0 +1,38 @@ +import os +from typing import Optional + +from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig{{#if memoryProviders.[0].strategies.length}}, RetrievalConfig{{/if}} +from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager + +MEMORY_ID = os.getenv("{{memoryProviders.[0].envVarName}}") +REGION = os.getenv("AWS_REGION") + +def get_memory_session_manager(session_id: str, actor_id: str) -> Optional[AgentCoreMemorySessionManager]: + if not MEMORY_ID: + return None + +{{#if memoryProviders.[0].strategies.length}} + retrieval_config = { +{{#if (includes memoryProviders.[0].strategies "SEMANTIC")}} + f"/users/{actor_id}/facts": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}} + f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} +{{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}} + f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5), +{{/if}} + } +{{/if}} + + return AgentCoreMemorySessionManager( + AgentCoreMemoryConfig( + memory_id=MEMORY_ID, + session_id=session_id, + actor_id=actor_id, +{{#if memoryProviders.[0].strategies.length}} + retrieval_config=retrieval_config, +{{/if}} + ), + REGION + ) diff --git a/src/assets/python/autogen/base/README.md b/src/assets/python/http/autogen/base/README.md similarity index 100% rename from src/assets/python/autogen/base/README.md rename to src/assets/python/http/autogen/base/README.md diff --git a/src/assets/python/http/autogen/base/gitignore.template b/src/assets/python/http/autogen/base/gitignore.template new file mode 100644 index 00000000..fa1c60ae --- /dev/null +++ b/src/assets/python/http/autogen/base/gitignore.template @@ -0,0 +1,41 @@ +# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/src/assets/python/autogen/base/main.py b/src/assets/python/http/autogen/base/main.py similarity index 100% rename from src/assets/python/autogen/base/main.py rename to src/assets/python/http/autogen/base/main.py diff --git a/src/assets/python/crewai/base/model/__init__.py b/src/assets/python/http/autogen/base/mcp_client/__init__.py similarity index 100% rename from src/assets/python/crewai/base/model/__init__.py rename to src/assets/python/http/autogen/base/mcp_client/__init__.py diff --git a/src/assets/python/autogen/base/mcp_client/client.py b/src/assets/python/http/autogen/base/mcp_client/client.py similarity index 100% rename from src/assets/python/autogen/base/mcp_client/client.py rename to src/assets/python/http/autogen/base/mcp_client/client.py diff --git a/src/assets/python/googleadk/base/mcp_client/__init__.py b/src/assets/python/http/autogen/base/model/__init__.py similarity index 100% rename from src/assets/python/googleadk/base/mcp_client/__init__.py rename to src/assets/python/http/autogen/base/model/__init__.py diff --git a/src/assets/python/autogen/base/model/load.py b/src/assets/python/http/autogen/base/model/load.py similarity index 100% rename from src/assets/python/autogen/base/model/load.py rename to src/assets/python/http/autogen/base/model/load.py diff --git a/src/assets/python/autogen/base/pyproject.toml b/src/assets/python/http/autogen/base/pyproject.toml similarity index 100% rename from src/assets/python/autogen/base/pyproject.toml rename to src/assets/python/http/autogen/base/pyproject.toml diff --git a/src/assets/python/crewai/base/README.md b/src/assets/python/http/crewai/base/README.md similarity index 100% rename from src/assets/python/crewai/base/README.md rename to src/assets/python/http/crewai/base/README.md diff --git a/src/assets/python/http/crewai/base/gitignore.template b/src/assets/python/http/crewai/base/gitignore.template new file mode 100644 index 00000000..fa1c60ae --- /dev/null +++ b/src/assets/python/http/crewai/base/gitignore.template @@ -0,0 +1,41 @@ +# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/src/assets/python/crewai/base/main.py b/src/assets/python/http/crewai/base/main.py similarity index 100% rename from src/assets/python/crewai/base/main.py rename to src/assets/python/http/crewai/base/main.py diff --git a/src/assets/python/googleadk/base/model/__init__.py b/src/assets/python/http/crewai/base/model/__init__.py similarity index 100% rename from src/assets/python/googleadk/base/model/__init__.py rename to src/assets/python/http/crewai/base/model/__init__.py diff --git a/src/assets/python/crewai/base/model/load.py b/src/assets/python/http/crewai/base/model/load.py similarity index 100% rename from src/assets/python/crewai/base/model/load.py rename to src/assets/python/http/crewai/base/model/load.py diff --git a/src/assets/python/crewai/base/pyproject.toml b/src/assets/python/http/crewai/base/pyproject.toml similarity index 100% rename from src/assets/python/crewai/base/pyproject.toml rename to src/assets/python/http/crewai/base/pyproject.toml diff --git a/src/assets/python/googleadk/base/README.md b/src/assets/python/http/googleadk/base/README.md similarity index 100% rename from src/assets/python/googleadk/base/README.md rename to src/assets/python/http/googleadk/base/README.md diff --git a/src/assets/python/http/googleadk/base/gitignore.template b/src/assets/python/http/googleadk/base/gitignore.template new file mode 100644 index 00000000..fa1c60ae --- /dev/null +++ b/src/assets/python/http/googleadk/base/gitignore.template @@ -0,0 +1,41 @@ +# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/src/assets/python/googleadk/base/main.py b/src/assets/python/http/googleadk/base/main.py similarity index 100% rename from src/assets/python/googleadk/base/main.py rename to src/assets/python/http/googleadk/base/main.py diff --git a/src/assets/python/langchain_langgraph/base/mcp_client/__init__.py b/src/assets/python/http/googleadk/base/mcp_client/__init__.py similarity index 100% rename from src/assets/python/langchain_langgraph/base/mcp_client/__init__.py rename to src/assets/python/http/googleadk/base/mcp_client/__init__.py diff --git a/src/assets/python/googleadk/base/mcp_client/client.py b/src/assets/python/http/googleadk/base/mcp_client/client.py similarity index 100% rename from src/assets/python/googleadk/base/mcp_client/client.py rename to src/assets/python/http/googleadk/base/mcp_client/client.py diff --git a/src/assets/python/langchain_langgraph/base/model/__init__.py b/src/assets/python/http/googleadk/base/model/__init__.py similarity index 100% rename from src/assets/python/langchain_langgraph/base/model/__init__.py rename to src/assets/python/http/googleadk/base/model/__init__.py diff --git a/src/assets/python/http/googleadk/base/model/load.py b/src/assets/python/http/googleadk/base/model/load.py new file mode 100644 index 00000000..7c74e1ce --- /dev/null +++ b/src/assets/python/http/googleadk/base/model/load.py @@ -0,0 +1,41 @@ +import os +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> None: + """ + Set up Gemini API key authentication. + Uses AgentCore Identity for API key management in deployed environments, + and falls back to .env file for local development. + Sets the GOOGLE_API_KEY environment variable for the Google ADK. + """ + api_key = _get_api_key() + # Use Google AI Studios API Key Authentication. + # https://google.github.io/adk-docs/agents/models/#google-ai-studio + os.environ["GOOGLE_API_KEY"] = api_key + # Set to TRUE is using Google Vertex AI, Set to FALSE for Google AI Studio + os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "FALSE" diff --git a/src/assets/python/googleadk/base/pyproject.toml b/src/assets/python/http/googleadk/base/pyproject.toml similarity index 100% rename from src/assets/python/googleadk/base/pyproject.toml rename to src/assets/python/http/googleadk/base/pyproject.toml diff --git a/src/assets/python/langchain_langgraph/base/README.md b/src/assets/python/http/langchain_langgraph/base/README.md similarity index 100% rename from src/assets/python/langchain_langgraph/base/README.md rename to src/assets/python/http/langchain_langgraph/base/README.md diff --git a/src/assets/python/http/langchain_langgraph/base/gitignore.template b/src/assets/python/http/langchain_langgraph/base/gitignore.template new file mode 100644 index 00000000..fa1c60ae --- /dev/null +++ b/src/assets/python/http/langchain_langgraph/base/gitignore.template @@ -0,0 +1,41 @@ +# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/src/assets/python/langchain_langgraph/base/main.py b/src/assets/python/http/langchain_langgraph/base/main.py similarity index 100% rename from src/assets/python/langchain_langgraph/base/main.py rename to src/assets/python/http/langchain_langgraph/base/main.py diff --git a/src/assets/python/openaiagents/base/mcp_client/__init__.py b/src/assets/python/http/langchain_langgraph/base/mcp_client/__init__.py similarity index 100% rename from src/assets/python/openaiagents/base/mcp_client/__init__.py rename to src/assets/python/http/langchain_langgraph/base/mcp_client/__init__.py diff --git a/src/assets/python/langchain_langgraph/base/mcp_client/client.py b/src/assets/python/http/langchain_langgraph/base/mcp_client/client.py similarity index 100% rename from src/assets/python/langchain_langgraph/base/mcp_client/client.py rename to src/assets/python/http/langchain_langgraph/base/mcp_client/client.py diff --git a/src/assets/python/openaiagents/base/model/__init__.py b/src/assets/python/http/langchain_langgraph/base/model/__init__.py similarity index 100% rename from src/assets/python/openaiagents/base/model/__init__.py rename to src/assets/python/http/langchain_langgraph/base/model/__init__.py diff --git a/src/assets/python/http/langchain_langgraph/base/model/load.py b/src/assets/python/http/langchain_langgraph/base/model/load.py new file mode 100644 index 00000000..b8f2d71e --- /dev/null +++ b/src/assets/python/http/langchain_langgraph/base/model/load.py @@ -0,0 +1,123 @@ +{{#if (eq modelProvider "Bedrock")}} +from langchain_aws import ChatBedrock + +# Uses global inference profile for Claude Sonnet 4.5 +# https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html +MODEL_ID = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" + + +def load_model() -> ChatBedrock: + """Get Bedrock model client using IAM credentials.""" + return ChatBedrock(model_id=MODEL_ID) +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os +from langchain_anthropic import ChatAnthropic +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatAnthropic: + """Get authenticated Anthropic model client.""" + return ChatAnthropic( + model="claude-sonnet-4-5-20250929", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os +from langchain_openai import ChatOpenAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatOpenAI: + """Get authenticated OpenAI model client.""" + return ChatOpenAI( + model="gpt-4.1", + api_key=_get_api_key() + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os +from langchain_google_genai import ChatGoogleGenerativeAI +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> ChatGoogleGenerativeAI: + """Get authenticated Gemini model client.""" + return ChatGoogleGenerativeAI( + model="gemini-2.5-flash", + api_key=_get_api_key() + ) +{{/if}} diff --git a/src/assets/python/langchain_langgraph/base/pyproject.toml b/src/assets/python/http/langchain_langgraph/base/pyproject.toml similarity index 100% rename from src/assets/python/langchain_langgraph/base/pyproject.toml rename to src/assets/python/http/langchain_langgraph/base/pyproject.toml diff --git a/src/assets/python/openaiagents/base/README.md b/src/assets/python/http/openaiagents/base/README.md similarity index 100% rename from src/assets/python/openaiagents/base/README.md rename to src/assets/python/http/openaiagents/base/README.md diff --git a/src/assets/python/http/openaiagents/base/gitignore.template b/src/assets/python/http/openaiagents/base/gitignore.template new file mode 100644 index 00000000..fa1c60ae --- /dev/null +++ b/src/assets/python/http/openaiagents/base/gitignore.template @@ -0,0 +1,41 @@ +# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/src/assets/python/openaiagents/base/main.py b/src/assets/python/http/openaiagents/base/main.py similarity index 100% rename from src/assets/python/openaiagents/base/main.py rename to src/assets/python/http/openaiagents/base/main.py diff --git a/src/assets/python/strands/base/mcp_client/__init__.py b/src/assets/python/http/openaiagents/base/mcp_client/__init__.py similarity index 100% rename from src/assets/python/strands/base/mcp_client/__init__.py rename to src/assets/python/http/openaiagents/base/mcp_client/__init__.py diff --git a/src/assets/python/openaiagents/base/mcp_client/client.py b/src/assets/python/http/openaiagents/base/mcp_client/client.py similarity index 100% rename from src/assets/python/openaiagents/base/mcp_client/client.py rename to src/assets/python/http/openaiagents/base/mcp_client/client.py diff --git a/src/assets/python/strands/base/model/__init__.py b/src/assets/python/http/openaiagents/base/model/__init__.py similarity index 100% rename from src/assets/python/strands/base/model/__init__.py rename to src/assets/python/http/openaiagents/base/model/__init__.py diff --git a/src/assets/python/openaiagents/base/model/load.py b/src/assets/python/http/openaiagents/base/model/load.py similarity index 100% rename from src/assets/python/openaiagents/base/model/load.py rename to src/assets/python/http/openaiagents/base/model/load.py diff --git a/src/assets/python/openaiagents/base/pyproject.toml b/src/assets/python/http/openaiagents/base/pyproject.toml similarity index 100% rename from src/assets/python/openaiagents/base/pyproject.toml rename to src/assets/python/http/openaiagents/base/pyproject.toml diff --git a/src/assets/python/strands/base/README.md b/src/assets/python/http/strands/base/README.md similarity index 100% rename from src/assets/python/strands/base/README.md rename to src/assets/python/http/strands/base/README.md diff --git a/src/assets/python/strands/base/gitignore.template b/src/assets/python/http/strands/base/gitignore.template similarity index 100% rename from src/assets/python/strands/base/gitignore.template rename to src/assets/python/http/strands/base/gitignore.template diff --git a/src/assets/python/strands/base/main.py b/src/assets/python/http/strands/base/main.py similarity index 100% rename from src/assets/python/strands/base/main.py rename to src/assets/python/http/strands/base/main.py diff --git a/src/assets/python/strands/capabilities/memory/__init__.py b/src/assets/python/http/strands/base/mcp_client/__init__.py similarity index 100% rename from src/assets/python/strands/capabilities/memory/__init__.py rename to src/assets/python/http/strands/base/mcp_client/__init__.py diff --git a/src/assets/python/strands/base/mcp_client/client.py b/src/assets/python/http/strands/base/mcp_client/client.py similarity index 100% rename from src/assets/python/strands/base/mcp_client/client.py rename to src/assets/python/http/strands/base/mcp_client/client.py diff --git a/src/assets/python/http/strands/base/model/__init__.py b/src/assets/python/http/strands/base/model/__init__.py new file mode 100644 index 00000000..0e632e10 --- /dev/null +++ b/src/assets/python/http/strands/base/model/__init__.py @@ -0,0 +1 @@ +# Package marker diff --git a/src/assets/python/http/strands/base/model/load.py b/src/assets/python/http/strands/base/model/load.py new file mode 100644 index 00000000..8954269e --- /dev/null +++ b/src/assets/python/http/strands/base/model/load.py @@ -0,0 +1,123 @@ +{{#if (eq modelProvider "Bedrock")}} +from strands.models.bedrock import BedrockModel + + +def load_model() -> BedrockModel: + """Get Bedrock model client using IAM credentials.""" + return BedrockModel(model_id="global.anthropic.claude-sonnet-4-5-20250929-v1:0") +{{/if}} +{{#if (eq modelProvider "Anthropic")}} +import os + +from strands.models.anthropic import AnthropicModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> AnthropicModel: + """Get authenticated Anthropic model client.""" + return AnthropicModel( + client_args={"api_key": _get_api_key()}, + model_id="claude-sonnet-4-5-20250929", + max_tokens=5000, + ) +{{/if}} +{{#if (eq modelProvider "OpenAI")}} +import os + +from strands.models.openai import OpenAIModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> OpenAIModel: + """Get authenticated OpenAI model client.""" + return OpenAIModel( + client_args={"api_key": _get_api_key()}, + model_id="gpt-4.1", + ) +{{/if}} +{{#if (eq modelProvider "Gemini")}} +import os + +from strands.models.gemini import GeminiModel +from bedrock_agentcore.identity.auth import requires_api_key + +IDENTITY_PROVIDER_NAME = "{{identityProviders.[0].name}}" +IDENTITY_ENV_VAR = "{{identityProviders.[0].envVarName}}" + + +@requires_api_key(provider_name=IDENTITY_PROVIDER_NAME) +def _agentcore_identity_api_key_provider(api_key: str) -> str: + """Fetch API key from AgentCore Identity.""" + return api_key + + +def _get_api_key() -> str: + """ + Uses AgentCore Identity for API key management in deployed environments. + For local development, run via 'agentcore dev' which loads agentcore/.env. + """ + if os.getenv("LOCAL_DEV") == "1": + api_key = os.getenv(IDENTITY_ENV_VAR) + if not api_key: + raise RuntimeError( + f"{IDENTITY_ENV_VAR} not found. Add {IDENTITY_ENV_VAR}=your-key to .env.local" + ) + return api_key + return _agentcore_identity_api_key_provider() + + +def load_model() -> GeminiModel: + """Get authenticated Gemini model client.""" + return GeminiModel( + client_args={"api_key": _get_api_key()}, + model_id="gemini-2.5-flash", + ) +{{/if}} diff --git a/src/assets/python/strands/base/pyproject.toml b/src/assets/python/http/strands/base/pyproject.toml similarity index 100% rename from src/assets/python/strands/base/pyproject.toml rename to src/assets/python/http/strands/base/pyproject.toml diff --git a/src/assets/python/http/strands/capabilities/memory/__init__.py b/src/assets/python/http/strands/capabilities/memory/__init__.py new file mode 100644 index 00000000..0e632e10 --- /dev/null +++ b/src/assets/python/http/strands/capabilities/memory/__init__.py @@ -0,0 +1 @@ +# Package marker diff --git a/src/assets/python/strands/capabilities/memory/session.py b/src/assets/python/http/strands/capabilities/memory/session.py similarity index 100% rename from src/assets/python/strands/capabilities/memory/session.py rename to src/assets/python/http/strands/capabilities/memory/session.py diff --git a/src/assets/python/mcp/standalone/base/README.md b/src/assets/python/mcp/standalone/base/README.md new file mode 100644 index 00000000..6e4dc8a0 --- /dev/null +++ b/src/assets/python/mcp/standalone/base/README.md @@ -0,0 +1,36 @@ +# {{ name }} + +An MCP (Model Context Protocol) server deployed on Amazon Bedrock AgentCore. + +## Overview + +This project implements an MCP server using FastMCP. MCP servers expose tools that can be consumed by MCP clients (other agents or applications). + +## Local Development + +```bash +# Install dependencies +uv sync + +# Run the MCP server locally +uv run python main.py +``` + +The server starts on port 8000 with Streamable HTTP transport. + +## Adding Tools + +Define tools using the `@mcp.tool()` decorator in `main.py`: + +```python +@mcp.tool() +def my_tool(param: str) -> str: + """Description of what the tool does.""" + return f"Result: {param}" +``` + +## Deploy + +```bash +agentcore deploy +``` diff --git a/src/assets/python/mcp/standalone/base/gitignore.template b/src/assets/python/mcp/standalone/base/gitignore.template new file mode 100644 index 00000000..fa1c60ae --- /dev/null +++ b/src/assets/python/mcp/standalone/base/gitignore.template @@ -0,0 +1,41 @@ +# Environment variables +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.venv/ +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/src/assets/python/mcp/standalone/base/main.py b/src/assets/python/mcp/standalone/base/main.py new file mode 100644 index 00000000..f91415ec --- /dev/null +++ b/src/assets/python/mcp/standalone/base/main.py @@ -0,0 +1,24 @@ +from mcp.server.fastmcp import FastMCP +import uvicorn + +mcp = FastMCP("{{ name }}") + + +@mcp.tool() +def add_numbers(a: int, b: int) -> int: + """Return the sum of two numbers.""" + return a + b + + +@mcp.tool() +def greet(name: str) -> str: + """Return a greeting for the given name.""" + return f"Hello, {name}!" + + +if __name__ == "__main__": + uvicorn.run( + mcp.streamable_http_app(), + host="0.0.0.0", + port=8000, + ) diff --git a/src/assets/python/mcp/standalone/base/pyproject.toml b/src/assets/python/mcp/standalone/base/pyproject.toml new file mode 100644 index 00000000..599a5cef --- /dev/null +++ b/src/assets/python/mcp/standalone/base/pyproject.toml @@ -0,0 +1,19 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ name }}" +version = "0.1.0" +description = "AgentCore MCP Server" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "aws-opentelemetry-distro", + "bedrock-agentcore >= 1.0.3", + "mcp >= 1.19.0", + "uvicorn >= 0.30.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["."] diff --git a/src/cli/commands/add/__tests__/validate.test.ts b/src/cli/commands/add/__tests__/validate.test.ts index 9a24db86..6ac433aa 100644 --- a/src/cli/commands/add/__tests__/validate.test.ts +++ b/src/cli/commands/add/__tests__/validate.test.ts @@ -937,6 +937,142 @@ describe('validate', () => { }); }); + describe('validateAddAgentOptions protocol validation', () => { + it('MCP: succeeds with just name and language', () => { + const result = validateAddAgentOptions({ + name: 'McpAgent', + type: 'create', + language: 'Python', + protocol: 'MCP', + }); + expect(result.valid).toBe(true); + }); + + it('MCP: fails with --framework', () => { + const result = validateAddAgentOptions({ + name: 'McpAgent', + type: 'create', + language: 'Python', + protocol: 'MCP', + framework: 'Strands', + }); + expect(result.valid).toBe(false); + expect(result.error).toContain('not applicable for MCP protocol'); + }); + + it('MCP: fails with --model-provider', () => { + const result = validateAddAgentOptions({ + name: 'McpAgent', + type: 'create', + language: 'Python', + protocol: 'MCP', + modelProvider: 'Bedrock', + }); + expect(result.valid).toBe(false); + expect(result.error).toContain('not applicable for MCP protocol'); + }); + + it('MCP: fails with --memory (non-none)', () => { + const result = validateAddAgentOptions({ + name: 'McpAgent', + type: 'create', + language: 'Python', + protocol: 'MCP', + memory: 'shortTerm', + }); + expect(result.valid).toBe(false); + expect(result.error).toContain('not applicable for MCP protocol'); + }); + + it('A2A: succeeds with --framework Strands', () => { + const result = validateAddAgentOptions({ + name: 'A2aAgent', + type: 'byo', + language: 'Python', + protocol: 'A2A', + framework: 'Strands', + modelProvider: 'Bedrock', + codeLocation: '/path/to/code', + }); + expect(result.valid).toBe(true); + }); + + it('A2A: fails with --framework CrewAI', () => { + const result = validateAddAgentOptions({ + name: 'A2aAgent', + type: 'byo', + language: 'Python', + protocol: 'A2A', + framework: 'CrewAI', + modelProvider: 'Bedrock', + codeLocation: '/path/to/code', + }); + expect(result.valid).toBe(false); + expect(result.error).toContain('does not support A2A protocol'); + }); + + it('A2A: fails with --framework OpenAIAgents', () => { + const result = validateAddAgentOptions({ + name: 'A2aAgent', + type: 'byo', + language: 'Python', + protocol: 'A2A', + framework: 'OpenAIAgents', + modelProvider: 'OpenAI', + codeLocation: '/path/to/code', + }); + expect(result.valid).toBe(false); + expect(result.error).toContain('does not support A2A protocol'); + }); + + it('AGUI: succeeds with --framework Strands', () => { + const result = validateAddAgentOptions({ + name: 'AguiAgent', + type: 'byo', + language: 'Python', + protocol: 'AGUI', + framework: 'Strands', + modelProvider: 'Bedrock', + codeLocation: '/path/to/code', + }); + expect(result.valid).toBe(true); + }); + + it('AGUI: succeeds with --framework GoogleADK', () => { + const result = validateAddAgentOptions({ + name: 'AguiAgent', + type: 'byo', + language: 'Python', + protocol: 'AGUI', + framework: 'GoogleADK', + modelProvider: 'Gemini', + codeLocation: '/path/to/code', + }); + expect(result.valid).toBe(true); + }); + + it('invalid protocol fails validation', () => { + const result = validateAddAgentOptions({ + name: 'BadAgent', + type: 'create', + language: 'Python', + protocol: 'GRPC' as any, + framework: 'Strands', + modelProvider: 'Bedrock', + }); + expect(result.valid).toBe(false); + expect(result.error).toContain('Invalid protocol'); + }); + + it('default (no --protocol) works as before (HTTP)', () => { + const result = validateAddAgentOptions({ + ...validAgentOptionsByo, + protocol: undefined, + }); + expect(result.valid).toBe(true); + }); + }); + describe('validateAddIdentityOptions OAuth', () => { it('passes for valid OAuth identity', () => { const result = validateAddIdentityOptions({ diff --git a/src/cli/commands/add/types.ts b/src/cli/commands/add/types.ts index 6f39c224..216e7a41 100644 --- a/src/cli/commands/add/types.ts +++ b/src/cli/commands/add/types.ts @@ -1,4 +1,4 @@ -import type { GatewayAuthorizerType, ModelProvider, SDKFramework, TargetLanguage } from '../../../schema'; +import type { GatewayAuthorizerType, ModelProvider, ProtocolMode, SDKFramework, TargetLanguage } from '../../../schema'; import type { MemoryOption } from '../../tui/screens/generate/types'; // Agent types @@ -11,6 +11,7 @@ export interface AddAgentOptions { modelProvider?: ModelProvider; apiKey?: string; memory?: MemoryOption; + protocol?: ProtocolMode; codeLocation?: string; entrypoint?: string; json?: boolean; diff --git a/src/cli/commands/add/validate.ts b/src/cli/commands/add/validate.ts index 8c77476d..f9ee1118 100644 --- a/src/cli/commands/add/validate.ts +++ b/src/cli/commands/add/validate.ts @@ -5,9 +5,11 @@ import { GatewayExceptionLevelSchema, GatewayNameSchema, ModelProviderSchema, + ProtocolModeSchema, SDKFrameworkSchema, TARGET_TYPE_AUTH_CONFIG, TargetLanguageSchema, + getSupportedFrameworksForProtocol, getSupportedModelProviders, matchEnumValue, } from '../../../schema'; @@ -63,6 +65,9 @@ async function validateCredentialExists(credentialName: string): Promise = []; let strategy: Awaited> | undefined; - if (modelProvider !== 'Bedrock') { + const isMcp = protocol === 'MCP'; + + if (!isMcp && modelProvider !== 'Bedrock') { strategy = await credentialPrimitive.resolveCredentialStrategy( name, agentName, diff --git a/src/cli/commands/create/command.tsx b/src/cli/commands/create/command.tsx index ada69dd8..34e8ed68 100644 --- a/src/cli/commands/create/command.tsx +++ b/src/cli/commands/create/command.tsx @@ -1,5 +1,5 @@ import { getWorkingDirectory } from '../../../lib'; -import type { BuildType, ModelProvider, SDKFramework, TargetLanguage } from '../../../schema'; +import type { BuildType, ModelProvider, ProtocolMode, SDKFramework, TargetLanguage } from '../../../schema'; import { getErrorMessage } from '../../errors'; import { COMMAND_DESCRIPTIONS } from '../../tui/copy'; import { CreateScreen } from '../../tui/screens/create'; @@ -120,6 +120,7 @@ async function handleCreateCLI(options: CreateOptions): Promise { modelProvider: options.modelProvider as ModelProvider, apiKey: options.apiKey, memory: options.memory as 'none' | 'shortTerm' | 'longAndShortTerm', + protocol: options.protocol as ProtocolMode | undefined, skipGit: options.skipGit, skipPythonSetup: options.skipPythonSetup, onProgress, @@ -152,6 +153,7 @@ export const registerCreate = (program: Command) => { .option('--model-provider ', 'Model provider (Bedrock, Anthropic, OpenAI, Gemini) [non-interactive]') .option('--api-key ', 'API key for non-Bedrock providers [non-interactive]') .option('--memory