Imported from AimelHassan/khidmat-ai_hackathon (
traces_and_logs/AGENTS.md). Install upstream withnpx skills add AimelHassan/khidmat-ai_hackathon --skill traces_and_logs. Copyright stays with the author.
Google Antigravity — Backend Agent Logic Prompt
Project: KhidmatAI — AI Service Orchestrator for Informal Economy
CONTEXT & GOAL
You are building the AGENTIC BRAIN for a hackathon submission. This is a Python-based agentic backend deployed on Google Cloud Run. It receives a natural language service request from a mobile app (to be built later), runs a multi-step agentic reasoning pipeline powered by Gemini 3 Flash, and returns structured results including booking confirmation.
This backend is the true "brain" of the system. It must demonstrate clear, traceable agentic behavior and autonomy — not just sequential, hardcoded API calls. The agents should decide how to formulate queries, when to use tools, and how to recover from failures autonomously. Every reasoning step must be logged and returned to the frontend so judges can see the agent thinking.
The mobile Flutter app calls this backend via REST. Firebase Firestore is the shared data store.
TECH STACK
- Language: Python 3.11
- Framework: FastAPI
- LLM: Gemini 3 Flash via
google-generativeaiSDK - Database: Firebase Admin SDK → Firestore
- Deployment: Google Cloud Run
- Environment:
.envfile withGOOGLE_API_KEY,GOOGLE_MAPS_API_KEY,FIREBASE_CREDENTIALS_PATH,PROJECT_ID - Logging: Python
loggingmodule + structured JSON logs for Cloud Run
SYSTEM ARCHITECTURE
Mobile App (Flutter)
│
▼
FastAPI on Cloud Run
│
├── /analyze ←── Main agent entry point
│ │
│ ▼
│ AgentOrchestrator
│ │
│ ├── Step 1: IntentParserAgent (Gemini 3 Flash)
│ ├── Step 2: ProviderSearchAgent (Firestore query + Google Maps API)
│ ├── Step 3: RankingAgent (Gemini 3 Flash reasoning)
│ ├── Step 4: DecisionAgent (Gemini 3 Flash)
│ └── Step 5: BookingAgent (Firestore write)
│
├── /book ←── Confirm booking
├── /bookings/{user_id} ←── List bookings
└── /session/{session_id}/status ←── Polling endpoint
Each agent step writes its output to a session document in Firestore so the mobile app can poll it in real time.
AGENT PIPELINE — BUILD EACH STEP COMPLETELY
Step 1: IntentParserAgent
Purpose: Parse raw user input (Urdu/Roman Urdu/English mixed) into structured intent.
Input: Raw string e.g. "Mujhe kal subah G-13 mein AC technician chahiye"
Gemini 3 Flash Prompt:
You are an intent parser for a Pakistani home services app.
Extract structured information from this service request.
The input may be in Urdu, Roman Urdu, English, or a mix.
Input: "{user_input}"
Return ONLY valid JSON with these exact fields:
{{
"service_type": "string (normalized in English e.g. AC Technician, Plumber, Electrician, Home Tutor, Beautician)",
"location": "string (sector/area name e.g. G-13, F-7, H-8)",
"time_preference": "string (normalized e.g. Tomorrow Morning, Today Afternoon, This Weekend)",
"time_slot": "string (ISO-like e.g. tomorrow_morning, today_afternoon, weekend)",
"urgency": "normal | urgent",
"confidence": 0.0-1.0,
"original_language": "urdu | roman_urdu | english | mixed",
"notes": "any additional context from the request"
}}
If a field cannot be determined, use null. Never guess wildly.
Output: Pydantic model IntentResult
Reasoning log entry:
{
"step": "intent_parsing",
"status": "done",
"detail": "Detected: AC Technician in G-13, Tomorrow Morning (confidence: 0.94)",
"raw_output": { ...parsed intent... },
"timestamp": "ISO datetime"
}
Step 2: ProviderSearchAgent
Purpose: An autonomous agent that decides how to search for providers using the Google Maps Places API based on user intent.
Agentic Logic & Tool Usage:
- Query Formulation: The agent receives the parsed intent and formulates a search query (e.g., "AC Technician near G-13, Islamabad").
- Tool Execution: The agent calls a
search_google_mapstool to execute the query against the Places API (Text Search or Nearby Search). - Data Extraction: The agent processes the real-world provider data from the API response (Name, Rating, Location, etc.) and maps it to the
Providerschema. - Autonomous Fallback: If the tool returns 0 providers or very few results, the agent autonomously decides to loosen the search query (e.g., dropping "G-13" and searching city-wide "AC Technician Islamabad") and calls the tool again.
- If still 0 providers after retries, the agent gracefully fails and returns an empty list with a reasoning note.
Reasoning log entry:
{
"step": "provider_search",
"status": "done",
"detail": "Found 8 AC Technician providers within 5km of G-13",
"candidates_count": 8,
"fallback_triggered": false,
"timestamp": "ISO datetime"
}
Step 3: RankingAgent
Purpose: Use Gemini 3 Flash to reason about provider ranking, not just sort by a number.
Input: List of candidate providers with distance, rating, availability
Gemini 3 Flash Prompt:
You are a smart service matching agent for a Pakistani home services platform.
A user needs: {service_type} in {location} at {time_preference}.
Here are the available providers (already filtered by category and availability):
{providers_json}
Your task:
1. Rank these providers from best to worst for this specific request
2. Consider: distance (closer = better), rating (higher = better), availability
3. Give extra weight to providers within 3km
4. Penalize providers with rating below 4.0
Return ONLY valid JSON:
{{
"ranked_provider_ids": ["id1", "id2", "id3", ...],
"ranking_reasoning": "2-3 sentence explanation of why top provider was chosen",
"top_provider_id": "id1",
"confidence": 0.0-1.0
}}
Reasoning log entry:
{
"step": "ranking",
"status": "done",
"detail": "Ranked 8 providers. Top pick: Ali AC Services (2.1km, 4.7★) — closest with highest rating",
"ranking_reasoning": "...",
"timestamp": "ISO datetime"
}
Step 4: DecisionAgent
Purpose: Make the final selection and generate a human-readable explanation. This is where the agent shows "autonomy."
Input: Ranked list + full provider details + user intent
Gemini 3 Flash Prompt:
You are the decision-making agent for KhidmatAI, a service booking assistant.
User request: "{original_input}"
Parsed intent: {intent_json}
Selected provider: {top_provider_json}
Alternatives: {alternatives_json}
Generate a friendly, concise explanation (2 sentences max) of why this provider was selected.
Write it as if you are the AI assistant speaking to the user directly.
Keep it simple. Mention distance and rating naturally.
Output in English only.
Return ONLY valid JSON:
{{
"explanation": "string",
"suggested_time": "e.g. Tomorrow at 10:00 AM",
"confirmation_message": "short booking summary in simple English/Urdu mix"
}}
Reasoning log entry:
{
"step": "decision",
"status": "done",
"detail": "Final decision made. Provider: Ali AC Services. Suggested time: Tomorrow 10:00 AM",
"explanation": "...",
"timestamp": "ISO datetime"
}
Step 5: BookingAgent
Purpose: An execution agent that securely handles state changes and simulates real-world actions.
Agentic Logic & Tool Usage: The agent is provided with the final decision and must use specific simulated tools to complete the workflow. It decides the sequence of execution and logs each action:
- Call
create_booking_record_toolto write the document to/bookings/{booking_id}in Firestore. - Call
notify_provider_toolto simulate sending a WhatsApp/SMS to the provider (logs the message, doesn't actually send). - Call
schedule_reminder_toolto simulate calculatingreminder_timeand queuing a notification. - Call
generate_receipt_toolto compile the final JSON receipt for the user. - Call
update_provider_availability_toolto setavailable=falsein Firestore for that time slot (if applicable).
Booking document schema:
{
"booking_id": "BK-YYYYMMDD-XXXX", # auto-generated
"user_id": str,
"provider_id": str,
"provider_name": str,
"service_type": str,
"location": str,
"scheduled_time": datetime,
"reminder_time": datetime,
"status": "confirmed",
"agent_reasoning": [...all reasoning steps...],
"actions_taken": [
"booking_created",
"provider_notified",
"reminder_scheduled",
"receipt_generated",
"provider_availability_updated"
],
"created_at": datetime
}
Reasoning log entry:
{
"step": "booking",
"status": "done",
"detail": "Booking BK-20240521-0042 confirmed. 5 actions executed.",
"actions_taken": [...],
"booking_id": "BK-20240521-0042",
"timestamp": "ISO datetime"
}
FASTAPI ENDPOINTS — BUILD ALL OF THESE
POST /analyze
# Full agent pipeline
# 1. Create session in Firestore with status="processing"
# 2. Run all 5 agent steps sequentially
# 3. After each step, update session doc in Firestore with new reasoning step
# 4. Return final complete result
# Handle: timeout after 30s, partial failure with graceful error
POST /book
# Confirm a booking from a completed session
# Trigger BookingAgent only
# Return booking confirmation
GET /bookings/{user_id}
# Query Firestore /bookings where user_id == user_id
# Return list sorted by created_at desc
GET /session/{session_id}/status
# Polling endpoint
# Return current reasoning steps from Firestore session doc
# Mobile app polls this every 1.5s during reasoning screen
GET /health
# Simple health check for Cloud Run
# Return {"status": "ok", "timestamp": ...}
EDGE CASES & ROBUSTNESS (MANDATORY FOR JUDGES)
Implement and test all of these:
- No providers found → Return
fallback=true, explain what was tried, suggest expanding radius - Ambiguous location → e.g. user says "meri gali" (my street) — IntentParser returns
location=null, backend returns structured error asking for clarification - Ambiguous service → e.g. "koi aajaye" (someone come) — return low confidence score + ask for service type
- Provider becomes unavailable mid-session → BookingAgent catches Firestore conflict, selects next ranked provider automatically, logs the retry
- Gemini API timeout → Catch exception, return partial results with
status="partial", log the failure step - Invalid input (empty string, gibberish) → IntentParser returns
confidence < 0.3, return structured error - Google Maps API Failure / Quota Exceeded → Catch
googlemaps.exceptions.ApiError, gracefully fallback to querying the mock Firestore/providersdatabase using Haversine distance calculations. - LLM JSON Parsing Failure → If Gemini returns malformed JSON, catch
JSONDecodeError, automatically strip markdown code fences, and retry up to 2 times before failing gracefully.
Each edge case must produce a structured JSON response, never a 500 error.
SESSION MANAGEMENT IN FIRESTORE
/sessions/{session_id}
- user_id
- original_input
- status: "processing" | "complete" | "failed" | "partial"
- reasoning_steps: [] ← updated after each agent step
- result: {} ← populated when complete
- created_at
- updated_at
- error: null | string
After each agent step completes, immediately write the step to reasoning_steps array in Firestore. This is what the mobile app polls to show the live reasoning animation.
LOGGING REQUIREMENTS (FOR JUDGE TRACES)
Every agent step must log to stdout in this exact JSON format (Cloud Run captures this):
{
"timestamp": "ISO datetime",
"session_id": "abc123",
"agent": "IntentParserAgent | ProviderSearchAgent | RankingAgent | DecisionAgent | BookingAgent",
"step": "intent_parsing | provider_search | ranking | decision | booking",
"status": "started | done | failed | fallback",
"input_summary": "brief description of input",
"output_summary": "brief description of output",
"llm_called": true | false,
"tokens_used": 0,
"latency_ms": 0,
"detail": "human readable explanation"
}
This structured log IS the "Agent Trace" required for submission. Cloud Run automatically collects these. Export them for the README.
COST & SCALABILITY NOTES TO IMPLEMENT
Add a /metrics endpoint that returns:
{
"cost_per_request_estimate": {
"gemini_3_flash_tokens_avg": 1200,
"cost_usd": 0.00018,
"firestore_reads_avg": 12,
"firestore_cost_usd": 0.000004,
"total_per_request_usd": 0.000184
},
"scaling_estimate": {
"requests_per_dollar": 5434,
"100x_daily_requests": "cost ~$0.018/day",
"cloud_run_latency_p50_ms": 1200,
"bottleneck": "Gemini 3 Flash API latency"
}
}
These numbers will go directly into the README submission requirement for cost/scalability.
BASELINE COMPARISON ENDPOINT
Add a POST /analyze/baseline endpoint that solves the same request using simple heuristics only (no LLM):
- Parse service type by keyword matching
- Return nearest provider by distance only (no reasoning)
- No ranking explanation
Then add a POST /analyze/compare endpoint that runs both and returns:
{
"agentic": { ...full result... },
"baseline": { ...simple result... },
"comparison": {
"agentic_better_because": [
"Understands Roman Urdu without keyword matching",
"Considers rating + distance together, not just distance",
"Provides explainable reasoning",
"Handles ambiguous inputs gracefully",
"Adapts when first provider unavailable"
],
"baseline_limitations": [
"Fails on Urdu/Roman Urdu input",
"No explanation for selection",
"No fallback on unavailability",
"Fixed rules, no reasoning"
]
}
}
This satisfies the baseline comparison submission requirement directly.
MOCK DATA SEEDER
Create seed_providers.py that populates Firestore /providers with 15 providers:
MOCK_PROVIDERS = [
{"id": "p001", "name": "Ali AC Services", "category": "AC Technician", "rating": 4.7, "lat": 33.6850, "lng": 73.0490, "available": True, "phone": "0300-1234567", "experience_years": 8},
{"id": "p002", "name": "Hassan Cooling Solutions", "category": "AC Technician", "rating": 4.2, "lat": 33.6920, "lng": 73.0550, "available": True, "phone": "0301-2345678", "experience_years": 5},
{"id": "p003", "name": "Khan AC Repair", "category": "AC Technician", "rating": 3.9, "lat": 33.7100, "lng": 73.0400, "available": True, "phone": "0302-3456789", "experience_years": 3},
# ... plumbers, electricians, tutors, beauticians
# generate 15 total with realistic Pakistani names and Islamabad coordinates
]
DELIVERABLES FROM THIS PROMPT
Generate these files completely — no placeholders:
main.py— FastAPI app, all routesagents/intent_parser.py— IntentParserAgent classagents/provider_search.py— ProviderSearchAgent classagents/ranking.py— RankingAgent classagents/decision.py— DecisionAgent classagents/booking.py— BookingAgent classagents/orchestrator.py— AgentOrchestrator that runs all 5 stepsmodels/schemas.py— All Pydantic modelsservices/firestore_service.py— All Firestore operationsservices/gemini_service.py— Gemini 3 Flash wrapper with retry logicservices/maps_service.py— Google Maps API wrapperutils/haversine.py— Distance calculation (fallback)utils/booking_id.py— Booking ID generatorutils/logger.py— Structured JSON loggerseed_providers.py— Firestore seeder scriptrequirements.txt— All dependencies pinnedDockerfile— For Cloud Run deployment.env.example— TemplateREADME.md— Full documentation