Skip to content

tool_registry_debug_e2e_test.py asserts Orchestrator.tool_registry, an attribute that doesn't exist #13037

Closed

Description

@mrveiss

Context

Discovered while running the baseline test sweep for #13024/#13025/#13026/#13027 (KB-search call-site fixes). Unrelated to those issues -- this file doesn't touch knowledge/, knowledge_base.py, or any KB search path.

autobot-backend/tools/tool_registry_debug_e2e_test.py:25:

orchestrator = Orchestrator()
print(f"Tool registry exists: {hasattr(orchestrator, 'tool_registry')}")
print(f"Tool registry value: {orchestrator.tool_registry}")  # <-- AttributeError

Orchestrator (autobot-backend/orchestrator.py:123) has no tool_registry attribute at all -- only self.agent_registry (orchestrator.py:159). The preceding hasattr() check even prints False immediately before the crash, so the test author already knew the attribute might be missing but the script wasn't updated to handle that case gracefully.

This is a stale debug script (last touched only by a repo-wide file-rename and a license-header commit, per git log --follow), not a real regression -- it currently fails on the Dev_new_gui tip with no relation to my in-flight PR.

Suggested fix

Either:

  • Update the script to reference whatever the orchestrator's actual tool-registry-equivalent attribute is (if one exists elsewhere, e.g. via get_tool_registry() from tools/tool_registry.py), or
  • If Orchestrator was never meant to hold a tool_registry reference, delete this stale debug script (or gate the crashing line behind the hasattr() check it already computes).

Model Used

Claude Sonnet 5

Activity

  1. mrveiss commented on Jul 30, 2026

    @mrveiss
    OwnerAuthor

    Fixed by PR #13039, merged to Dev_new_gui as a2f788889 (batched with #13013, #13021, #13037 — all three fully delivered, none dropped).

    #13013 — wired, not deleted. services/research/models.py:88's truncated_sources was genuinely dead scaffolding (grepped services/research/*.py: zero appenders). The real truncation point already existed at extractor.py:102 (content[:max_content_chars]). It is now recorded by orchestrator._record_truncation_if_needed(), called from _land_page — the one place holding both the budget and the pre-slice markdown. Under the never-delete rule, giving the field a true meaning beat removing it.

    #13021 — enforced during streaming, and the severity is latent rather than live. The cap at media/link/pipeline.py:79 (line moved from 67 since #13019/#13022 landed) was declaration-only; _fetch_and_parse's fallback did an unbounded await response.text(...). New _read_bounded_content() streams in 64 KiB chunks — mirroring web_fetch/fetcher.py._fetch_bs4 — and stops requesting chunks once the cap is crossed, so an oversized body is refused mid-stream rather than after being read into memory. Enforcing post-hoc would have defeated the point entirely. The limit is now ssot_config.link_pipeline_max_content_bytes (AUTOBOT_LINK_PIPELINE_MAX_CONTENT_BYTES, default 1 MB) instead of a literal, and a rejection logs distinguishably from a fetch/connection failure.

    Honest severity: LinkPipeline/process_url() still has zero production callers (referenced only from api/knowledge_scrape_test.py), so this closes a latent gap, not an active resource-exhaustion incident.

    #13037 — larger than filed, and repointed rather than deleted. The assertion at line 25 named Orchestrator.tool_registry, which that class has never had (orchestrator.py:159 — only agent_registry). But the same script also unconditionally referenced available_tools, _execute_planned_action and local_worker, none of which exist either, and git log --follow shows the file untouched but for renames and relicensing since before the #5040 orchestrator consolidation. It was testing an architecture that predates the current one. Rather than delete it, its original intent — prove the tool-dispatch pipeline is wired and can execute a tool — was reconstructed and repointed at the real surface, tools.tool_registry.get_tool_registry() (dispatched from task_handlers/executor.py and api/agent.py), as 3 passing tests.

    Verification: 528 passing across services/research/, media/link/, tools/tool_registry*, api/knowledge_scrape_test.py, autobot_shared/ssot_config_test.py and tests/test_startup_imports.py; the #13021 test asserts chunk consumption stays bounded, proving the stream is cut rather than a flag being set after a full read; cp-swapped baseline (never git stash) left startup-import smoke at 350/350 before and after; py_compile / flake8 --max-line-length=120 / black --check --line-length=120 clean on every changed file.

    Three pre-existing mock-response builders in pipeline_test.py — shared with PR #13022's SSRF-pinning fixtures — needed .content.iter_chunked() added because the read mechanism changed. No assertions were altered and all still pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions