feat(examples): add HS Code Classifier trade compliance agent#569
feat(examples): add HS Code Classifier trade compliance agent#569Subhajitdas99 wants to merge 5 commits into
Conversation
Agno + OpenRouter agent that classifies products into 6-digit HS codes, provides duty rates for China/India → EU/US trade routes, flags compliance risks, and lists alternative codes. Part of Bindu's trade compliance toolchain. Verified locally end-to-end with cotton t-shirts classification query.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds an HS code classifier example: README and env template, a Bindu HTTP handler that validates input and calls an OpenRouter-backed Agent using a strict Markdown prompt, startup wiring, and a declarative HS classification skill YAML. ChangesHS Code Classifier Example
Sequence DiagramsequenceDiagram
participant Client
participant BinduHTTP as Bindu HTTP
participant Handler as hs_code_classifier.handler
participant Agent as Agent(OpenRouter)
Client->>BinduHTTP: POST user messages
BinduHTTP->>Handler: invoke handler(messages)
Handler->>Agent: agent.run(input=messages)
Agent->>Handler: classification Markdown result
Handler->>BinduHTTP: return HTTP response
BinduHTTP->>Client: HTTP response with result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hey @raahulrahl 👋 Just opened PR #569 — HS Code Classifier, the first trade compliance agent for Bindu. It classifies any product into its 6-digit HS code, provides duty rates for China/India → EU/US, flags compliance risks, and lists alternative codes. Directly aligned with the trade compliance roadmap you shared. • Verified end-to-end (correctly classified cotton t-shirts as 6109.10 with 12% EU duty) Happy to keep building out the compliance toolchain — CBAM calculator or EUDR checker next if useful. |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
examples/hs-code-classifier/hs_code_classifier.py (1)
163-165: ⚡ Quick winUse the repo logger for startup messages.
These
print()calls should beget_logger(__name__)calls to stay consistent with the repo’s Python logging convention.As per coding guidelines, "Use
get_logger(__name__)frombindu/utils/logging.pyfor logging, notprint()".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/hs-code-classifier/hs_code_classifier.py` around lines 163 - 165, Replace the two print() startup messages in the module-level __main__ block with the repository logger: import get_logger from bindu.utils.logging (if missing), create logger = get_logger(__name__), and call logger.info(...) for the existing messages (e.g. logger.info("🛃 HS Code Classifier running at http://localhost:3773") and logger.info("📦 Example: Classify cotton t-shirts for adults")) so logging follows the repo convention instead of using print().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/hs-code-classifier/.env.example`:
- Line 1: Add the secret-scan allowlist pragma comment to the .env.example
template so pre-commit secret scanners won't flag the example API key; insert
the line "# pragma: allowlist secret" at the top of the .env.example file (above
the OPENROUTER_API_KEY=your_openrouter_api_key_here entry) and keep the example
placeholder value unchanged.
In `@examples/hs-code-classifier/hs_code_classifier.py`:
- Around line 54-78: The prompt in hs_code_classifier.py currently asks for DUTY
RATES, COMPLIANCE NOTES, and ALTERNATIVE CODES without any authoritative data
source; either remove/disable those sections and restrict output to HS
classification only (keep the RULES and ask one clarifying question if
ambiguous), or implement and document a dated external data lookup (e.g., call
to a tariff API or citation variable) and include the source/date alongside any
duty/trade-agreement statements; update the prompt text blocks named "DUTY
RATES", "COMPLIANCE NOTES", and "ALTERNATIVE CODES" accordingly so the code
producing the prompt (the prompt constant or function that generates it) no
longer asserts tariff/regulatory facts without a referenced source.
- Around line 83-85: The code reads OPENROUTER_API_KEY and BINDU_DEPLOYMENT_URL
directly from os.environ when constructing the OpenRouter model (see the
model=OpenRouter call), which violates the config guideline; replace those
os.getenv calls with values from app_settings (use
app_settings.OPENROUTER_API_KEY and app_settings.BINDU_DEPLOYMENT_URL) and add a
startup-time validation step (e.g., in module init or a dedicated
validate_settings function invoked at import/startup) that raises a clear error
if the key/URL are missing or empty so the service fails fast instead of at
first request; apply the same replacement/validation for the other occurrences
noted around lines 113-115.
- Around line 155-156: In hs_code_classifier.py replace the current except
Exception as e block that returns f"Classification error: {str(e)}" with logic
that logs the full exception using get_logger(__name__) from
bindu/utils/logging.py (capture and log the exception/traceback) and instead
returns a generic, non-sensitive message like "Classification failed" to
callers; locate the except block (the one catching Exception as e) to implement
the change and ensure you do not expose str(e) in the returned value.
---
Nitpick comments:
In `@examples/hs-code-classifier/hs_code_classifier.py`:
- Around line 163-165: Replace the two print() startup messages in the
module-level __main__ block with the repository logger: import get_logger from
bindu.utils.logging (if missing), create logger = get_logger(__name__), and call
logger.info(...) for the existing messages (e.g. logger.info("🛃 HS Code
Classifier running at http://localhost:3773") and logger.info("📦 Example:
Classify cotton t-shirts for adults")) so logging follows the repo convention
instead of using print().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c503576e-0205-419a-8fe0-b1c10def180d
📒 Files selected for processing (4)
examples/hs-code-classifier/.env.exampleexamples/hs-code-classifier/README.mdexamples/hs-code-classifier/hs_code_classifier.pyexamples/hs-code-classifier/skills/hs-classification-skill/skill.yaml
- Add AppSettings validation for required environment variables - Use pydantic_settings for config management instead of os.getenv() - Replace print() with get_logger() for consistent logging - Log full exception with traceback, return generic error message - Add secret-scan allowlist pragma to .env.example - Update README with pydantic-settings dependency
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/hs-code-classifier/hs_code_classifier.py`:
- Around line 45-55: AppSettings currently calls os.getenv inside field defaults
which prevents pydantic's BaseSettings from loading env vars; remove the
os.getenv calls and declare the fields so BaseSettings can populate them (e.g.,
make openrouter_api_key a plain str field and set bindu_deployment_url with the
literal default "http://localhost:3773" or use pydantic Field(...,
env="BINDU_DEPLOYMENT_URL")/Field(..., env="OPENROUTER_API_KEY") if you want
explicit env names), leaving the inner Config with env_file intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9bb41029-1b42-485b-a1e9-fac8889e8a65
📒 Files selected for processing (3)
examples/hs-code-classifier/.env.exampleexamples/hs-code-classifier/README.mdexamples/hs-code-classifier/hs_code_classifier.py
✅ Files skipped from review due to trivial changes (2)
- examples/hs-code-classifier/.env.example
- examples/hs-code-classifier/README.md
Paraschamoli
left a comment
There was a problem hiding this comment.
hey @Subhajitdas99 i think we already have good number for example agent
Addresses CodeRabbit major issue: agent now searches authoritative sources before emitting tariff figures. Duty rate tables include source citations and official TARIC/HTS verification links.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
examples/hs-code-classifier/hs_code_classifier.py (1)
216-217:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winFix Agno
Agent.run(...)usage in hs_code_classifier handler (return type + call signature)
- In agno 2.5.2,
Agent.run()returns aRunOutputobject (not a plain string). Returning it directly from the Bindu handler may not produce a usable text response—returnresult.content(or the appropriate text field) instead.Agent.run()does not natively acceptinput=as a way to pass a list of chat-message dicts.agent.run(input=messages)is likely incorrect—update the call to use the supported prompt/history mechanism, and only pass messages if that kwarg is valid.- Double-check that providing the full
messageslist doesn’t duplicate Bindu’s own prepended system prompt when usinginstructions=INSTRUCTIONS.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/hs-code-classifier/hs_code_classifier.py` around lines 216 - 217, Agent.run currently is being called incorrectly and its return is a RunOutput object; replace the call to avoid using the unsupported input= keyword and return the textual field from the RunOutput. Specifically, call agent.run with the messages list as a positional prompt/history argument (e.g., agent.run(messages) rather than agent.run(input=messages)), then return result.content (or the appropriate text attribute from RunOutput) instead of the whole result object; also ensure the messages you pass do not include a duplicated system prompt when instructions=INSTRUCTIONS is used (omit the prepended system message or only pass user/assistant turns).
🧹 Nitpick comments (1)
examples/hs-code-classifier/hs_code_classifier.py (1)
60-61: 💤 Low valueOptional: prefer
model_config = SettingsConfigDict(...)over the legacyclass ConfiginAppSettings
pydantic-settingsv2 deprecates the innerclass Configin favor ofmodel_config, e.g. forenv_file.♻️ Suggested change
-from pydantic_settings import BaseSettings +from pydantic_settings import BaseSettings, SettingsConfigDict @@ - class Config: - env_file = ".env" + model_config = SettingsConfigDict(env_file=".env")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/hs-code-classifier/hs_code_classifier.py` around lines 60 - 61, Replace the legacy inner class Config used for env file configuration in AppSettings with the pydantic v2 pattern: define a module-level or class attribute model_config on AppSettings using SettingsConfigDict to set env_file (e.g. model_config = SettingsConfigDict({"env_file": ".env"})); update the AppSettings class to remove the inner class Config and import SettingsConfigDict from pydantic_settings to apply the same env_file behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/hs-code-classifier/hs_code_classifier.py`:
- Line 234: Add a trailing newline at end-of-file to satisfy the
end-of-file-fixer pre-commit hook: open the file containing the bindufy(config,
handler) call and ensure there is a single newline character after the final
line (after the bindufy(config, handler) statement), then save and re-run the
pre-commit checks or commit the change.
---
Outside diff comments:
In `@examples/hs-code-classifier/hs_code_classifier.py`:
- Around line 216-217: Agent.run currently is being called incorrectly and its
return is a RunOutput object; replace the call to avoid using the unsupported
input= keyword and return the textual field from the RunOutput. Specifically,
call agent.run with the messages list as a positional prompt/history argument
(e.g., agent.run(messages) rather than agent.run(input=messages)), then return
result.content (or the appropriate text attribute from RunOutput) instead of the
whole result object; also ensure the messages you pass do not include a
duplicated system prompt when instructions=INSTRUCTIONS is used (omit the
prepended system message or only pass user/assistant turns).
---
Nitpick comments:
In `@examples/hs-code-classifier/hs_code_classifier.py`:
- Around line 60-61: Replace the legacy inner class Config used for env file
configuration in AppSettings with the pydantic v2 pattern: define a module-level
or class attribute model_config on AppSettings using SettingsConfigDict to set
env_file (e.g. model_config = SettingsConfigDict({"env_file": ".env"})); update
the AppSettings class to remove the inner class Config and import
SettingsConfigDict from pydantic_settings to apply the same env_file behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 477af21f-515b-4fd2-a509-0050bd22f3e1
📒 Files selected for processing (1)
examples/hs-code-classifier/hs_code_classifier.py
|
Hey @Paraschamoli — understood, happy to defer to the team's judgment on example count. One thing worth noting: this one is directly aligned with Raahul's trade compliance roadmap — HS code classification is the first step in every international shipment, and it demonstrates Bindu's A2A + DID capabilities in a real commercial use case rather than a general-purpose demo. Also just pushed a fix addressing CodeRabbit's major concern — added DuckDuckGoTools so duty rates are sourced from live web search rather than LLM memory, with TARIC/HTS source citations in every response. Happy to close if the team prefers to keep examples focused elsewhere — just wanted to flag the trade compliance angle. Up to you and @raahulrahl |
Summary
examples/hs-code-classifier/— an Agno + OpenRouter agent that classifies any product into its 6-digit HS code, provides indicative duty rates for China/India → EU/US trade routes, flags compliance risks, and lists alternative codes.Change Type
Scope
Linked Issue/PR
Related: Bindu trade compliance roadmap (Discord, 29 May 2026)
User-Visible / Behavior Changes
New example agent at
examples/hs-code-classifier/. RequiresOPENROUTER_API_KEY. No changes to existing behaviour.Security Impact
# pragma: allowlist secretadded to suppress false-positive detection.Verification
Environment
Steps to Test
cd examples/hs-code-classifiercp .env.example .envand setOPENROUTER_API_KEYpython hs_code_classifier.pyClassify cotton t-shirts for adultsplainto the clarifying questionExpected Behavior
Actual Behavior
Matches expected. Correctly returned
6109.10with 12% EU duty, compliance notes, and alternative codes. DID signature present on every response.Evidence
Human Verification
Compatibility / Migration
Failure Recovery
examples/hs-code-classifier/to revert — self-contained, no framework changesRisks and Mitigations
Checklist
Summary by CodeRabbit
New Features
Documentation
Configuration