# Project export: AeroFreight AI

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2026
- Tagline: AeroFreight AI: A multi-agent platform that plans smarter international shipments from origin to final delivery, whether through air or sea.
- Devpost: https://devpost.com/software/aerofreight-ai
- GitHub: https://github.com/aniketggg/AeroFreight-AI
- Demo: https://docs.google.com/presentation/d/1hJPsd8jtFylR9ah5Q0OP9WI32L5B94Ub/edit?usp=sharing&ouid=102749372460662281325&rtpof=true&sd=true
- Video: https://www.youtube.com/embed/5XbmtxZjauw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (Best Use of The Agentverse by Fetch AI)
- Team: 7 GitHub contributor(s) — Aniket Gupta (18 commits), riyakhasnis (15 commits), np2024 (13 commits), Ashwin Kalyan (5 commits), Claude Sonnet 4.6 (4 commits), Cursor (2 commits), copilot-swe-agent[bot] (1 commits)

## Devpost submission (written by the team)

### Overview

Fetch.ai Track Submission 🤖 Complete ASI:One Workflow: https://asi1.ai/shared-chat/3a7383cc-c9a7-412c-a473-0e0665ab97ea ASI Demo: https://youtu.be/EdWXfnOk8GI?is=RygbgCXSJ7HwRoXo **Agentverse Profiles: AeroFreight Orchestrator The central user-facing agent that handles ASI:One chat interactions, session state, and coordinates tasks among the sub-agents. AeroFreight Orchestrator The central user-facing agent that handles ASI:One chat interactions, session state, and coordinates tasks among the sub-agents. Economic Constraints Agent Analyzes transport preferences and calculates necessary international taxes and customs requirements. Economic Constraints Agent Analyzes transport preferences and calculates necessary international taxes and customs requirements. Routing Agent The primary routing decision-maker that evaluates the extracted data to determine the optimal shipping method. Routing Agent The primary routing decision-maker that evaluates the extracted data to determine the optimal shipping method. Air Freight Sub-Agent Specialized agent responsible for quoting and logistics mapping for air-based transit routes. Air Freight Sub-Agent Specialized agent responsible for quoting and logistics mapping for air-based transit routes. Ship Freight Sub-Agent Specialized agent responsible for quoting and logistics mapping for sea-based maritime freight. Ship Freight Sub-Agent Specialized agent responsible for quoting and logistics mapping for sea-based maritime freight. Treasury Agent Handles the final checkout pipeline, integrating the Stripe payment wall, generating PDF invoices, and managing documentation. Treasury Agent Handles the final checkout pipeline, integrating the Stripe payment wall, generating PDF invoices, and managing documentation. GitHub: [https://github.com/aniketggg/AeroFreight-AI] Problem: International freight planning is fragmented across routing, cost estimation, and payment. Target User: Businesses importing goods into the United States. Outcome: AeroFreight AI produces a validated route, landed-cost estimate, and user-approved settlement workflow. We designed AeroFreight AI as a four-agent system: one central Orchestrator and three specialized agents. Each agent has a clearly defined responsibility, typed inputs and outputs, and an independent Agentverse-compatible interface, allowing the workflow to fit naturally within the Fetch.ai ecosystem and expand with additional logistics agents. The project demonstrates multi-agent collaboration, ASI: One integration, structured agent-to-agent messaging, external transportation data, failure handling, and a human-approved payment workflow. One shipment request. Specialized agents. One coordinated international freight workflow.

### Inspiration

