Skip to content

Commit 7ad1e61

Browse files
authored
Merge pull request #2 from aws-samples/fix/hardcoding
Fix hardcoding-related deployment issues
2 parents 99a1736 + ed37473 commit 7ad1e61

File tree

17 files changed

+2674
-188
lines changed

17 files changed

+2674
-188
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ logs/
5454
*.tfstate.*
5555
.terraform/
5656
.terraform.lock.hcl
57+
backend.hcl
5758
terraform.tfvars
5859

5960
# AWS
@@ -75,7 +76,6 @@ terraform.tfvars
7576

7677
# Dependencies
7778
node_modules/
78-
uv.lock
7979

8080
# Temporary files
8181
*.tmp

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,18 @@ Explore the README.md file under the **infra** directory for more details on the
6565

6666
### Test locally
6767

68-
1. **Initialize the project**:
68+
1. **Initialize the project and dependencies**:
6969
```bash
7070
cd cx-agent-backend
71-
pip install uv
72-
uv init
71+
uv venv
72+
uv sync --all-extras --frozen
7373
```
74-
2. **Install dependencies**: `uv sync --frozen`
75-
3. **Run locally**:
74+
2. **Run locally**:
7675
```bash
7776
cd src
7877
uv run run.py
7978
```
80-
4. **Test the health endpoint**:
79+
3. **Test the health endpoint**:
8180
```bash
8281
curl http://localhost:8080/ping
8382
```
@@ -106,6 +105,8 @@ curl -X POST http://localhost:8080/api/v1/feedback \
106105
5. **Run the Streamlit app**:
107106
```bash
108107
cd cx-agent-frontend
108+
uv venv
109+
uv sync --frozen
109110
uv run streamlit run src/app.py --server.port 8501 --server.address 127.0.0.1
110111
```
111112
6. Access the web interface at `http://localhost:8501`

