Skip to content

Latest commit

 

History

History
126 lines (92 loc) · 3.76 KB

File metadata and controls

126 lines (92 loc) · 3.76 KB

Agent Instructions — nanobot-hook

NanoBot AgentHook integration that redacts PII before LLM calls and restores original values in responses.

Package Layout

src/nanobot_hook/
├── __init__.py      # Exports PrivacyFilterHook
└── hook.py          # AgentHook implementation

Development Commands

# IMPORTANT: privacy-filter must be installed first (editable or from wheel)
cd ../privacy-filter
uv pip install -e .

# Then work on nanobot-hook
cd ../nanobot-hook
uv sync

# Build wheel
uv build

Key Implementation Details

Dependency Chain

  • pyproject.toml depends on "privacy-filter" (local package, not PyPI yet)
  • Optional extra: nanobot → installs nanobot-ai (the AgentHook framework)
  • Must install privacy-filter (editable: uv pip install -e ../privacy-filter) before nanobot-hook will work

NanoBot AgentHook Interface

From nanobot.agent.hook:

class AgentHook:
    def __init__(self, reraise: bool = False) -> None
    async def before_iteration(self, context: AgentHookContext) -> None
    async def after_iteration(self, context: AgentHookContext) -> None
    def finalize_content(self, context: AgentHookContext, content: str | None) -> str | None

@dataclass
class AgentHookContext:
    iteration: int
    messages: list[dict[str, Any]]  # Mutate in place for redaction
    response: LLMResponse | None
    final_content: str | None
    ...

Hook Lifecycle

class PrivacyFilterHook(AgentHook):
    def __init__(self, min_score=0.8, entity_types=None, cache_dir=None)
    async def before_iteration(self, context: AgentHookContext) -> None  # Redact PII
    def finalize_content(self, context: AgentHookContext, content: str | None) -> str | None  # Unredact
  1. before_iteration() — creates fresh PiiStore, redacts all text content in context.messages
  2. finalize_content() — restores original values from placeholders in the LLM response

Message Format Support

  • String content: {"role": "user", "content": "My email is..."}
  • List content (OpenAI vision format): {"type": "text", "text": "..."} — only redacts type: "text" parts
  • Only processes role: "user" and role: "system" messages

Usage Pattern

from nanobot_hook import PrivacyFilterHook

hook = PrivacyFilterHook(min_score=0.9)
# Register with NanoBot agent's CompositeHook

Package Path Quirk

pyproject.toml uses:

[tool.hatch.build.targets.wheel]
packages = ["src/nanobot_hook"]

This means the package imports as nanobot_hook (root level), not src.nanobot_hook. The src/ directory is a build artifact path, not a namespace package.

Publishing

This is a separate package (nanobot-privacy-filter-hook) that depends on privacy-filter.

Important publishing order:

  1. privacy-filter must be on PyPI first
  2. Wait a few minutes for PyPI index propagation
  3. Then build/publish nanobot-privacy-filter-hook
# 1. Ensure privacy-filter is published to PyPI
cd ../privacy-filter
uv build
uv publish dist/*

# 2. Wait for PyPI, then build/publish nanobot-hook
cd ../nanobot-hook
uv build
uv publish dist/*

Note: nanobot-hook fails to build if privacy-filter is not on PyPI (pyproject.toml declares it as a dependency).

Dependencies

  • privacy-filter — Core PII library (local dependency)
  • nanobot-ai (optional) — NanoBot AgentHook framework

NanoBot AgentHook Validation

Verified against: https://github.com/HKUDS/nanobot/blob/main/nanobot/agent/hook.py

  • AgentHookContext is the proper context type (not Any)
  • context.messages is list[dict[str, Any]] — mutate in place for redaction
  • finalize_content is a pipeline method (not async) — transforms content before sending to user
  • Hooks are registered via CompositeHook([hook1, hook2, ...])