Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/hs-code-classifier/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# pragma: allowlist secret
OPENROUTER_API_KEY=your_openrouter_api_key_here
Comment thread
coderabbitai[bot] marked this conversation as resolved.
100 changes: 100 additions & 0 deletions examples/hs-code-classifier/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# 🛃 HS Code Classifier

A Bindu trade compliance agent that classifies any product into its correct
6-digit Harmonized System (HS) code — the international standard used by
customs authorities in every country to identify goods crossing borders.

Getting the HS code wrong means wrong tariffs, blocked shipments, or fines.
This agent helps SMBs get it right without hiring a trade lawyer.

## Features

- Accepts any product description in plain English
- Returns the correct 6-digit HS code with WCO chapter heading
- Explains the classification rationale with chapter/heading/subheading references
- Provides indicative duty rates for China→EU, India→EU, China→US, India→US
- Flags common misclassification risks and required documentation
- Identifies preferential trade agreements (GSP, FTA) that may reduce duty
- Lists alternative HS codes with conditions for when each applies
- Asks clarifying questions when the product description is ambiguous

## Output Format

```text
HS CODE
6109.10 — T-shirts, singlets and other vests, of cotton

CLASSIFICATION RATIONALE
Why this code applies, with chapter/heading/subheading references.

DUTY RATES
Table of indicative MFN rates for common SMB trade routes.

COMPLIANCE NOTES
Misclassification risks, trade agreements, required documentation.

ALTERNATIVE CODES
Other codes that could apply depending on product specifications.
```

## Setup

```bash
cp .env.example .env
# Add your OPENROUTER_API_KEY to .env

uv add bindu agno python-dotenv pydantic-settings
python hs_code_classifier.py
```

The agent runs at `http://localhost:3773`.

## Example Queries

```text
Classify cotton t-shirts for adults
What HS code for lithium-ion batteries used in laptops?
HS code for green coffee beans from Ethiopia
Classify unroasted arabica coffee, not decaffeinated
What code for stainless steel kitchen knives?
```

## Project Structure

```text
hs-code-classifier/
├── hs_code_classifier.py # Main agent + bindufy()
├── .env.example # Environment variables
├── skills/
│ └── hs-classification-skill/
│ └── skill.yaml # Skill definition
└── README.md
```

## Environment Variables

| Variable | Required | Description |
|---|---|---|
| `OPENROUTER_API_KEY` | Yes | OpenRouter API key |
| `BINDU_DEPLOYMENT_URL` | No | Override default `http://localhost:3773` |

## Disclaimer

Duty rates provided are indicative MFN rates only. Always verify against
the official tariff schedule of the importing country before filing a
customs declaration. For complex classifications, consult a licensed
customs broker or trade compliance specialist.

## Why This Matters

Every product crossing an international border needs an HS code. Get it
wrong and you face:

- **Wrong tariff rates** — overpaying or underpaying duty
- **Blocked shipments** — customs holds your goods pending reclassification
- **Fines** — penalties for incorrect declarations
- **Delays** — Rotterdam container dwell averaged 9.1 days in 2025 vs a
normal 3, largely due to compliance failures

This agent is part of Bindu's trade compliance toolchain — a swarm of
agents helping SMBs navigate global trade without eye-watering legal bills.
234 changes: 234 additions & 0 deletions examples/hs-code-classifier/hs_code_classifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
"""
HS Code Classifier — Bindu Example

A trade compliance agent that classifies products into their correct
Harmonized System (HS) codes — the 6-digit international standard used
by customs authorities in every country to identify goods crossing borders.

Getting the HS code wrong means wrong tariffs, blocked shipments, or fines.
This agent helps SMBs get it right without hiring a trade lawyer.

Features
--------
- HS code classification backed by DuckDuckGo live web search
- Duty rates sourced from live search (not LLM memory)
- Compliance notes with misclassification risks
- Alternative codes with conditions

Prerequisites
-------------
uv add bindu agno duckduckgo-search python-dotenv pydantic-settings

Usage
-----
export OPENROUTER_API_KEY="your_api_key_here" # pragma: allowlist secret
python hs_code_classifier.py

The agent will be live at http://localhost:3773
Example queries:
"Classify cotton t-shirts for adults"
"What HS code for lithium-ion batteries used in laptops?"
"HS code for green coffee beans from Ethiopia"
"""

from agno.agent import Agent
from agno.models.openrouter import OpenRouter
from agno.tools.duckduckgo import DuckDuckGoTools
from bindu.penguin.bindufy import bindufy
from bindu.utils.logging import get_logger
from dotenv import load_dotenv
from pydantic import Field
from pydantic_settings import BaseSettings

load_dotenv()

logger = get_logger(__name__)


# ---------------------------------------------------------------------------
# 1. Settings validation
# ---------------------------------------------------------------------------

class AppSettings(BaseSettings):
"""Application settings with validation."""

openrouter_api_key: str = Field(default="", alias="OPENROUTER_API_KEY")
bindu_deployment_url: str = Field(
default="http://localhost:3773", alias="BINDU_DEPLOYMENT_URL"
)

class Config:
env_file = ".env"