agentcore_runtime_deployment.ipynb

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"source": [
77
"# LangGraph Agent Deployment to Amazon Bedrock AgentCore\n",
88
"\n",
9-
"This notebook demonstrates how to deploy a FastAPI LangGraph agent to Amazon Bedrock AgentCore Runtime and invoke it."
9+
"This notebook demonstrates how to deploy a FastAPI LangGraph agent to Amazon Bedrock AgentCore Runtime and invoke it.\n",
10+
"\n",
11+
"It's tested to run in the Python virtual environment created in `cx-agent-backend`"
1012
]
1113
},
1214
{
@@ -46,21 +48,26 @@
4648
"outputs": [],
4749
"source": [
4850
"# Configuration\n",
49-
"AWS_REGION = \"us-east-1\"\n",
51+
"AWS_REGION = os.environ.get(\"AWS_REGION\", os.environ.get(\"AWS_DEFAULT_REGION\", \"us-east-1\"))\n",
5052
"AWS_ACCOUNT_ID = boto3.client('sts').get_caller_identity()['Account']\n",
5153
"ECR_REPOSITORY = \"langgraph-cx-agent\"\n",
5254
"IMAGE_TAG = \"latest\"\n",
5355
"ECR_URI = f\"{AWS_ACCOUNT_ID}.dkr.ecr.{AWS_REGION}.amazonaws.com/{ECR_REPOSITORY}:{IMAGE_TAG}\"\n",
54-
"AGENT_RUNTIME_NAME = \"langgraph_cx_agent_110902\"\n",
56+
"AGENT_RUNTIME_NAME = \"langgraph_cx_agent\"\n",
5557
"AGENT_RUNTIME_ROLE_ARN = f\"arn:aws:iam::{AWS_ACCOUNT_ID}:role/agentic-ai-bedrock-role\" # deployed in the prerequisite section\n",
56-
"USER_POOL_ID = \"<your-user-pool-id>\" # Replace with your Cognito User Pool ID from the terraform deployment output\n",
57-
"CLIENT_ID = \"<your-client-id>\" # Replace with your Cognito App Client ID from the terraform deployment output\n",
58-
"CLIENT_SECRET = \"<your-client-secret>\" # Replace with your Cognito App Client Secret from the AWS console\n",
58+
"USER_POOL_ID = \"\" # TODO: Enter Cognito User Pool ID from the terraform deployment output\n",
59+
"CLIENT_ID = \"\" # TODO: Enter Cognito App Client ID from the terraform deployment output\n",
60+
"CLIENT_SECRET = \"\" # TODO: Enter Cognito App Client Secret from the AWS console\n",
5961
"\n",
6062
"print(f\"Account ID: {AWS_ACCOUNT_ID}\")\n",
6163
"print(f\"Region: {AWS_REGION}\")\n",
6264
"print(f\"ECR URI: {ECR_URI}\")\n",
63-
"print(f\"User Pool ID: {USER_POOL_ID}\")"
65+
"print(f\"User Pool ID: {USER_POOL_ID}\")\n",
66+
"\n",
67+
"if not (USER_POOL_ID and CLIENT_ID and CLIENT_SECRET):\n",
68+
" raise ValueError(\n",
69+
" \"Please set USER_POOL_ID, CLIENT_ID, and CLIENT_SECRET above\"\n",
70+
" )\n"
6471
]
6572
},
6673
{
@@ -90,7 +97,10 @@
9097
"outputs": [],
9198
"source": [
9299
"# Login to ECR\n",
93-
"!aws ecr get-login-password --region {AWS_REGION} | docker login --username AWS --password-stdin {AWS_ACCOUNT_ID}.dkr.ecr.{AWS_REGION}.amazonaws.com"
100+
"!aws ecr get-login-password --region {AWS_REGION} | docker login --username AWS --password-stdin {AWS_ACCOUNT_ID}.dkr.ecr.{AWS_REGION}.amazonaws.com\n",
101+
"\n",
102+
"# Alternatively with Finch:\n",
103+
"#!aws ecr get-login-password --region {AWS_REGION} | finch login --username AWS --password-stdin {AWS_ACCOUNT_ID}.dkr.ecr.{AWS_REGION}.amazonaws.com"
94104
]
95105
},
96106
{
@@ -100,7 +110,10 @@
100110
"outputs": [],
101111
"source": [
102112
"# Build and tag Docker image for ARM64\n",
103-
"!cd cx-agent-backend && docker buildx build --platform linux/arm64 -t {ECR_URI} --push ."
113+
"!cd cx-agent-backend && docker buildx build --platform linux/arm64 -t {ECR_URI} --push .\n",
114+
"\n",
115+
"# Alternatively with Finch:\n",
116+
"#!cd cx-agent-backend && finch build --platform linux/arm64 -t {ECR_URI} . && finch push {ECR_URI}"
104117
]
105118
},
106119
{
@@ -177,7 +190,7 @@
177190
" os.environ[var] = getpass.getpass(f\"Please provide your {var}\")\n",
178191
"\n",
179192
"\n",
180-
"_set_if_undefined(\"USERNAME\")\n",
193+
"_set_if_undefined(\"EMAIL_USERNAME\")\n",
181194
"_set_if_undefined(\"TEMPORARY_PASSWORD\")\n",
182195
"_set_if_undefined(\"PERMANENT_PASSWORD\")"
183196
]
@@ -189,7 +202,7 @@
189202
"outputs": [],
190203
"source": [
191204
"# Access values later in the notebook\n",
192-
"username = os.environ['USERNAME']\n",
205+
"username = os.environ['EMAIL_USERNAME']\n",
193206
"temp_password = os.environ['TEMPORARY_PASSWORD']\n",
194207
"permanent_password = os.environ['PERMANENT_PASSWORD']"
195208
]
@@ -280,7 +293,8 @@
280293
" )\n",
281294
" \n",
282295
" access_token = response['AuthenticationResult']['AccessToken']\n",
283-
" print(f\"Access token: {access_token}\")\n",
296+
" os.environ[\"COGNITO_TOKEN\"] = access_token\n",
297+
" print(\"Access token fetched\")\n",
284298
" \n",
285299
"except Exception as e:\n",
286300
" print(f\"Error: {e}\")"
@@ -303,7 +317,7 @@
303317
"import urllib.parse\n",
304318
"import json\n",
305319
"\n",
306-
"def invoke_agent(message, agent_arn, auth_token, session_id, region=\"us-east-1\"):\n",
320+
"def invoke_agent(message, agent_arn, auth_token, session_id, region=AWS_REGION):\n",
307321
" \"\"\"Invoke Bedrock AgentCore runtime with a message.\"\"\"\n",
308322
" escaped_agent_arn = urllib.parse.quote(agent_arn, safe='')\n",
309323
" url = f\"https://bedrock-agentcore.{region}.amazonaws.com/runtimes/{escaped_agent_arn}/invocations?qualifier=DEFAULT\"\n",
@@ -338,8 +352,8 @@
338352
"metadata": {},
339353
"outputs": [],
340354
"source": [
341-
"AUTH_TOKEN = \"\"\n",
342-
"AGENT_ARN = \"\"\n",
355+
"AUTH_TOKEN = os.environ[\"COGNITO_TOKEN\"] # (See above)\n",
356+
"AGENT_ARN = agent_runtime_arn\n",
343357
"SESSION_ID = str(uuid.uuid4())\n",
344358
" \n",
345359
"result = invoke_agent(\"Hello, can you help me?\", AGENT_ARN, AUTH_TOKEN, SESSION_ID)\n",
@@ -393,7 +407,7 @@
393407
],
394408
"metadata": {
395409
"kernelspec": {
396-
"display_name": "Python 3",
410+
"display_name": ".venv",
397411
"language": "python",
398412
"name": "python3"
399413
},
@@ -407,7 +421,7 @@
407421
"name": "python",
408422
"nbconvert_exporter": "python",
409423
"pygments_lexer": "ipython3",
410-
"version": "3.11.5"
424+
"version": "3.12.8"
411425
}
412426
},
413427
"nbformat": 4,

