About This Code Showcase
This code snippet shows the M5 Agentic Workflow pattern applied to car rental bookings. The LLM generates Python code that queries vehicles, checks date conflicts, computes rental cost, and inserts new bookings.
The full implementation (main.py) is under 200 lines and handles all rental flow logic through code-as-action.
Core: Agentic Booking Engine (main.py)
FastAPI backend wraps Gemini 2.5 Flash to generate executable Python code for each rental request. Helper functions are injected into the execution namespace:
from fastapi import FastAPI, HTTPException
import google.generativeai as genai
from tinydb import TinyDB, Query
from datetime import datetime, timedelta
app = FastAPI(title="Kereta Sewa Jalan-jalan API")
db = TinyDB('kereta_sewa_bookings.json')
vehicles_tbl = db.table('vehicles')
bookings_tbl = db.table('bookings')
PICKUP_LOCATIONS = ["KLIA", "KL Sentral",
"Subang Airport (SZB)", "TBS"]
BOOKING_DEPOSIT = 100.0
HOTEL_DELIVERY_FEE = 50.0
def get_daily_rate(tier):
return {"Economy": 120, "Compact": 160,
"SUV": 250, "MPV": 220,
"Premium": 350}.get(tier, 150)
def calculate_rental_cost(tier, days, hotel_delivery=False):
weekly = {"Economy": 700, "Compact": 950}.get(tier)
daily = get_daily_rate(tier)
base = weekly if (weekly and days == 7) else daily * days
total = base + BOOKING_DEPOSIT
if hotel_delivery:
total += HOTEL_DELIVERY_FEE
return {"base": base, "deposit": BOOKING_DEPOSIT,
"delivery": HOTEL_DELIVERY_FEE if hotel_delivery else 0,
"total": total}
def has_date_conflict(vehicle_id, pickup_date, return_date, bookings_tbl):
start = datetime.strptime(pickup_date, "%Y-%m-%d")
end = datetime.strptime(return_date, "%Y-%m-%d")
existing = bookings_tbl.search(
(Query().vehicle_id == vehicle_id) &
(Query().status.one_of(["rented", "booked"]))
)
for b in existing:
ex_start = datetime.strptime(b["pickup_date"], "%Y-%m-%d")
ex_end = datetime.strptime(b["return_date"], "%Y-%m-%d")
if not (end <= ex_start or start >= ex_end):
return True
return False
Agentic Workflow: Code Generation Prompt
The LLM receives a strict prompt that lists available helpers and expected output format. It writes Python code that sets STATUS and answer_text variables:
PROMPT = """You are Kereta Sewa Jalan-jalan car rental booking assistant.
WRITE PYTHON CODE.
Database: vehicles_tbl, bookings_tbl
Functions: next_booking_id, get_daily_rate, calculate_rental_cost,
has_date_conflict, datetime, timedelta
Fleet: 56 vehicles across Economy/Compact/SUV/MPV/Premium tiers
Pricing: Economy RM120/day RM700/week | Compact RM160/day RM950/week
SUV RM250/day | MPV RM220/day | Premium RM350/day
Booking deposit: RM 100 (deducted from final bill)
Hotel delivery: RM 50 add-on
Pickup locations (free): KLIA, KL Sentral, Subang Airport (SZB), TBS
Required: customer_name, phone, license_no
Booking prefix: RNT. Min 1 day, max 7 days.
Reference: Wednesday, 8 Apr 2026
Set STATUS (success|vehicle_unavailable|date_conflict|invalid_request)
and answer_text
Output: Python code in markdown block
Request: {question}"""
def execute_code(code, user_request):
SAFE = {"Query": Query, "next_booking_id": next_booking_id,
"get_daily_rate": get_daily_rate,
"calculate_rental_cost": calculate_rental_cost,
"has_date_conflict": has_date_conflict,
"datetime": datetime, "timedelta": timedelta,
"user_request": user_request}
LOCALS = {"db": db, "vehicles_tbl": vehicles_tbl,
"bookings_tbl": bookings_tbl}
try:
exec(code, SAFE, LOCALS)
except Exception:
return {"error": traceback.format_exc()}
return {
"answer": LOCALS.get("answer_text", "No response"),
"status": LOCALS.get("STATUS", "unknown")
}
Example: AI-Generated Booking Code
When a user says "Book a Myvi for 3 days from KLIA. Name: Ahmad, Phone: 0123456789, License: D1234567", Gemini produces code like:
pickup_date = "2026-04-09"
days = 3
return_date = (datetime.strptime(pickup_date, "%Y-%m-%d")
+ timedelta(days=days)).strftime("%Y-%m-%d")
candidates = vehicles_tbl.search(
(Query().model == "Perodua Myvi") &
(Query().status != "maintenance")
)
vehicle = None
for v in candidates:
if not has_date_conflict(v["vehicle_id"], pickup_date,
return_date, bookings_tbl):
vehicle = v
break
if vehicle is None:
STATUS = "vehicle_unavailable"
answer_text = "No Myvi available for those dates."
else:
cost = calculate_rental_cost("Economy", days, hotel_delivery=False)
bk_id = next_booking_id(bookings_tbl, "RNT")
bookings_tbl.insert({
"booking_id": bk_id,
"vehicle_id": vehicle["vehicle_id"],
"model": vehicle["model"],
"customer_name": "Ahmad",
"phone": "0123456789",
"license_no": "D1234567",
"pickup_location": "KLIA",
"pickup_date": pickup_date,
"return_date": return_date,
"days": days,
"total_amount_myr": cost["total"],
"status": "booked"
})
STATUS = "success"
answer_text = f"Booking {bk_id} confirmed for {vehicle['model']} " \
f"({pickup_date} to {return_date}). Total RM {cost['total']}."
Key Points:
- The LLM parsed the natural language request and extracted model, duration, location, and customer details
- It searched the fleet for an available Myvi and checked date conflicts
- It invoked
calculate_rental_cost with the Economy tier
- It generated a new RNT booking ID and inserted the record
- All business logic emerged dynamically, not hardcoded per intent
FastAPI Endpoints
@app.post("/api/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
content = generate_code(PROMPT.format(question=request.message))
result = execute_code(extract_code(content), request.message)
if result["error"]:
raise HTTPException(500, detail=result["error"])
return ChatResponse(answer=result["answer"], status=result["status"])
@app.get("/api/vehicles")
async def get_vehicles(status=None, tier=None):
vehicles = [v for v in vehicles_tbl.all()
if (not status or v["status"] == status)
and (not tier or v["tier"] == tier)]
return {"vehicles": vehicles, "total": len(vehicles)}
@app.get("/api/bookings")
async def get_bookings(status=None, date=None):
bookings = [b for b in bookings_tbl.all()
if (not status or b["status"] == status)
and (not date or b["pickup_date"] == date)]
return {"bookings": bookings, "total": len(bookings)}