Skip to content
Back to skills

1603 2026 02 05 Issue 358 Tool Dispatcher Complexity A6397fbe

ASecurity

**Status: COMPLETED via PR #366** The tool_dispatcher decomposition was completed on 2026-02-05. See PR #366 for implementation details.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
testingpythongonoderailsgitapi

Works with

  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 1603-2026-02-05_issue-358_tool-dispatcher-complexity_a6397fbe --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1603 2026 02 05 Issue 358 Tool Dispatcher Complexity A6397fbe?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1603 2026 02 05 Issue 358 Tool Dispatcher Complexity A6397fbe
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1603-2026-02-05-issue-358-tool-dispatcher-complexi/badge)](https://www.skillsdirectory.com/skills/tools-only-1603-2026-02-05-issue-358-tool-dispatcher-complexi)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
title: "Issue #358 – Tool Dispatcher Complexity Reduction Plan"
phase: Completed
date: "2026-02-05T00:00:00Z"
completed_date: "2026-02-05"
completion_pr: "#366"
owner: "tuna"
parent_research: "memory-bank/research/2026-02-05_tool_dispatcher_complexity_358.md"
git_commit_at_plan: "9ed9739d"
git_commit_at_complete: "d5b3cc7c"
tags: [plan, refactor, complexity, tool-dispatcher, orchestrator, issue-358, completed]
---

**Status: COMPLETED via PR #366**

The tool_dispatcher decomposition was completed on 2026-02-05. See PR #366 for implementation details.

## Objective

Reduce cognitive load and maintenance risk in:
`src/tunacode/core/agents/agent_components/orchestrator/tool_dispatcher.py`

Primary drivers from research (#358):
- Unused parameters in `_collect_structured_tool_calls`
- Magic numbers for debug preview truncation and ms conversion
- Overloaded module responsibilities (collection + registry + execution + logging)

## Non-goals

- No user-visible behavior changes
- No new tool call formats / parsing rules
- No state-machine ownership changes (orchestrator still drives transitions)
- No new dependencies

## Success Criteria (Definition of Done)

1. **Dead parameters removed** and call sites updated.
2. **Magic numbers removed** (replaced with named constants).
3. **Assertions replaced** where they act as runtime type checks (asserts can be stripped with `-O`).
4. **All existing tests pass**:
   - `uv run pytest tests/integration/tools/test_tool_dispatcher_coverage.py`
   - `uv run pytest tests/integration/core/test_tool_call_lifecycle.py`
5. **Ruff clean**: `uv run ruff check --fix .`
6. **No new type-checking regressions introduced** (keep mypy error count from increasing).

## Constraints / Project Rules

- Small, focused diffs; commit frequently.
- Fail fast, fail loud (no silent fallbacks).
- Keep identical things identical (normalize naming + constants consistently).
- Do not introduce new mypy errors.

## Work Plan (Phased)

### Phase 0 — Baseline + Guardrails (no behavior changes)
**Goal:** lock in baseline behavior + metrics so we can refactor safely.

Tasks:
- [ ] Confirm current tests are green for the two integration files.
- [ ] Capture before/after metrics in PR description (file lines, function count, magic literals count).

Acceptance:
- Tests pass before changes.

---

### Phase 1 — Extract Constants (low risk)
**Goal:** remove magic literals and document intent.

Changes:
- [ ] Add module constants:
  - `DEBUG_PREVIEW_MAX_LENGTH = 100`
  - `MS_PER_SECOND = 1000`
- [ ] Replace occurrences:
  - `tool_name[:100]`, `str(... )[:100]`, `text_content[:100]`
  - `* 1000` in elapsed-ms calculation

Acceptance:
- Tests pass.
- Diff is strictly mechanical (no logic changes).

---

### Phase 2 — Remove Dead Parameters (low risk)
**Goal:** reduce misleading API surface.

Changes:
- [ ] Update `_collect_structured_tool_calls` signature to remove unused parameters:
  - remove `node`
  - remove `tool_callback`
- [ ] Update internal call site in `dispatch_tools`.

Acceptance:
- Tests pass.
- No other callers exist (verify via ripgrep).

---

### Phase 3 — Replace Runtime-Type `assert` with Explicit Errors (behavior-preserving)
**Goal:** assertions currently enforce runtime contracts; they should fail loudly even under `python -O`.

Changes (in `_collect_fallback_tool_calls`):
- [ ] Replace:
  - `assert isinstance(result, tuple)`
  - `assert isinstance(result, list)`
  with explicit checks and a raised exception type that won’t be optimized away.

Proposed error type:
- Prefer `StateError` with a clear message, unless a more precise local exception exists.

Acceptance:
- Tests pass.
- Failure mode remains loud and actionable.

---

### Phase 4 — Module Responsibility Split (medium risk, still behavior-preserving)
**Goal:** make `tool_dispatcher.py` read like an orchestrator, not a grab bag.

Proposed structure (private modules; names are suggestions):
- `tool_dispatch_collection.py`
  - `_collect_structured_tool_calls`
  - `_collect_fallback_tool_calls`
- `tool_dispatch_registry_ops.py`
  - `_register_tool_call`, `_mark_tool_calls_running`, `_record_tool_failure`
- `tool_dispatch_logging.py`
  - `_log_dispatch_summary`

Constraints:
- Keep the public API stable: `dispatch_tools`, `has_tool_calls`, `consume_tool_call_args`, `record_tool_call_args`, `normalize_tool_args`.
- Avoid introducing circular imports (keep deferred imports if needed).

Acceptance:
- Tests pass.
- `tool_dispatcher.py` is meaningfully smaller and reads as a 4-phase dispatcher.

---

### Phase 5 — Optional: Introduce a `ToolDispatcher` Object (high risk / optional)
**Goal:** reduce parameter threading (`node`, `state_manager`, callbacks) by bundling into an explicit object.

Only do this if Phase 4 still leaves the module hard to navigate.

Acceptance:
- No public API change (module-level `dispatch_tools(...)` can instantiate and delegate).
- Tests pass.

## Risks & Mitigations

| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| Circular imports when splitting modules | High | Medium | Keep deferred imports; move only leaf functions first; run import-time smoke test |
| Silent behavior change in fallback parser | High | Low | Keep logic identical; only replace asserts with explicit raises; rely on existing integration tests |
| Refactor causes new type errors | Medium | Medium | Prefer explicit types; keep changes small; run targeted tests frequently |

## Execution Checklist (per phase)

- [ ] `uv run ruff check --fix .`
- [ ] `uv run pytest tests/integration/tools/test_tool_dispatcher_coverage.py -q`
- [ ] `uv run pytest tests/integration/core/test_tool_call_lifecycle.py -q`

## References

- Research: `memory-bank/research/2026-02-05_tool_dispatcher_complexity_358.md`
- Target module: `src/tunacode/core/agents/agent_components/orchestrator/tool_dispatcher.py`
- Orchestrator: `src/tunacode/core/agents/agent_components/orchestrator/orchestrator.py`
- Tests:
  - `tests/integration/tools/test_tool_dispatcher_coverage.py`
  - `tests/integration/core/test_tool_call_lifecycle.py`

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.