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

Regionus-west-2 Agent IDJDLTXAKYJY AliasesBianca (v99), Paul (v97), Gina (v98), Test (DRAFT) Lambdadaisy_in_action-0k2c0 (Python 3.12) Proxyproxy.mjs on :8787 DebugS3 origin-daisy-bucket/debug-tool-io/
Tool‑first policy No placeholders THEN lines IATA + Time parsing

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

%%{init: {"theme": "neutral","themeVariables": {"primaryColor": "#FFE066","secondaryColor":"#F3A712"},"flowchart": {"curve":"monotoneY","fontFamily":"Inter,Arial"}} }%% flowchart TD %% USER User((Traveler)) FE(["Frontends
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.

Fetch model config via CLI:

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

sequenceDiagram autonumber %% Group frontend %% Frontend Clients actor U as User participant UI as Frontend UI %% Group middle-tier/backend %% Service Layer participant PX as Proxy participant BR as Bedrock Agent participant L as Lambda %% Group external API %% 3rd Party API participant A as Amadeus API U->>UI: Natural language intent UI->>PX: POST /invoke PX->>BR: InvokeAgent (stream) BR-->>PX: Streamed outputText BR->>L: function-details (tools) L->>PX: /tools/iata | /tools/datetime PX-->>L: IATA matches | ISO date L->>PX: /tools/amadeus/search PX->>A: GET /v2/shopping/flight-offers A-->>PX: Offers JSON PX-->>L: Normalized offers L-->>BR: functionResponse TEXT BR-->>PX: final-response alt Stream empty or heading-only PX-->>UI: Use TEXT from functionResponse (fallback) Note right of UI: Fallback renders final output only else Stream contains content PX-->>UI: Render streamed text Note right of UI: UI displays live results to user end

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.mjs
  • aws/lambda_function.py
  • frontend/paul/index.html (+ other variants)
  • scripts/replay_sessions.mjs, scripts/extract_proxy_logs.py
  • handoff.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 usedFunctionResponseFallback when 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

AWS_REGIONus-west-2 AGENT_IDJDLTXAKYJY AGENT_ALIAS_IDBianca/Paul/Gina/Test AWS_ACCESS_KEY_IDSigV4 credentials AWS_SECRET_ACCESS_KEYSigV4 credentials ORIGINCORS allowlist (comma-separated) AMADEUS_API_KEYRequired for pricing AMADEUS_API_SECRETRequired for pricing IATA_DB_PATHDefault: ./iata.json TRANSCRIPT_BUCKET/PREFIXOptional transcript uploads AMADEUS_TIMEOUT_MSDefault: 12000

Lambda Env (selected)

PROXY_BASE_URLhttps://origin-daisy.onrender.com DEFAULT_CURRENCYEUR LH_GROUP_ONLYtrue RECOMMENDER_VERBOSEtrue RECOMMENDER_MAX_OPTIONS10 RECOMMENDER_MAX_TEXT_BYTES4000 DEBUG_TOOL_IOtrue DEBUG_S3_BUCKET/PREFIXorigin-daisy-bucket / debug-tool-io ACTION_GROUP_NAMEdaisy_in_action ACTION_GROUP_RECOMMENDERDestinationRecommender

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 Accept header.
  • Verify includedAirlineCodes forwarded when needed.
  • Timeouts: tune AMADEUS_TIMEOUT_MS.

Formatting Drift

  • Run replay suite and inspect format_ok / placeholders.
  • Review instruction ASCII variants in aws/.

Appendix

%%{init: {'theme':'dark'}}%% flowchart LR classDef cap fill:#fde68a,stroke:#b45309,stroke-width:2px,color:#111; classDef rep fill:#c4b5fd,stroke:#6d28d9,stroke-width:2px,color:#111; classDef st fill:#99f6e4,stroke:#0f766e,stroke-width:2px,color:#111; classDef lg fill:#fecaca,stroke:#b91c1c,stroke-width:2px,color:#111; classDef out fill:#bfdbfe,stroke:#1d4ed8,stroke-width:2px,color:#111; subgraph Capture["Tool I/O Capture"] P["Proxy payload (POST /tools)"]:::cap R["Proxy response (offers + raw)"]:::cap end S3D["S3 debug-tool-io/"]:::st P --> S3D R --> S3D subgraph Replay["Replay & Analytics"] RS["replay_sessions.mjs"]:::rep EX["extract_proxy_logs.py"]:::rep end CWL["CloudWatch Logs"]:::lg S3D -.-> RS CWL --> EX RS --> SUM["analytics/replay results"]:::out EX --> SUM

Use replay outputs to guide instruction and tool tuning. Keep conversations realistic and enforce tool‑first rules.