Skip to main content

Overview

In this guide, you’ll build a flight booking agent that works like a personal travel assistant. Here’s what it does:
  • Searches Google and airline websites for the best flights
  • Analyzes options and picks the top recommendations
  • Sends you an approval email before booking anything
  • Charges your card and confirms your booking
You’ll learn how to build actions (search, scrape, book), connect two agents that work together, and deploy everything to production with one command. Time: 10 minutes • Level: Beginner

Prerequisites

1

Install Ziet

pip install ziet
2

Set your API key

export ZIET_API_KEY="your_api_key_here"
Create a key in the dashboard

Step 1: Create Your Actions

Create a file called flight_agent.py:
from ziet import Action, Agent, memory
from ziet.integrations import google, apify, openai, stripe, sendgrid
from ziet import PickActionsStrategy, HandOffStrategy, ManualApprovalStrategy, input

@Action(
    id="search_flights",
    name="Search Flights",
    description="Search Google for flight prices",
    timeout=30,
    retries=2
)
def search_flights(origin: str, dest: str, date: str) -> list:
    """Search Google for flight information."""
    query = f"flights from {origin} to {dest} on {date}"
    
    # Use built-in Google integration
    results = google.search(query, num_results=10)
    
    # Store results in memory
    memory.add(key="search_results", value=results)
    
    return results


@Action(
    id="scrape_airline",
    name="Scrape Airline Website",
    description="Scrape airline website for detailed pricing",
    timeout=60
)
def scrape_airline(url: str) -> None:
    """Extract pricing details from airline website."""
    # Use built-in Apify integration
    data = apify.scrape(
        url=url,
        extract=[".price", ".flight-details", ".airline-name"]
    )
    
    # Store HTML body in memory for later analysis
    memory.add(key=url, value=data.get("html", ""))


@Action(
    id="generate_summary",
    name="Generate Summary",
    description="Generate summary report using LLM",
    timeout=30
)
def generate_summary() -> str:
    """Create a natural language summary of findings."""
    # Retrieve search results from memory
    search_results = memory.get("search_results")
    
    # Retrieve scraped data from memory
    scraped_data = []
    for result in search_results:
        url = result.get("url")
        if url:
            body = memory.get(url)
            if body:
                scraped_data.append({"url": url, "content": body[:500]})
    
    prompt = f"""
    Analyze these flight search results and provide a summary:
    
    Search Results:
    {search_results}
    
    Detailed Pricing:
    {scraped_data}
    
    Provide:
    1. Cheapest option
    2. Best value option
    3. Recommended choice with reasoning
    """
    
    response = openai.chat(
        messages=[{"role": "user", "content": prompt}],
        model="gpt-4o-mini"
    )
    
    # Store summary in memory
    memory.add(key="final_summary", value=response)
    
    return response


@Action(
    id="book_flight",
    name="Book Flight",
    description="Book the selected flight",
    timeout=60
)
def book_flight(flight_details: dict) -> dict:
    """Book the flight."""
    # Booking logic here
    booking = {
        "booking_id": f"BK{flight_details.get('id', '12345')}",
        "status": "confirmed"
    }
    memory.add(key="booking", value=booking)
    return booking


@Action(
    id="charge_payment",
    name="Charge Payment",
    description="Charge customer payment",
    timeout=30
)
def charge_payment(amount: int, email: str) -> dict:
    """Charge payment via Stripe."""
    payment = stripe.create_payment_intent(
        amount=amount * 100,
        currency="usd"
    )
    memory.add(key="payment", value=payment)
    return payment


@Action(
    id="send_confirmation",
    name="Send Confirmation",
    description="Send booking confirmation email",
    timeout=20
)
def send_confirmation(email: str) -> bool:
    """Send confirmation email."""
    # Retrieve booking from memory
    booking = memory.get("final_booking")
    
    sendgrid.send(
        to=email,
        subject=f"Flight Booked - {booking['booking_id']}",
        body=f"<h1>Booking Confirmed</h1><p>{booking['booking_id']}</p>",
        html=True
    )
    return True

Step 2: Create Your Agents

Add the agent classes to flight_agent.py:
# Agent 1: Research and find flights
@PickActionsStrategy(picks=10, allow_repeats=True)
@HandOffStrategy(agents=["booking_agent"])
@Agent(
    id="research_agent",
    name="FlightResearcher",
    description="Research and analyze flight options",
    instructions="""
    You are a flight research agent. Your goal:
    1. Search Google for flights between the origin and destination
    2. Scrape top airline websites for detailed pricing
    3. Compare all options and identify the best 3-5 flights
    4. Store all findings in memory with key "flight_options"
    5. Hand off to the booking agent with your recommendations
    
    Prioritize value over just price. Consider flight duration, layovers, and airline quality.
    """,
    actions=["search_flights", "scrape_airline", "generate_summary"],
    model="gpt-4o-mini"
)
class FlightResearchAgent:
    pass  # Agent behavior is defined by instructions and strategies


# Agent 2: Book the selected flight
@ManualApprovalStrategy(signee=input.user_email, method="email")
@Agent(
    id="booking_agent",
    name="FlightBooker", 
    description="Book flights after user approval",
    instructions="""
    You are a flight booking agent. Your workflow:
    1. Retrieve flight options from memory (key: "flight_options")
    2. Select the best flight based on the research
    3. Request user approval via email before booking
    4. After approval: book the flight using book_flight action
    5. Send confirmation email
    6. Store booking confirmation in memory
    
    Always wait for explicit approval before charging or booking.
    """,
    actions=["book_flight", "charge_payment", "send_confirmation"],
    model="gpt-4o-mini"
)
class FlightBookingAgent:
    pass  # Agent behavior is defined by instructions and strategies

Step 3: Test Locally

Test your agent locally before deploying:
ziet run --local --agent research_agent
This runs your agent in local mode with test data. You’ll see:
  • Actions being called
  • Memory operations
  • Integration calls (mocked locally)
  • Agent handoffs
  • Strategy execution
Expected output:
🧪 Running agent locally: research_agent

[INFO] Starting local run...
[INFO] Agent research_agent initialized
[INFO] PickActionsStrategy: Selecting 10 actions
[INFO] Action search_flights started
[INFO] google.search returned 10 results (mocked)
[INFO] Memory added: key=search_results
[INFO] Action search_flights completed in 0.23s
[INFO] Action scrape_airline started (x3)
[INFO] Memory added: key=https://...
[INFO] Action generate_summary started
[INFO] Memory retrieved: search_results
[INFO] OpenAI chat completed
[INFO] Memory added: key=final_summary
[INFO] HandOffStrategy: Handing off to booking_agent
✅ Local run completed

Results: {...}

Step 4: Deploy to Production

Deploy your agent with one command:
ziet deploy
Output:
🚀 Deploying to Ziet...

✓ Analyzing code...
✓ Building agents...
✓ Uploading to cloud...
✓ Configuring infrastructure...

✅ Deployment successful!

Deployed 2 agents:
- research_agent: FlightResearcher
- booking_agent: FlightBooker

Actions deployed: 6
- search_flights, scrape_airline, generate_summary
- book_flight, charge_payment, send_confirmation

Endpoints:
  https://api.ziet.ai/agents/research_agent/run
  https://api.ziet.ai/agents/booking_agent/run

Dashboard: https://dashboard.ziet.ai/agents

Invoke via API:
  curl -X POST https://api.ziet.ai/agents/research_agent/run \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -d '{"origin": "SFO", "dest": "NYC", "user_email": "user@example.com"}'

Invoke via CLI:
  ziet run research_agent --origin "SFO" --dest "NYC" --user_email "user@example.com"

Step 5: Invoke Your Agent

Via API

curl -X POST https://api.ziet.ai/agents/research_agent/run \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "origin": "SFO",
    "dest": "NYC",
    "date": "2024-12-25",
    "user_email": "user@example.com"
  }'

Via CLI

ziet run research_agent \
  --origin "SFO" \
  --dest "NYC" \
  --date "2024-12-25" \
  --user_email "user@example.com"

Via Python SDK

from ziet import Client

client = Client(api_key="your_api_key")

result = client.run_agent(
    agent_id="research_agent",
    data={
        "origin": "SFO",
        "dest": "NYC",
        "date": "2024-12-25",
        "user_email": "user@example.com"
    }
)

print(result)

Via Dashboard

  1. Go to dashboard.ziet.ai
  2. Navigate to Agentsresearch_agent
  3. Click Run Agent
  4. Fill in the input form:
    • origin: “SFO”
    • dest: “NYC”
    • date: “2024-12-25”
    • user_email: “your@email.com
  5. Click Execute

Next Steps

Common Patterns

@Action(
    id="safe_action",
    name="Safe Action",
    description="Action with error handling",
    timeout=30,
    retries=3
)
def safe_action(data: dict) -> dict:
    try:
        result = process_data(data)
        memory.add(key="success", value=result)
        return result
    except Exception as e:
        memory.add(key="error", value={"error": str(e)})
        raise
import os

@Action(
    id="call_external_api",
    name="Call External API",
    description="Call external API with credentials"
)
def call_api(endpoint: str) -> dict:
    api_key = os.getenv("EXTERNAL_API_KEY")
    # Use api_key...
Set in dashboard: DeveloperEnvironment Variables
@PickActionsStrategy(picks=5, allow_repeats=False)
@WaitStrategy(memory=["data_ready"], timeout=300)
@HandOffStrategy(agents=["processing_agent"])
@Agent(
    id="analysis_agent",
    name="AnalysisAgent",
    instructions="Process data when ready, pick best 5 actions, then hand off",
    actions=["action_1", "action_2", "action_3", "action_4", "action_5"]
)
class AnalysisAgent:
    pass
@Action(
    id="analyze_options",
    name="Analyze Options",
    description="Analyze stored options"
)
def analyze_options(query: str) -> list:
    # Semantic search across all memories
    results = memory.search("cheapest flight option", limit=5)
    
    best_options = [entry["value"] for entry in results]
    return best_options

Need Help?