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.
Summary
The core SDK's largest module,
praisonaiagents/llm/llm.py, contains provably dead code: three methods are defined twice inside the sameLLMclass (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 duplicateformat_errorbranch that can never execute. Separately,agent/agent.pycarries 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@staticmethodcopy 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_stringat 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 inclassify_error_kindLines 1005–1011 are a second
format_errorblock whose indicators (validation error, invalid format, parse error, parsing error, decode error, malformed, invalid json, schema error) are all already covered by the firstformat_errorblock at lines 976–980, which returns first. The second block can never run.agent/agent.py— unused / duplicate top-level importsimport concurrent.futures(line 10) — noconcurrent.*reference anywhere in the file.import random(line 11) — norandomreference.import re(line 12) — duplicate of theimport realready on line 2.Generatorin thetypingimport (line 13) — never used inagent.py.Why it matters
_param_accepts_string/_schema_accepts_stringpair 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.)agent.pyadd noise to the most-read file.Category
Dead code
Capability preserved
LLM._param_accepts_string,_force_tool_usage_message,_tool_repair_message, andclassify_error_kindis byte-for-byte unchanged — only the unreachable copies are removed.agent.pybehaviour is unchanged (the removed imports have no references;reremains imported once).Proposed approach
Remove dead code only:
llm.py2042–2089 (_param_accepts_stringinstance 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.llm.py1005–1011.agent.py(keep the singleimport reon line 2).Resolution sketch
Severity
Low (code health; zero behaviour change, zero runtime risk — but a genuine latent-maintenance hazard in the two most-edited core files)
Validation
agent.pyimports confirmed unused via file-wide search (each token appears only on its own import line;re.used 6× is satisfied by the line-2 import).LLMmethods andclassify_error_kindremain; removed names are private/internal duplicates._plugin_namehelper in plugins/__init__.py shadows module-level helper #5253 plugins helper, [Core SDK] ~42 sub-package__init__.pyhand-roll__getattr__instead of the DRYcreate_lazy_getattrhelper #5254__getattr__, Core SDK:param_resolverduplicates thecanonical_preset_keynormalisation inline instead of calling the single source of truth #5148 preset key, Core SDK: async turns skip DB run tracking while sync turns race on a shared run id, memory-side Chroma init lacks the already-shipped pyo3-crash guard, and a hardcoded tool name defeats max_iterations #5156 run tracking are unrelated).Keep unchanged
LLMmethods and the firstformat_errorblock.classify_error_kind's ordering and every other branch.import reand all other imports/behaviour inagent.py.