Skip to content

Commit aa6b03d

Browse files
committed
feat(market-trends-agent): add demo UI, LangGraph checkpointer/store, multi-region support
- Add AgentCoreMemorySaver (checkpointer) and AgentCoreMemoryStore for dual-layer memory - Add React chat UI with pre-built broker profiles and markdown rendering - Add FastAPI backend proxy bridging UI to deployed AgentCore agent - Add run_demo_ui.py launcher for single-command startup - Replace hardcoded us-east-1 with os.getenv for multi-region deployability - Add IAM permissions for checkpointer and memory record operations - Fix extract_actor_id regex and add new intro patterns - Remove personal AWS_PROFILE reference from error message - Sync requirements.txt with pyproject.toml (fastapi, uvicorn, langgraph-checkpoint-aws) - Update README with UI setup, architecture diagram, and troubleshooting
1 parent 3b9d9d0 commit aa6b03d

19 files changed

Lines changed: 6023 additions & 1384 deletions

02-use-cases/market-trends-agent/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33
.memory_id
44
.bedrock_agentcore.yaml
55

6+
# Browser screenshots captured during demo runs
7+
browser_screenshots/
8+
9+
# Test results (generated by test_auto.py)
10+
test_results.md
11+
test_auto.py
12+
13+
# PR description drafts (local only)
14+
PR_DESCRIPTION*.md
15+
616
# Python
717
__pycache__/
818
*.py[cod]
@@ -43,6 +53,9 @@ venv.bak/
4353
*.swp
4454
*.swo
4555

56+
# Node
57+
node_modules/
58+
4659
# OS
4760
.DS_Store
4861
Thumbs.db

02-use-cases/market-trends-agent/README.md

Lines changed: 144 additions & 87 deletions
Large diffs are not rendered by default.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""
2+
FastAPI backend for Market Trends Agent React UI.
3+
Proxies chat requests to the deployed AgentCore Runtime agent.
4+
"""
5+
6+
import json
7+
import os
8+
import logging
9+
from pathlib import Path
10+
from fastapi import FastAPI
11+
from fastapi.middleware.cors import CORSMiddleware
12+
from pydantic import BaseModel, Field
13+
import boto3
14+
from botocore.config import Config
15+
16+
logging.basicConfig(level=logging.INFO)
17+
logger = logging.getLogger(__name__)
18+
19+
app = FastAPI(title="Market Trends Agent API")
20+
21+
# Allow React dev server to connect
22+
app.add_middleware(
23+
CORSMiddleware,
24+
allow_origins=["http://localhost:3000"],
25+
allow_methods=["*"],
26+
allow_headers=["*"],
27+
)
28+
29+
# AWS region for AgentCore Runtime
30+
REGION = os.getenv("AWS_REGION", "us-east-1")
31+
32+
# Boto3 client with extended timeout for agent responses (browser + LLM calls can be slow)
33+
boto_config = Config(read_timeout=300, retries={"max_attempts": 2})
34+
agentcore_client = boto3.client("bedrock-agentcore", region_name=REGION, config=boto_config)
35+
36+
37+
def load_agent_arn() -> str | None:
38+
"""Load deployed agent ARN from the .agent_arn file created by deploy.py"""
39+
arn_file = Path(__file__).parent / ".agent_arn"
40+
if arn_file.exists():
41+
return arn_file.read_text().strip()
42+
return None
43+
44+
45+
class ChatRequest(BaseModel):
46+
message: str = Field(..., max_length=4000)
47+
session_id: str = Field(default="", max_length=100)
48+
49+
50+
@app.get("/api/health")
51+
def health():
52+
"""Health check — also reports whether the agent is deployed"""
53+
arn = load_agent_arn()
54+
return {"status": "ok", "agent_deployed": arn is not None, "region": REGION}
55+
56+
57+
@app.post("/api/chat")
58+
def chat(req: ChatRequest):
59+
"""Send a message to the deployed AgentCore agent and return the response"""
60+
arn = load_agent_arn()
61+
if not arn:
62+
return {"error": "Agent not deployed. Run 'uv run python deploy.py' first."}
63+
64+
try:
65+
# Build invocation payload matching the agent's expected format
66+
payload = json.dumps({"prompt": req.message, "session_id": req.session_id}).encode("utf-8")
67+
params: dict = {"agentRuntimeArn": arn, "payload": payload}
68+
69+
# Pass session ID for memory continuity across messages
70+
if req.session_id:
71+
params["runtimeSessionId"] = req.session_id
72+
73+
logger.info(f"Invoking agent | session={req.session_id[:24]}...")
74+
response = agentcore_client.invoke_agent_runtime(**params)
75+
76+
# Read the response body (handles both streaming and standard responses)
77+
if "response" in response:
78+
body = response["response"].read().decode("utf-8")
79+
else:
80+
body = str(response)
81+
82+
# AgentCore often returns a JSON-encoded string (e.g. "\"hello\\nworld\"")
83+
# Unwrap it so the frontend receives clean text with real newlines
84+
try:
85+
parsed = json.loads(body)
86+
if isinstance(parsed, str):
87+
body = parsed
88+
except (json.JSONDecodeError, TypeError):
89+
pass
90+
91+
# Final safety: replace any remaining literal \n sequences with real newlines
92+
body = body.replace("\\n", "\n")
93+
94+
return {"response": body, "session_id": req.session_id}
95+
96+
except Exception as e:
97+
logger.error(f"Agent invocation error: {e}")
98+
return {"error": "Agent request failed. Check server logs for details."}
99+
100+
101+
if __name__ == "__main__":
102+
import uvicorn
103+
uvicorn.run(app, host="0.0.0.0", port=8001)

02-use-cases/market-trends-agent/deploy.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@ def create_execution_role(self, role_name: str) -> str:
138138
"bedrock-agentcore:DeleteMemory",
139139
"bedrock-agentcore:GetMemory",
140140
"bedrock-agentcore:RetrieveMemoryRecords",
141+
"bedrock-agentcore:CreateMemoryRecord",
142+
"bedrock-agentcore:DeleteMemoryRecord",
143+
"bedrock-agentcore:UpdateMemoryRecord",
144+
"bedrock-agentcore:GetCheckpoint",
145+
"bedrock-agentcore:PutCheckpoint",
146+
"bedrock-agentcore:ListCheckpoints",
141147
],
142148
"Resource": [
143149
f"arn:aws:bedrock-agentcore:{self.region}:{account_id}:memory/*"
@@ -156,7 +162,7 @@ def create_execution_role(self, role_name: str) -> str:
156162
],
157163
"Resource": [
158164
f"arn:aws:bedrock-agentcore:{self.region}:{account_id}:browser-custom/*",
159-
"arn:aws:bedrock-agentcore:*:aws:browser/*"
165+
f"arn:aws:bedrock-agentcore:*:aws:browser/*"
160166
],
161167
},
162168
{
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Market Trends Agent — AgentCore Demo</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.jsx"></script>
11+
</body>
12+
</html>

0 commit comments

Comments
 (0)