Skip to content

feat(display): declarative tool-preview schema to eliminate per-tool hardcoding (#28621)#28719

Open
xxxigm wants to merge 3 commits into
NousResearch:mainfrom
xxxigm:feat/28621-tool-preview-schema
Open

feat(display): declarative tool-preview schema to eliminate per-tool hardcoding (#28621)#28719
xxxigm wants to merge 3 commits into
NousResearch:mainfrom
xxxigm:feat/28621-tool-preview-schema

Conversation

@xxxigm

@xxxigm xxxigm commented May 19, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a declarative tool-preview schema registry to agent/display.py so new tools — including plugin/third-party tools — can ship a one-line progress preview alongside their schema definition, instead of editing the hardcoded if-elif chain in build_tool_preview() every time.

Before, tools without a manual entry fell back to ⚙️ tool_name... on Feishu / Telegram bubbles and the CLI spinner. This is what prompted #28598 (fact_store / fact_feedback showing no useful context); #28621 generalises that observation: the if-elif chain is a structural oversight generator, and plugins have no path to preview support at all.

The new API is:

from agent.display import register_tool_preview

register_tool_preview(
    "fact_store",
    field="action",
    templates={
        "add":    '+ "{content:.30}"',
        "search": 'search: "{query:.25}"',
        "remove": "remove: #{fact_id}",
        "*":      "{action}",          # wildcard fallback
    },
    truncate=60,                        # per-tool cap
)

Design choices:

  • Backward compatible — registry is consulted before the legacy chain. Existing tools keep working; migration is incremental, no flag-day.
  • Plugin-friendly — plugins call register_tool_preview() at import time, next to their schema definition. No core code edit required.
  • Safe by default — missing keys render as "" (a partial tool call never crashes the spinner), string values are whitespace-collapsed, lists are joined with , , bad templates degrade to None + a warning log instead of raising.
  • Per-tool overridetruncate=N takes priority over the global _tool_preview_max_len, useful for plugins that know their content is naturally short.
  • Last-write-wins — plugins can override built-in previews if they need to.

Related Issue

Fixes #28621
Also closes #28598 (the user-visible bug that prompted this proposal — fact_store and fact_feedback now render meaningful previews).

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)

Changes Made

  • agent/display.py — adds register_tool_preview(), _unregister_tool_preview(), the _TOOL_PREVIEW_REGISTRY module-level dict, _SafePreviewArgs (a dict subclass that returns "" for missing keys and normalises values for str.format_map), and _render_registered_preview(). build_tool_preview() consults the registry first, applies the per-tool truncate (falling back to the global _tool_preview_max_len), and only then falls through to the existing hardcoded chain. Also hardens the legacy path against truthy non-dict args.
  • plugins/memory/holographic/__init__.py — registers preview templates for fact_store (10 actions, including add, search, probe, reason, update, remove, plus a * fallback) and fact_feedback (helpful / unhelpful / *). The registration sits right next to FACT_STORE_SCHEMA / FACT_FEEDBACK_SCHEMA so reviewers see UX + schema together.
  • tests/agent/test_display.py — adds TestRegisterToolPreview (15 unit tests covering single-template rendering, field dispatch with * fallback, missing-key safety, list-arg joining, per-field precision truncation, per-tool vs. global truncate precedence, whitespace collapsing, None"", bad-template fallback with log assertion, last-write-wins re-registration, registry-over-legacy priority, and rejection of malformed registrations) plus TestFactStorePluginPreview (7 smoke tests for the holographic plugin registrations) and one extra defensive test for truthy non-dict args.
  • website/docs/developer-guide/adding-tools.md — adds an "Optional: Tool Progress Previews" section showing the API and dispatch form, plus a checklist nudge so authors register a preview when relevant.

Memory and the other complex special cases (process, todo, send_message) are intentionally left on the legacy path in this PR — the issue's scope calls for 2–3 POC migrations with the rest deferred. memory in particular has a "<missing old_text>" sentinel that doesn't fit the minimal field/templates/truncate schema cleanly; if that's wanted, it should land in a follow-up PR (possibly extending the schema with an optional defaults mapping).

How to Test

# Full registry coverage + smoke tests for the plugin migration.
scripts/run_tests.sh tests/agent/test_display.py -q
# Expected: 55 passed (31 existing + 24 new).

# Manual: with the holographic-memory plugin enabled, watch a tool
# progress bubble while issuing a fact_store call from chat.
# Before this PR:  ⚙️ fact_store...
# After this PR:   ⚙️ fact_store + "user prefers tabs"

Checklist

Code

  • My commit messages follow Conventional Commits (feat(display):, feat(memory/holographic):, test(display)+docs:)
  • I searched for existing PRs — no duplicate
  • My PR contains only changes related to this feature
  • I've run scripts/run_tests.sh tests/agent/test_display.py -q (55 passed, 0 failed)
  • I've added tests for my changes (22 new tests covering the registry contract + plugin smoke tests)
  • I've tested on my platform: macOS 15.x (darwin 24.6.0)

Documentation & Housekeeping

  • I've updated relevant documentation (website/docs/developer-guide/adding-tools.md)
  • N/A — no config keys changed (cli-config.yaml.example)
  • N/A — no architecture / workflow change requiring CONTRIBUTING.md / AGENTS.md updates
  • I've considered cross-platform impact — pure Python, no platform-specific code paths
  • N/A — no tool description/schema changes (preview registration is additive metadata)

xxxigm added 3 commits May 19, 2026 19:12
…#28621)

Replace the open-coded ``if tool_name == "memory" / "session_search" / ...``
chain in ``build_tool_preview`` with a small declarative registry so new
tools — including plugins — can ship a one-line progress preview alongside
their schema instead of waiting for a core code edit.

``register_tool_preview()`` accepts either a single template or a
``field``-dispatched mapping with ``"*"`` fallback; templates use
``str.format_map`` semantics with missing-key safety, list-arg joining,
whitespace collapsing on string fields, and per-field precision
truncation (``{content:.30}``).  A per-tool ``truncate=N`` cap layers
on top of the global ``_tool_preview_max_len``.  Registry entries take
priority over the legacy hardcoded chain so migration is incremental
with no flag-day.  Bad templates degrade to ``None`` and a warning log
instead of crashing the spinner.
…ore + fact_feedback (NousResearch#28621, NousResearch#28598)

Co-locates declarative preview templates with the holographic-memory
plugin's tool schemas so Feishu / Telegram / CLI bubbles render
``+ "user prefers tabs"`` or ``search: "editor config"`` instead of
the previous useless ``⚙️ fact_store...`` fallback.

This is the proof-of-concept migration called out in NousResearch#28621's scope
(plugins ship preview support without touching core display code) and
directly closes the user-visible gap reported in NousResearch#28598.
…_tool_preview (NousResearch#28621)

Adds 22 new unit tests pinning the registry contract — single-template
rendering, field dispatch with ``"*"`` fallback, missing-key safety,
list-arg joining, per-field precision truncation, per-tool ``truncate``
cap precedence over the global limit, graceful degradation on bad
templates, last-write-wins re-registration, and registry-over-legacy
priority — plus a smoke test for the ``fact_store`` / ``fact_feedback``
plugin registrations.

Adds a "Tool Progress Previews" section to the Adding Tools developer
guide so authors discover the API alongside schema authoring and the
checklist nudges them to register one when relevant.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent loop, run_agent.py, prompt builder comp/plugins Plugin system and bundled plugins labels May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

2 participants