💡 International shipping is fragmented across route planning, cost estimation, and payment systems. Before a shipment can move, businesses must compare freight modes, calculate tariffs, identify transportation hubs, plan inland delivery, and approve payment. We built AeroFreight AI to coordinate this workflow through a network of specialized autonomous agents. Each agent focuses on a specific task while a central orchestrator maintains the shared shipment state. What It Does 🚀 AeroFreight AI converts a natural-language shipping request into a structured freight plan for shipments traveling from an international origin to a destination in the United States. The user provides: origin and destination; cargo details; weight and volume; declared value; preference for speed or lower cost. If information is missing, the system asks a follow-up question before continuing. The completed request then moves through four coordinated stages. 1. Orchestrator Agent The Orchestrator acts as the central coordinator. It: connects the user experience to ASI:One; converts natural language into structured shipment data; validates required fields; stores the shared shipment state; communicates with each agent in sequence. 2. Economist Agent The Economist Agent evaluates the shipment's financial and physical constraints. It determines: whether the cargo is high-value or luxury; estimated U.S. tariffs and entry taxes; whether the shipment should use AIR, SHIP, or EITHER. 3. Routing Agent The Routing Agent calculates route options, transportation cost, and estimated transit time. It coordinates two Fetch.ai sub-agents: AIR Agent — evaluates airport-based routes; SHIP Agent — evaluates seaport-based routes. Each sub-agent calculates: route nodes; countries visited; inland trucking; freight charges; route fees; estimated transit time. When both modes are allowed, the system prioritizes based on the user's SPEED or COST preference and returns a validated RouteData object. 4. Treasury and Settlement Agent The Treasury and Settlement Agent generates the final shipment summary, including: recommended route; transportation mode; itemized cost breakdown; total landed cost. The user must explicitly approve the transaction before settlement begins. System Architecture 🏗️ AeroFreight AI uses a centralized hub-and-spoke architecture. The Orchestrator maintains the global shipment state, while each agent receives only the information required for its task. How We Built It 🛠️ Technology Stack Python 3.11 and 3.12 Fetch.ai uAgents ASI:One Pydantic airport and seaport datasets Structured Agent Communication Each workflow stage communicates through typed request and response messages. We created shared Pydantic models for: ShipmentRequest EconData RouteData SettlementStatus These shared schemas prevent inconsistencies between independently developed agents. Agent-to-Agent Messaging Agents communicate asynchronously through Fetch.ai protocols. The Orchestrator manages the flow, ensuring each agent receives validated input from the previous step. For dependent operations, we use: Geographic Routing The Routing Agent uses airport and seaport coordinates to estimate great-circle distance with the Haversine formula. This includes inland transportation instead of comparing only airport-to-airport or port-to-port distance. Cost and Time Comparison The total landed cost is calculated as: Challenges We Faced 🧩 Agent Integration Small differences in field names, data types, or expected outputs could break the workflow. We solved this by treating shared Pydantic schemas as fixed interfaces between agents. Transportation Data Airport and seaport datasets use different identifiers, coordinate formats, country codes, and naming conventions. We added normalization and fallback logic so both routing agents could use a consistent process. Asynchronous Dependencies The workflow must execute in order: This required careful handling of asynchronous messages, validation, timeouts, agent addresses, and downstream failures. Human Control International shipping and payment decisions can have major legal and financial consequences. AeroFreight AI therefore requires explicit user confirmation before settlement. What We Learned 🎓 Multi-agent systems work best when every agent has: a clear responsibility; a limited and stable interface; validated inputs and outputs; access only to the data required for its task. This structure made AeroFreight AI easier to test, debug, integrate, and extend. We also gained experience with: Fetch.ai uAgents; ASI:One integration; asynchronous messaging; Pydantic validation; hub-and-spoke orchestration; geospatial routing; transportation data normalization; cost-versus-time optimization; human-in-the-loop approval; environment-based credential management. Most importantly, we learned that autonomous agents can do more than generate text. With structured data and reliable communication, they can collaborate on complex operational workflows. Responsible AI and Privacy 🔐 AeroFreight AI is designed as a decision-support platform rather than an unchecked autonomous authority. The system clearly displays: transportation mode; route nodes; countries visited; freight costs; entry taxes; total landed cost. Users can reject the proposed transaction, and explicit confirmation is required before settlement. Credentials and agent seeds are stored in environment variables, secrets are excluded from version control, and typed schemas limit unnecessary data sharing. Environmental Impact 🌱 Transportation mode affects a shipment's environmental footprint. A future version could add estimated carbon emissions so users can compare environmental impact alongside cost and delivery time. What's Next 🔮 Future improvements include: live freight pricing; real-time weather and port congestion; updated tariff and customs APIs; live shipment tracking; rail and trucking agents; carbon-emission estimates; sanctions screening; automated carrier bidding; dynamic route replanning; production-grade payment and escrow. Our long-term vision is for AeroFreight AI to become an intelligent logistics coordination layer that helps businesses plan, approve, and execute international shipments through a trusted network of specialized agents. One request. Multiple agents. One smarter freight workflow.

