Skip to content

[Core SDK] Dead code in llm/llm.py: three shadowed LLM method definitions + an unreachable format-error branch (plus 4 unused imports in agent/agent.py) #5394

Description

@MervinPraison

Summary

The core SDK's largest module, praisonaiagents/llm/llm.py, contains provably dead code: three methods are defined twice inside the same LLM class (so the earlier copy is silently shadowed and unreachable — Python keeps the last definition), plus one helper reachable only from a shadowed copy, plus a duplicate format_error branch that can never execute. Separately, agent/agent.py carries four unused/duplicate top-level imports. This is a dead-code removal only — no feature, behaviour, or public API changes.

Current behaviour

llm/llm.py — shadowed duplicate method definitions (last definition wins)

  • _param_accepts_string — instance-method copy at lines 2042–2060 is shadowed by the @staticmethod copy at lines 2195–2214 (the live one; sole caller is at ~line 1962).
  • _schema_accepts_string — lines 2062–2089 is reachable only from the shadowed _param_accepts_string at 2042 (self._schema_accepts_string(spec) at line 2057). Since its only caller is dead, it is dead too.
  • _force_tool_usage_message — copy at lines 2091–2106 is shadowed by the copy at lines 2157–2168 (callers at ~4031/5787 hit the live one).
  • _tool_repair_message — copy at lines 2108–2132 is shadowed by the copy at lines 2170–2193 (callers at ~4051/5797 hit the live one).

llm/llm.py — unreachable duplicate branch in classify_error_kind

Lines 1005–1011 are a second format_error block whose indicators (validation error, invalid format, parse error, parsing error, decode error, malformed, invalid json, schema error) are all already covered by the first format_error block at lines 976–980, which returns first. The second block can never run.

agent/agent.py — unused / duplicate top-level imports

  • import concurrent.futures (line 10) — no concurrent.* reference anywhere in the file.
  • import random (line 11) — no random reference.
  • import re (line 12) — duplicate of the import re already on line 2.
  • Generator in the typing import (line 13) — never used in agent.py.

Why it matters

  • Maintenance / correctness hazard. ~90 lines of shadowed methods in the largest core file mean an edit to the dead copy silently has no effect, and the two copies can drift. Notably, the shadowed _param_accepts_string/_schema_accepts_string pair handles richer JSON-Schema shapes (oneOf/allOf/enum) than the live @staticmethod; today the richer handling is dead. (This finding is a straight removal that preserves current runtime behaviour exactly; whether the richer handling should be the live one is a separate, deliberate decision and is intentionally out of scope here.)
  • Error-path clutter. The duplicate branch at 1005–1011 adds unreachable comparisons on every error classification.
  • Readability. Dead imports in the hot-path agent.py add noise to the most-read file.

Category

Dead code

Capability preserved

  • All current runtime behaviour of LLM._param_accepts_string, _force_tool_usage_message, _tool_repair_message, and classify_error_kind is byte-for-byte unchanged — only the unreachable copies are removed.
  • Error classification results are identical (the removed branch is a subset of an earlier one that already returns).
  • agent.py behaviour is unchanged (the removed imports have no references; re remains imported once).

Proposed approach

Remove dead code only:

  • Delete the shadowed copies at llm.py 2042–2089 (_param_accepts_string instance copy and the now-orphaned _schema_accepts_string), 2091–2106, and 2108–2132, keeping the live definitions at 2157–2168, 2170–2193, and 2195–2214.
  • Delete the unreachable branch at llm.py 1005–1011.
  • Delete the four dead import lines in agent.py (keep the single import re on line 2).

Resolution sketch

# llm/llm.py classify_error_kind — BEFORE
        if any(indicator in error_str for indicator in [
            "timeout", "timed out", ...]):
            return "idle_timeout"

        # Format errors   <-- unreachable, subset of the block ~30 lines above
        if any(indicator in error_str for indicator in [
            "validation error", "invalid format", "parse error",
            "parsing error", "decode error", "malformed",
            "invalid json", "schema error"]):
            return "format_error"

        return "unknown"

# AFTER (same behaviour)
        if any(indicator in error_str for indicator in [
            "timeout", "timed out", ...]):
            return "idle_timeout"

        return "unknown"
# agent/agent.py — BEFORE (lines 10-13)
import concurrent.futures
import random
import re
from typing import ..., Callable, Generator

# AFTER
from typing import ..., Callable   # 'import re' already present on line 2

Severity

Low (code health; zero behaviour change, zero runtime risk — but a genuine latent-maintenance hazard in the two most-edited core files)

Validation

Keep unchanged

  • The live definitions of all three LLM methods and the first format_error block.
  • classify_error_kind's ordering and every other branch.
  • The single import re and all other imports/behaviour in agent.py.
  • No change to retry, error-handling, tool-repair, or schema-acceptance semantics as they run today.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingclaudeAuto-trigger Claude analysis

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions