Project Overview
Daisy is an AWS Bedrock Agent solution that transforms traveler intent into concrete Lufthansa Group flight options. It integrates an Agent (with action groups), a Python Lambda executor, a minimal Node proxy for Bedrock + Amadeus tooling, and lightweight frontends.
Essentials
What You Build
Students will extend an Agent’s tool orchestration (IATA, time, pricing), refine instructions, and verify responses with replay tooling — aiming for reliable, testable flight results without fabrication.
Architecture
paul/ · bianca/ · gina/ · origin/"]) Proxy(["Node Proxy
:8787"]) AG((Bedrock Agent)) Orchestrator(["Agent Orchestrator"]) Lambda(["Action Lambda
daisy_in_action"]) Reco([Destination
Recommender]) Amadeus[(Amadeus
Flight API)] subgraph Obs["Observability"] S3[(S3
debug-tool-io)] CW([CloudWatch Logs]) end %% FLOW User -- Chat --> FE FE -- JSON --> Proxy Proxy -- InvokeAgent --> Orchestrator Orchestrator -- chooses --> AG Orchestrator -- "Fn Details" --> Lambda Lambda -- IATA --> Proxy Lambda -- Time --> Proxy Lambda -- Pricing --> Proxy Lambda -- Destination --> Reco Reco -- "Flight offers" --> Amadeus Amadeus -- offers --> Reco Lambda -- "Fn Response" --> Orchestrator Orchestrator -.-> Proxy Proxy -- "Final Text" --> FE %% LOGGING Lambda -. Log .-> S3 Lambda -. Log .-> CW Proxy -.-> CW %% STYLE classDef portal fill:#fcf5c7,stroke:#8a7900,stroke-width:2px; classDef lambda fill:#e3f7e3,stroke:#2b5c1a,stroke-width:2px; classDef vendor fill:#e9efc0,stroke:#005f73,stroke-width:2px; classDef core fill:#e9e9fc,font-weight:bold; class AG,Proxy,Orchestrator core; class Amadeus vendor; class FE portal; class Lambda,Reco lambda;
The proxy assembles streamed text from Bedrock and falls back to Lambda’s functionResponse TEXT when Bedrock streams only a heading.
Components & Roles
Agent (Bedrock)
Hosts instructions and routes calls to action groups. Ensures tool‑first behavior and consistent presentation (THEN lines, sections, flight number format).
Models (LLM)
The foundation model used by the Agent is configured in AWS Bedrock per agent version and alias. This repo does not hard-code a model check Bedrock for the authoritative source.
aws bedrock-agent list-agent-aliases --agent-id JDLTXAKYJY --region us-west-2
aws bedrock-agent list-agent-versions --agent-id JDLTXAKYJY --region us-west-2
aws bedrock-agent get-agent --agent-id JDLTXAKYJY --agent-version <97|98|99> --region us-west-2
Record the chosen model per alias in docs (handoff.md). Avoid calling Bedrock directly from the browser/UI.
Lambda: daisy_in_action
Executes function‑details and OpenAPI actions: resolves IATA, parses time phrases, calls Amadeus via the proxy, and returns simplified offers plus human‑readable message text.
Proxy (proxy.mjs)
Minimal gateway for Bedrock and tools. Signs Bedrock Invoke, normalizes event streams, exposes Amadeus/IATA/Time adapters, and implements text fallback. CORS‑gated and transcript‑aware.
Frontends
Four identical UIs (config‑only variants). Render chat, sanitize formatting, support PDF creation from itineraries, and log transcripts. Now rely solely on text from proxy.
Amadeus
Flight Offers Search v2.8/2.9. Proxy forwards GET query params (origin/destination, dates, passengers, cabin, LH filters, currency, nonstop, max) and adds Accept: application/vnd.amadeus+json.
Observability
CloudWatch captures Lambda/Proxy telemetry. Optional S3 debug captures full tool I/O payloads. Replay scripts summarize failures, formatting, placeholders, and tool‑call counts.
Data & Logical Flows
Formatting Guarantees
- THEN lines for connections; flight numbers compact (e.g., LH612).
- Sections: DIRECT FLIGHTS, CONNECTING FLIGHTS.
- No placeholders: no “EUR X.XX”, “Airport Name N”, “Notes: …”.
Fallback Logic (Proxy)
- If no streamed text → use functionResponse TEXT.
- If streamed text is a short/heading line → replace with functionResponse TEXT.
- Frontends do not parse finalResponse; they rely on proxy’s
text.
APIs & Contracts
Proxy Routes
POST /invoke POST /tools/amadeus/search GET /tools/iata/lookup POST /tools/datetime/interpret POST /log/transcript GET /health
Amadeus Query (Spec v2.8/2.9)
originLocationCode, destinationLocationCode, departureDate, returnDate?, adults, children?, infants?, travelClass?, nonStop?, currencyCode?, includedAirlineCodes?, excludedAirlineCodes?, max?
Proxy adds Accept: application/vnd.amadeus+json and forwards LH-group filters when provided.
File References
proxy.mjsaws/lambda_function.pyfrontend/paul/index.html(+ other variants)scripts/replay_sessions.mjs,scripts/extract_proxy_logs.pyhandoff.md,docs/replay_handoff.md
Operations & Observability
CloudWatch & Debug
- Tail:
aws logs tail "/aws/lambda/daisy_in_action-0k2c0" --since 15m --follow --region us-west-2 - Debug tool I/O:
s3://origin-daisy-bucket/debug-tool-io/YYYY/MM/DD/ - Proxy logs mark
usedFunctionResponseFallbackwhen fallback applied.
Replay & QA
node scripts/replay_sessions.mjs→ per-turn formatting and placeholder flags.python scripts/extract_proxy_logs.py --minutes 60→ tool-call counts and sessions.- PDF generation validated from itinerary options (first option).
Configuration
Proxy Env Vars
Lambda Env (selected)
Deploy & Test
Proxy
npm ci node proxy.mjs # health curl http://localhost:8787/health # CORS origins: set ORIGIN env var
Smoke
# IATA lookup
curl -s "http://localhost:8787/tools/iata/lookup?term=Zurich&limit=3" | jq .
# Agent call
curl -s -X POST http://localhost:8787/invoke \
-H 'Content-Type: application/json' \
-d '{"sessionId":"smoke-1","inputText":"ZAG to ZRH 2025-12-10 return 2025-12-12"}' | jq .text
Troubleshooting
No Text Response
- Proxy now falls back to functionResponse TEXT on empty/heading-only streams.
- Confirm proxy logs show
usedFunctionResponseFallback: true.
Amadeus Issues
- Check creds and
Acceptheader. - Verify
includedAirlineCodesforwarded when needed. - Timeouts: tune
AMADEUS_TIMEOUT_MS.
Formatting Drift
- Run replay suite and inspect
format_ok/ placeholders. - Review instruction ASCII variants in
aws/.
Appendix
Use replay outputs to guide instruction and tool tuning. Keep conversations realistic and enforce tool‑first rules.