## README (from the GitHub repository)


# AeroFreight AI

[Devpost Submission](https://devpost.com/software/aerofreight-ai)

**AeroFreight AI** is an autonomous, multi-agent logistics orchestration platform built on the [Fetch.ai uAgents framework](https://fetch.ai/). A swarm of specialized agents, governed by strict Pydantic data contracts, automates the end-to-end logistics lifecycle: natural-language intent parsing, mode/route selection, pricing, and simulated financial settlement (Stripe checkout + PDF invoicing).

---

## Architecture Overview

The system employs a **Hub-and-Spoke** model. A centralized **Orchestrator Agent** acts as the system's "brain," coordinating specialized teammate agents — **Economic Agent** (pricing), **Riya/Routing Agent** (route + carrier selection), and **Treasury Agent** (invoicing + payment). Each teammate can run as a local in-process mock or as a remote uAgent reachable over the Fetch.ai network.

### The Workflow Loop

```text
User message (CLI, Agent Chat Protocol, or browser UI via server.py)
  → ConversationController
  → ClaudeShipmentExtractor (natural-language extraction)
  → OrchestratorService + validation (deterministic Python)
  → WorkflowCoordinator
  → [Mock or Remote] Economist, Routing, and Treasury agents
  → Quote → User CONFIRM → Stripe checkout (simulated) → Invoice → COMPLETED
```

---

## Technical Stack

* **Runtime:** Python 3.11+
* **Agent Framework:** `uagents` (Fetch.ai)
* **Data Validation:** `Pydantic` (strict inter-agent contracts in [shared_models.py](shared_models.py))
* **LLM:** Anthropic Claude (`anthropic` SDK, default model `claude-opus-4-8`)
* **Web/API:** `FastAPI` + `uvicorn` ([server.py](server.py)) serving a static browser demo ([index.html](index.html))
* **Payments:** Stripe (embedded checkout via `treasury_agent/payment_backend.py`)
* **Invoicing:** `reportlab` (PDF generation), with optional Google Drive upload for invoice links
* **Testing:** `pytest`, with mocked Anthropic/Stripe clients

---

## Getting Started

### 1. Installation

```bash
git clone https://github.com/aniketggg/AeroFreight-AI/
cd AeroFreight-AI
python -m venv .venv && source .venv/bin/activate   # or .venv\Scripts\activate on Windows
pip install -r requirements.txt
```

NOTE: You will need to refer to the fetchai-asi branch if you want to run the code specifically backend based only using the ASI ONE Platform.

### 2. Configuration

Copy [.env.example](.env.example) to `.env` and fill in your keys. **Never commit `.env`.** Key variables:

```text
# --- LLM ---
ANTHROPIC_API_KEY=replace_with_your_key
ANTHROPIC_MODEL=claude-opus-4-8

# --- Agent network ---
AGENT_SEED=replace_with_a_private_random_seed
AGENT_NAME=aerofreight-orchestrator
AGENT_PORT=8001

# Leave blank to fall back to the local mock agents
ECONOMIST_AGENT_ADDRESS=
ROUTER_AGENT_ADDRESS=
TREASURY_AGENT_ADDRESS=

# --- Treasury process (separate agent) ---
TREASURY_AGENT_NAME=aerofreight-treasury-agent
TREASURY_AGENT_SEED=
TREASURY_AGENT_PORT=8014
ORCHESTRATOR_AGENT_ADDRESS=

# --- Stripe ---
STRIPE_SECRET_KEY=sk_test_...
STRIPE_PUBLISHABLE_KEY=
STRIPE_RETURN_URL=https://agentverse.ai

# --- Optional: Google Drive invoice upload ---
GOOGLE_DRIVE_FOLDER_ID=
GOOGLE_SERVICE_ACCOUNT_JSON=
```

See [.env.example](.env.example) for the full list of supported variables.

### 3. Running it

* **Local CLI demo** (no network agents, mocked teammates):
  ```bash
  python -m orchestrator.cli
  ```
* **Browser demo** (FastAPI bridge driving real Stripe checkout + invoice generation):
  ```bash
  uvicorn server:app --reload
  ```
  then open `index.html` via the server's root route.
* **Distributed mode** — run teammate agents and the orchestrator as separate uAgents, each in its own terminal:
  ```bash
  python -m economic_agent.agent
  python -m step3_riya.agent
  python -m treasury_agent.agent
  python -m orchestrator.agent
  ```

---

## Integration: ASI:One & Agentverse

The Orchestrator exposes the workflow via the **Agent Chat Protocol**:

1. Run `python -m orchestrator.agent`.
2. Open the **Inspector URL** printed in the terminal.
3. Connect via **Mailbox** to chat with the agent through the **ASI:One** interface.

---

## Logic & Constraints

* **Deterministic safety:** Claude performs natural-language intent extraction only. All workflow transitions, validation, and pricing math are deterministic Python in [orchestrator/validation.py](orchestrator/validation.py) and [orchestrator/service.py](orchestrator/service.py).
* **Mode/route selection:** Handled by the routing agent ([step3_riya](step3_riya)), which resolves airports/seaports/cities from local reference data (`step3_riya/data/`) and applies route logic to compare carriers/modes.
* **Settlement:** Once a quote is accepted (`CONFIRM`), the Treasury Agent ([treasury_agent](treasury_agent)) creates a Stripe checkout session, then on payment confirmation generates an itemized PDF invoice (optionally uploaded to Google Drive).

---

## Project Structure

```text
shared_models.py              # Inter-agent Pydantic contracts
schemas.py                    # Additional shared schemas
server.py                     # FastAPI bridge for the browser demo (index.html)
index.html                    # Static browser UI for the demo

orchestrator/
  agent.py                    # uAgent + Agent Chat Protocol entry point
  cli.py                       # Interactive local CLI demo
  conversation.py              # ConversationController
  extractor.py                  # Claude-based shipment extraction
  coordinator.py                  # WorkflowCoordinator
  service.py                        # Workflow state machine
  validation.py                       # Deterministic data validation
  mock_agents.py                       # Local in-process mock teammate agents
  remote_agents.py                      # Remote uAgent clients
  location_normalization.py              # Address/location cleanup
  session_store.py                        # Conversation/session persistence
  uagents_mailbox.py / uagents_storage.py  # Mailbox + storage helpers

economic_agent/                # Pricing teammate agent
step3_riya/                    # Routing teammate agent (airports/ports/cities lookups)
treasury_agent/                # Invoicing + Stripe settlement teammate agent

tests/                         # Unit tests, with mocked Anthropic/Stripe clients
```

---

*Warning: All freight costs, tariffs, routes, documents, and payments in this repository are simulated demo values for research purposes.*


## Detected evidence (automated analysis)

Indexed codebase: 76 recognized source files, 509 KB.
- Anthropic (technology) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- Python (language) — detected in the code
- AI coding agent: Claude Code — evidence: commit authorship or trailers
- AI coding agent: Cursor — evidence: commit authorship or trailers

## Codebase structure (from repository index)

### Files (84 of 84)

```
.env.example
.gitignore
economic_agent/__init__.py
economic_agent/agent.py
economic_agent/demo.py
economic_agent/economics.py
economic_agent/messages.py
economic_agent/README.md
economic_agent/run_local.py
economic_agent/test_agent.py
economic_agent/test_economics.py
index.html
orchestrator/__init__.py
orchestrator/agent_interfaces.py
orchestrator/agent.py
orchestrator/cli.py
orchestrator/conversation.py
orchestrator/coordinator.py
orchestrator/extractor.py
orchestrator/location_normalization.py
orchestrator/mock_agents.py
orchestrator/models.py
orchestrator/payment_diagnostic.py
orchestrator/payment_trace.py
orchestrator/remote_agents.py
orchestrator/service.py
orchestrator/session_store.py
orchestrator/uagents_mailbox.py
orchestrator/uagents_storage.py
orchestrator/validation.py
README.md
requirements.txt
schemas.py
server.py
setup.cfg
shared_models.py
step3_riya/__init__.py
step3_riya/.env.example
step3_riya/agent.py
step3_riya/air_agent.py
step3_riya/airport_data.py
step3_riya/city_data.py
step3_riya/data/airports.csv
step3_riya/data/cities1000.txt
step3_riya/data/ports.csv
step3_riya/local_bureau_demo.py
step3_riya/port_data.py
step3_riya/quote_models.py
step3_riya/route_logic.py
step3_riya/routing_models.py
step3_riya/ship_agent.py
step3_riya/test_route.py
tests/conftest.py
tests/test_agent_chat.py
tests/test_conversation.py
tests/test_coordinator.py
tests/test_extractor.py
tests/test_mock_agents.py
tests/test_orchestrator_payment.py
tests/test_orchestrator_service.py
tests/test_payment_trace.py
tests/test_remote_agents.py
tests/test_route_coordinates.py
tests/test_router_resolution.py
tests/test_session_store.py
tests/test_shared_models.py
tests/test_step3_riya_package.py
tests/test_treasury_agent_package.py
tests/test_treasury_invoice.py
tests/test_treasury_messages.py
tests/test_treasury_payment_backend.py
tests/test_treasury_pricing.py
tests/test_uagents_mailbox.py
tests/test_uagents_storage.py
tests/test_us_destination_normalization.py
tests/test_validation.py
treasury_agent/__init__.py
treasury_agent/agent.py
treasury_agent/drive_upload.py
treasury_agent/invoice.py
treasury_agent/messages.py
treasury_agent/payment_backend.py
treasury_agent/payment_protocol.py
treasury_agent/pricing.py
```

### Dependencies

- requirements.txt: anthropic, fastapi, pydantic@>=2,<3, pytest@>=8,<9, python-dotenv, reportlab, stripe, uagents@==0.25.2, uvicorn

### Recent commits (newest first)

- Fix clone command formatting in README
- Update Anthropic model version in README
- Fix formatting of note in README.md
- Update README with note on fetchai-asi branch
- Update installation instructions with correct repo URL
- Update LLM model version in README
- Merge pull request #9 from aniketggg/claude/awesome-ishizaka-9eb54b
- Rewrite README to match actual repo structure and stack
- update seed
- Merge pull request #8 from aniketggg/claude/great-dirac-0957d9
- Switch the boarding-pass clock from UTC to Pacific Time
- Merge pull request #7 from aniketggg/claude/great-dirac-0957d9
- Remove the dismiss control from the Stripe payment modal
- Include invoice/Drive link text in the final settlement message
- Merge pull request #6 from aniketggg/claude/great-dirac-0957d9
- Wire Dispatch to Swarm button to the agent pipeline and Stripe checkout
- Include collection chat history in Claude extraction and improve routing diagnostics.
- Merge pull request #5 from aniketggg/riya-routing-agent
- Merge branch 'main' into riya-routing-agent
- hopefully this is final read me

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
anthropic
pydantic>=2,<3
python-dotenv
pytest>=8,<9
uagents==0.25.2
fastapi
uvicorn
stripe
reportlab
# Optional, only needed if GOOGLE_* Drive env vars are set for invoice upload:
# google-api-python-client
# google-auth-oauthlib

```

### server.py

```python
"""Local HTTP bridge between index.html and the AeroFreight agent pipeline.

Runs the same local/mock economist -> router -> treasury pipeline the
orchestrator uses, then drives a real Stripe embedded checkout and invoice
generation/upload. No uAgents messaging involved - this is a thin synchronous
wrapper for local-only use (`uvicorn server:app --reload`).
"""

from __future__ import annotations

import os
import tempfile
from typing import Any
from uuid import uuid4

from dotenv import load_dotenv
from fastapi import FastAPI
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel

from shared_models import DocTemplates, EconData, Item, RouteData, ShipmentRequest
from orchestrator.mock_agents import MockEconomistAgent, MockRoutingAgent
from treasury_agent.drive_upload import upload_invoice_and_get_link
from treasury_agent.invoice import generate_invoice_pdf
from treasury_agent.payment_backend import (
    create_settlement_checkout,
    is_configured as stripe_is_configured,
    verify_checkout_paid,
)
from treasury_agent.pricing import compute_service_fee

load_dotenv()

app = FastAPI()

_PENDING: dict[str, dict[str, Any]] = {}

_INDEX_PATH = os.path.join(os.path.dirname(__file__), "index.html")


class DispatchPayload(BaseModel):
    awb_number: str = ""
    priority: str = "COST"
    route: dict[str, Any]
    cargo: dict[str, Any]
    specs: dict[str, Any]


class FinalizePayload(BaseModel):
    session_id: str


def _shipment_from_payload(payload: DispatchPayload) -> ShipmentRequest:
    origin = payload.route.get("origin", {})
    destination = payload.route.get("destination", {})
    line_items = payload.cargo.get("line_items", [])
    items = [
        Item(
            name=item.get("description", "") or "Item",
            quantity=int(item.get("quantity") or 0),
            category=item.get("category", "general"),
        )
        for item in line_items
    ]
    return ShipmentRequest(
        origin={
            "country": origin.get("country", ""),
            "state": origin.get("state", ""),
            "city": origin.get("city", ""),
        },
        destination={
            "country": destination.get("country", ""),
            "state": destination.get("state", ""),
            "city": destination.get("city", ""),
        },
        items=items,
        total_weight_kg=float(payload.specs.get("gross_weight_kg") or 0),
        total_volume_cbm=float(payload.specs.get("volume_cbm") or 0),
        timeframe=payload.priority if payload.priority in ("SPEED", "COST") else "COST",
        declared_value_usd=float(payload.specs.get("declared_value_usd") or 0),
    )


def _doc_templates(shipment: ShipmentRequest) -> DocTemplates:
    return DocTemplates(
        required_form_names=["Commercial Invoice"],
        blank_form_structures={
            "Commercial Invoice": {
                "status": "SIMULATED_DRAFT",
                "origin": shipment.origin,
                "destination": shipment.destination,
                "declared_value_usd": shipment.declared_value_usd,
            }
        },
    )


@app.get("/")
def index() -> FileResponse:
    return FileResponse(_INDEX_PATH)


@app.post("/api/dispatch")
def dispatch(payload: DispatchPayload) -> JSONResponse:
    shipment = _shipment_from_payload(payload)
    econ: EconData = MockEconomistAgent().analyze(shipment)
    route: RouteData = MockRoutingAgent().route(shipment, econ)
    fee = compute_service_fee(econ, route)
    docs = _doc_templates(shipment)

    session_id = uuid4().hex

    quote = {
        "selected_mode": route.selected_mode,
        "route_nodes": route.optimal_route_nodes,
        "freight_and_toll_cost_usd": route.freight_and_toll_cost_usd,
        "base_entry_tax_usd": econ.base_entry_tax_usd,
        "total_landed_cost_usd": route.total_landed_cost_usd,
        "service_fee_usd": fee.total_fee_usd,
    }

    checkout_payload = None
    if stripe_is_configured():
        description = (
            f"Shipment {shipment.origin.get('city', '')} -> "
            f"{shipment.destination.get('city', '')}, {route.selected_mode} mode"
        )
        checkout = create_settlement_checkout(
            user_address=f"web:{session_id}",
            session_id=session_id,
            amount_usd=fee.total_fee_usd,
            description=description,
        )
        if checkout:
            _PENDING[session_id] = {
                "shipment": shipment,
                "econ": econ,
                "route": route,
                "docs": docs,
                "fee": fee,
                "checkout_session_id": checkout["checkout_session_id"],
                "finalized": False,
            }
            checkout_payload = {
                "client_secret": checkout["client_secret"],
                "publishable_key": checkout["publishable_key"],
                "checkout_session_id": checkout["checkout_session_id"],
            }

    return JSONResponse(
        {
            "session_id": session_id,
            "quote": quote,
            "checkout": checkout_payload,
        }
    )


@app.post("/api/finalize")
def finalize(payload: FinalizePayload) -> JSONResponse:
    pending = _PENDING.get(payload.session_id)
    if not pending:
        return JSONResponse({"paid": False, "error": "Unknown session."}, status_code=404)

    if pending["finalized"]:
        return JSONResponse(
            {
                "paid": True,
                "final_message": pending["final_message"],
                "invoice_link": pending["invoice_link"],
            }
        )

    if not verify_checkout_paid(pending["checkout_session_id"]):
        return JSONResponse({"paid": False})

    shipment: ShipmentRequest = pending["shipment"]
    econ: EconData = pending["econ"]
    route: RouteData = pending["route"]
    docs: DocTemplates = pending["docs"]
    fee = pending["fee"]
    transaction_id = pending["checkout_session_id"]

    invoice_path = os.path.join(
        tempfile.g
[truncated — 1207 more characters]
```

### orchestrator/cli.py

```python
"""Local interactive CLI for AeroFreight AI demonstration."""

from __future__ import annotations

import sys

from dotenv import load_dotenv

from orchestrator.conversation import ConversationController
from orchestrator.coordinator import WorkflowCoordinator
from orchestrator.extractor import ClaudeShipmentExtractor, ExtractorConfigurationError
from orchestrator.extractor import ExtractionError
from orchestrator.mock_agents import (
    MockEconomistAgent,
    MockRoutingAgent,
    MockTreasuryAgent,
)
from orchestrator.service import OrchestratorService
from orchestrator.session_store import InMemorySessionStore

LOCAL_SENDER = "local-demo-user"

WELCOME = """
AeroFreight AI — Local Demo
===========================
This CLI runs a local shipment workflow with simulated freight, tax, routing,
documents, and payment values. Claude is used only to extract shipment details.

Commands:
  EXIT          — quit
  NEW SHIPMENT  — reset and start over
  CONFIRM       — execute simulated payment after receiving a quote
"""


def main() -> None:
    load_dotenv()

    try:
        extractor = ClaudeShipmentExtractor()
    except ExtractorConfigurationError:
        print(
            "ANTHROPIC_API_KEY is not configured.\n"
            "Create a local .env file:\n"
            "  cp .env.example .env\n"
            "Then edit .env and set ANTHROPIC_API_KEY to your own key.",
            file=sys.stderr,
        )
        sys.exit(1)

    store = InMemorySessionStore()
    service = OrchestratorService(store)
    conversation = ConversationController(service, extractor)
    coordinator = WorkflowCoordinator(
        conversation=conversation,
        service=service,
        economist=MockEconomistAgent(),
        router=MockRoutingAgent(),
        treasury=MockTreasuryAgent(),
    )

    print(WELCOME.strip())

    while True:
        try:
            user_message = input("\nYou: ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\nGoodbye.")
            break

        if not user_message:
            continue

        if user_message.upper() == "EXIT":
            print("Goodbye.")
            break

        try:
            _, response = coordinator.handle_user_message(LOCAL_SENDER, user_message)
        except ExtractionError as exc:
            print(f"\nOrchestrator: {exc}")
            continue

        print(f"\nOrchestrator: {response}")


if __name__ == "__main__":
    main()

```

### shared_models.py

```python
from typing import List, Literal, Optional

from pydantic import BaseModel, Field


class Item(BaseModel):
    name: str
    quantity: int
    category: str


class ShipmentRequest(BaseModel):
    origin: dict = Field(
        ...,
        description="{'country': 'CN', 'state': 'Guangdong', 'city': 'Shenzhen'}",
    )
    destination: dict = Field(
        ...,
        description="{'country': 'US', 'state': 'TX', 'city': 'Austin'}",
    )
    items: List[Item]
    total_weight_kg: float
    total_volume_cbm: float
    timeframe: Literal["SPEED", "COST"]
    declared_value_usd: float


class EconData(BaseModel):
    transport_preference: Literal["AIR", "SHIP", "EITHER"]
    is_high_value: bool
    is_luxury: bool
    base_entry_tax_usd: float


class RouteData(BaseModel):
    selected_mode: Literal["AIR", "SHIP"]
    optimal_route_nodes: List[str]
    countries_visited: List[str]
    freight_and_toll_cost_usd: float
    total_landed_cost_usd: float


class DocTemplates(BaseModel):
    required_form_names: List[str]
    blank_form_structures: dict


class SettlementStatus(BaseModel):
    filled_documents: dict
    final_user_prompt: str
    payment_hash: Optional[str] = None

```

### schemas.py

```python
from pydantic import BaseModel, Field
from typing import List, Literal, Optional

# --- STEP 1: ORCHESTRATOR OUTPUT ---
class Item(BaseModel):
    name: str
    quantity: int
    category: str

class ShipmentRequest(BaseModel):
    origin: dict = Field(..., description="{'country': 'CN', 'state': 'Guangdong', 'city': 'Shenzhen'}")
    destination: dict = Field(..., description="{'country': 'US', 'state': 'TX', 'city': 'Austin'}")
    items: List[Item]
    total_weight_kg: float
    total_volume_cbm: float
    timeframe: Literal["SPEED", "COST"]
    declared_value_usd: float

# --- STEP 2: ASHWIN'S OUTPUT ---
class EconData(BaseModel):
    transport_preference: Literal["AIR", "SHIP", "EITHER"]
    is_high_value: bool
    is_luxury: bool
    base_entry_tax_usd: float

# --- STEP 3: RIYA'S OUTPUT ---
class RouteData(BaseModel):
    selected_mode: Literal["AIR", "SHIP"]
    optimal_route_nodes: List[str] # e.g. ["SZX", "LAX", "Austin"]
    countries_visited: List[str]
    freight_and_toll_cost_usd: float
    total_landed_cost_usd: float # Includes Ashwin's entry tax

# --- STEP 4: ANIKET'S OUTPUT ---
class DocTemplates(BaseModel):
    required_form_names: List[str]
    blank_form_structures: dict # The empty templates found via browser

# --- STEP 5: NEEL'S OUTPUT ---
class SettlementStatus(BaseModel):
    filled_documents: dict # The completed forms
    final_user_prompt: str # The Markdown string asking for "CONFIRM"
    payment_hash: Optional[str] = None

```

### economic_agent/messages.py

```python
"""uAgents wire models for Economist agent communication."""

from uagents import Model


class EconomistRequest(Model):
    shipment_json: str


class EconomistResponse(Model):
    econ_data_json: str


class EconomistError(Model):
    error_message: str

```

### treasury_agent/__init__.py

```python
"""Neel's Treasury / settlement agent package."""

from treasury_agent.messages import SettlementRequestMessage, SettlementResultMessage
from treasury_agent.pricing import FeeBreakdown, compute_service_fee

__all__ = [
    "FeeBreakdown",
    "SettlementRequestMessage",
    "SettlementResultMessage",
    "compute_service_fee",
]

```

### tests/test_uagents_mailbox.py

```python
"""Tests for mailbox-only uAgents registration."""

from uagents.registration import AlmanacApiRegistrationPolicy

from orchestrator.uagents_mailbox import mailbox_registration_policy


def test_mailbox_registration_policy_is_api_only():
    policy = mailbox_registration_policy()
    assert isinstance(policy, AlmanacApiRegistrationPolicy)

```

### tests/conftest.py

```python
"""Shared pytest fixtures."""

from __future__ import annotations

import pytest


@pytest.fixture(autouse=True)
def isolate_treasury_address_from_private_env(monkeypatch: pytest.MonkeyPatch):
    """Keep mock payment tests independent of live TREASURY_AGENT_ADDRESS in .env."""
    monkeypatch.delenv("TREASURY_AGENT_ADDRESS", raising=False)

```

### orchestrator/uagents_mailbox.py

```python
"""Mailbox-only uAgents registration helpers."""

from __future__ import annotations

from uagents.config import ALMANAC_API_URL
from uagents.registration import AlmanacApiRegistrationPolicy


def mailbox_registration_policy() -> AlmanacApiRegistrationPolicy:
    """Register via Almanac API only; skip on-chain ledger for mailbox agents."""
    return AlmanacApiRegistrationPolicy(almanac_api=ALMANAC_API_URL)

```

[64 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]