cx-agent-backend/pyproject.toml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,31 @@ version = "0.1.0"
44
description = "Clean Architecture CX Agent Backend"
55
requires-python = ">=3.11"
66
dependencies = [
7+
"aws-opentelemetry-distro>=0.1.0",
8+
"boto3>=1.34.0",
9+
"dependency-injector>=4.41.0",
710
"fastapi>=0.104.0",
8-
"uvicorn[standard]>=0.24.0",
9-
"pydantic>=2.5.0",
10-
"pydantic-settings>=2.1.0",
1111
"langchain>=0.1.0",
12+
"langchain-aws>=0.1.0",
1213
"langchain-core>=0.1.0",
1314
"langchain-openai>=0.1.0",
14-
"langchain-aws>=0.1.0",
15-
"langgraph>=0.1.0",
1615
"langfuse>=2.0.0",
17-
"boto3>=1.34.0",
16+
"langgraph>=0.1.0",
17+
"pydantic>=2.5.0",
18+
"pydantic-settings>=2.1.0",
1819
"structlog>=23.2.0",
19-
"dependency-injector>=4.41.0",
2020
"tavily-python>=0.3.0",
21-
"aws-opentelemetry-distro>=0.1.0",
21+
"uvicorn[standard]>=0.24.0",
2222
]
2323

2424
[project.optional-dependencies]
2525
dev = [
26+
"httpx>=0.25.0",
27+
"ipykernel>=6.30.1",
28+
"mypy>=1.7.0",
2629
"pytest>=7.4.0",
2730
"pytest-asyncio>=0.21.0",
28-
"httpx>=0.25.0",
2931
"ruff>=0.1.0",
30-
"mypy>=1.7.0",
3132
]
3233

3334
[build-system]
@@ -43,4 +44,4 @@ line-length = 88
4344

4445
[tool.mypy]
4546
python_version = "3.11"
46-
strict = true
47+
strict = true

cx-agent-backend/src/domain/services/conversation_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async def start_conversation(self, user_id: str) -> Conversation:
3030
return conversation
3131

3232
async def send_message(
33-
self, conversation_id: UUID, content: str, model: str = "gpt-4o-mini"
33+
self, conversation_id: UUID, content: str, model: str
3434
) -> tuple[Message, list[str]]:
3535
"""Send a message and get AI response."""
3636
# Get conversation

cx-agent-backend/src/infrastructure/adapters/bedrock_guardrail_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
class BedrockGuardrailService(GuardrailService):
1717
"""Bedrock Guardrails implementation."""
1818

19-
def __init__(self, guardrail_id: str, region: str = "us-east-1"):
19+
def __init__(self, guardrail_id: str, region: str | None = None):
2020
self._guardrail_id = guardrail_id
2121
self._client = boto3.client("bedrock-runtime", region_name=region)
2222

cx-agent-backend/src/infrastructure/aws/secret_reader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from infrastructure.config.settings import settings
55

66
class AWSSecretsReader(SecretReader):
7-
def read_secret(self, name: str, region: str = "us-east-1") -> str:
7+
def read_secret(self, name: str) -> str:
88
client = boto3.client("secretsmanager", region_name=settings.aws_region)
99
try:
1010
response = client.get_secret_value(SecretId=name)

cx-agent-backend/src/infrastructure/config/settings.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Application settings using Pydantic Settings."""
2+
from os import environ
23

34
from pydantic import Field
45
from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -22,10 +23,16 @@ class Settings(BaseSettings):
2223
debug: bool = Field(default=False, description="Debug mode")
2324

2425
# LLM Settings
25-
default_model: str = Field(default="gpt-4o-mini", description="Default LLM model")
26+
default_model: str = Field(
27+
default="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
28+
description="Default LLM model",
29+
)
2630

2731
# AWS Settings
28-
aws_region: str = Field(default="us-east-1", description="AWS region")
32+
aws_region: str = Field(
33+
default=environ.get("AWS_REGION", environ.get("AWS_DEFAULT_REGION", "us-east-1")),
34+
description="AWS region",
35+
)
2936

3037
# Logging
3138
log_level: str = Field(default="INFO", description="Log level")

cx-agent-backend/src/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ async def invocations(request: dict, http_request: Request):
7979
internal_request = SendMessageRequest(
8080
prompt=prompt,
8181
conversation_id=None,
82-
model="gpt-4o-mini"
82+
model=settings.default_model
8383
)
8484

8585
# Call internal endpoint

0 commit comments

Comments
 (0)