Comment thread
coderabbitai[bot] marked this conversation as resolved.
def validate(self) -> None:
"""Validate required settings at startup."""
if not self.openrouter_api_key:
raise ValueError(
"OPENROUTER_API_KEY is not set. "
"Please set it in .env or as an environment variable."
)


app_settings = AppSettings()


def validate_settings() -> None:
"""Startup-time validation of required settings."""
try:
app_settings.validate()
except ValueError as e:
logger.error("Configuration error: %s", e)
raise


# ---------------------------------------------------------------------------
# 2. Agent definition
# ---------------------------------------------------------------------------

INSTRUCTIONS = """
You are an expert customs classification specialist with deep knowledge of the
Harmonized System (HS) — the international standard for classifying traded goods,
maintained by the World Customs Organization (WCO).

You have access to DuckDuckGo web search. You MUST use it to look up:
1. The correct HS code for the product (search WCO or official tariff databases)
2. Current duty rates for the trade routes requested (search official sources)
3. Any applicable trade agreements or compliance requirements

Never rely on memory alone for duty rates or tariff information — always search
and cite the source. If search results are unavailable, state this explicitly
and direct the user to official sources rather than providing unverified figures.

When asked to classify a product, respond in this exact structure:

HS CODE
Provide the 6-digit HS code (format: XXXX.XX) and the official WCO chapter heading.
Cite the source used to verify this code.

CLASSIFICATION RATIONALE
2-3 sentences explaining exactly why this code applies, referencing the relevant
HS chapter, heading, and subheading rules.

DUTY RATES
A table of indicative import duty rates for the most relevant trade routes:
- China → EU
- India → EU
- China → US
- India → US
Cite the source for each rate. Always include this disclaimer:

⚠️ These rates are indicative only, sourced from web search.
Verify before filing against official schedules:
- EU TARIC: https://ec.europa.eu/taxation_customs/dds2/taric/
- US HTS: https://hts.usitc.gov/

COMPLIANCE NOTES
2-3 bullet points covering:
- Common misclassification risks for this product type
- Any preferential trade agreements that may reduce duty (GSP, FTA)
- Required certifications or documentation for this HS code

ALTERNATIVE CODES
If there are common alternative codes that could apply depending on product
specifications, list them with a one-line explanation of when each applies.

Rules:
- Always use 6-digit HS codes (the international standard)
- If the product description is ambiguous, ask ONE clarifying question
- Never invent HS codes or duty rates — search first, then cite sources
- Output in plain Markdown
Comment thread
coderabbitai[bot] marked this conversation as resolved.
""".strip()

agent = Agent(
instructions=INSTRUCTIONS,
model=OpenRouter(
id="openai/gpt-4o-mini",
api_key=app_settings.openrouter_api_key, # pragma: allowlist secret
),
tools=[DuckDuckGoTools()],
markdown=True,
)


# ---------------------------------------------------------------------------
# 3. Bindu configuration
# ---------------------------------------------------------------------------

config = {
"author": "your.email@example.com",
"name": "hs_code_classifier",
"description": (
"A trade compliance agent that classifies products into their correct "
"Harmonized System (HS) codes using live web search, provides sourced "
"duty rates for common trade routes, and flags compliance risks — "
"helping SMBs avoid costly customs errors."
),
"version": "1.0.0",
"capabilities": {
"classification": ["hs-code", "customs-classification", "trade-compliance"],
"research": ["duty-rates", "trade-agreements", "compliance-notes"],
"search": ["live-tariff-lookup", "duckduckgo"],
"streaming": False,
},
"skills": ["skills/hs-classification-skill"],
"auth": {"enabled": False},
"storage": {"type": "memory"},
"scheduler": {"type": "memory"},
"deployment": {
"url": app_settings.bindu_deployment_url,
"expose": True,
"cors_origins": ["http://localhost:5173"],
},
}


# ---------------------------------------------------------------------------
# 4. Handler
# ---------------------------------------------------------------------------

def handler(messages: list[dict[str, str]]):
"""Classify a product into its correct HS code using live web search.

Args:
messages: Standard A2A message list, e.g.
[{"role": "user", "content": "Classify cotton t-shirts for adults"}]

Returns:
HS code, classification rationale, duty rates (sourced from web search),
compliance notes, and alternative codes.
"""
try:
user_messages = [m for m in messages if m.get("role") == "user"]
if not user_messages:
return (
"No product description received. "
"Please describe the product you want to classify, e.g. "
"'Classify cotton t-shirts for adults'."
)

query = user_messages[-1].get("content", "").strip()
if not query:
return (
"Empty query. Please describe a product to classify, e.g. "
"'What HS code for lithium-ion batteries used in laptops?'"
)

result = agent.run(input=messages)
return result

except Exception as e:
logger.error("Classification error: %s", e, exc_info=True)
return "Classification failed. Please try again or contact support."


# ---------------------------------------------------------------------------
# 5. Entry point
# ---------------------------------------------------------------------------

if __name__ == "__main__":
validate_settings()
logger.info(
"🛃 HS Code Classifier running at %s", app_settings.bindu_deployment_url
)
logger.info("📦 Example: Classify cotton t-shirts for adults")
bindufy(config, handler)
Loading
Loading