Summary
praisonaiagents/config/feature_configs.py carries a second, parallel implementation of the parameter-precedence resolvers that the SDK already provides in praisonaiagents/config/param_resolver.py (which self-documents as "the SINGLE, DRY resolver"). The feature_configs versions have no production callers — every public config.resolve_* name routes to param_resolver — and are kept alive only by one precedence-ladder test. This is duplicate resolver logic that can be consolidated without dropping any option or behaviour.
Current behaviour
Dead duplicate resolvers in config/feature_configs.py (none referenced by production code):
resolve_memory (1274), resolve_knowledge (1346), resolve_planning (1400), resolve_reflection (1413), resolve_guardrails (1426), resolve_web (1441), resolve_caching (1455), resolve_autonomy (1468)
resolve_tool_search (1481) — zero references anywhere in the codebase (not even tests).
Routing evidence:
config/__init__.py maps every resolve_* name to "param_resolver" (lines 136–148). None map to feature_configs.
- Top-level
praisonaiagents/__init__.py maps resolve_memory/knowledge/web/planning/reflection/autonomy/caching/guardrails to praisonaiagents.config.param_resolver (lines 424–437).
agent/agent.py:1430 imports resolve_guardrails from param_resolver (not feature_configs).
- The only importers of the
feature_configs resolver functions are tests (e.g. tests/unit/config/test_precedence_ladder.py). No production path imports them.
Not dead — keep: resolve_tools (feature_configs.py:1496) is used by agent.py:2070 and has no param_resolver equivalent. The *Config dataclasses in feature_configs.py are widely imported and must stay.
Why it matters
Maintenance: the precedence ladder (Instance > Config > Array > Dict > String > Bool > Default) is implemented twice. A fix or new option added to param_resolver silently diverges from the shadow copy in feature_configs. Note the two families also have different signatures (feature_configs: single-arg resolve_memory(value); param_resolver: resolve_memory(value, config_class)), so the duplication is also a subtle inconsistency.
Category
Duplicate / Dead code
Capability preserved
param_resolver remains the canonical resolver — every public config.resolve_* name keeps working unchanged.
- All precedence rules and accepted input forms (Instance/Config/Array/Dict/String/Bool/Default) are retained.
resolve_tools and resolve_tool_search decisions: resolve_tools kept as-is (used in production); resolve_tool_search retained or shimmed for backward-compat even though unreferenced — no public name removed.
- All
*Config dataclasses untouched.
Proposed approach
Make param_resolver canonical and reduce the dead feature_configs resolvers to delegating wrappers (or repoint the single precedence-ladder test at param_resolver and drop the dead bodies). Preserve every public resolve_* name and the *Config dataclasses.
Resolution sketch
# Before: config/feature_configs.py — full second implementation
def resolve_memory(value: MemoryParam) -> Optional[MemoryConfig]:
# ...precedence ladder re-implemented...
# After: thin delegation to the canonical resolver (keeps the name + signature)
def resolve_memory(value: MemoryParam) -> Optional[MemoryConfig]:
from .param_resolver import resolve_memory as _resolve
return _resolve(value, MemoryConfig)
Severity
Low
Validation
- Traced:
resolve_memory/knowledge/planning/reflection/guardrails/web/caching/autonomy in feature_configs.py have zero production references (only param_resolver/__init__ routing + one test).
resolve_tool_search has zero references anywhere.
- Confirmed
resolve_tools IS used (agent.py:2070) — explicitly kept.
- No public API name removed; behaviour and all options preserved.
Keep unchanged
param_resolver.py (canonical resolver) and all its precedence logic.
resolve_tools in feature_configs.py.
- All
*Config dataclasses (MemoryConfig, WebConfig, OutputConfig, MultiAgent*Config, etc.) and the public config.resolve_* names.
Summary
praisonaiagents/config/feature_configs.pycarries a second, parallel implementation of the parameter-precedence resolvers that the SDK already provides inpraisonaiagents/config/param_resolver.py(which self-documents as "the SINGLE, DRY resolver"). Thefeature_configsversions have no production callers — every publicconfig.resolve_*name routes toparam_resolver— and are kept alive only by one precedence-ladder test. This is duplicate resolver logic that can be consolidated without dropping any option or behaviour.Current behaviour
Dead duplicate resolvers in
config/feature_configs.py(none referenced by production code):resolve_memory(1274),resolve_knowledge(1346),resolve_planning(1400),resolve_reflection(1413),resolve_guardrails(1426),resolve_web(1441),resolve_caching(1455),resolve_autonomy(1468)resolve_tool_search(1481) — zero references anywhere in the codebase (not even tests).Routing evidence:
config/__init__.pymaps everyresolve_*name to"param_resolver"(lines 136–148). None map tofeature_configs.praisonaiagents/__init__.pymapsresolve_memory/knowledge/web/planning/reflection/autonomy/caching/guardrailstopraisonaiagents.config.param_resolver(lines 424–437).agent/agent.py:1430importsresolve_guardrailsfromparam_resolver(notfeature_configs).feature_configsresolver functions are tests (e.g.tests/unit/config/test_precedence_ladder.py). No production path imports them.Not dead — keep:
resolve_tools(feature_configs.py:1496) is used byagent.py:2070and has noparam_resolverequivalent. The*Configdataclasses infeature_configs.pyare widely imported and must stay.Why it matters
Maintenance: the precedence ladder (Instance > Config > Array > Dict > String > Bool > Default) is implemented twice. A fix or new option added to
param_resolversilently diverges from the shadow copy infeature_configs. Note the two families also have different signatures (feature_configs: single-argresolve_memory(value);param_resolver:resolve_memory(value, config_class)), so the duplication is also a subtle inconsistency.Category
Duplicate / Dead code
Capability preserved
param_resolverremains the canonical resolver — every publicconfig.resolve_*name keeps working unchanged.resolve_toolsandresolve_tool_searchdecisions:resolve_toolskept as-is (used in production);resolve_tool_searchretained or shimmed for backward-compat even though unreferenced — no public name removed.*Configdataclasses untouched.Proposed approach
Make
param_resolvercanonical and reduce the deadfeature_configsresolvers to delegating wrappers (or repoint the single precedence-ladder test atparam_resolverand drop the dead bodies). Preserve every publicresolve_*name and the*Configdataclasses.Resolution sketch
Severity
Low
Validation
resolve_memory/knowledge/planning/reflection/guardrails/web/caching/autonomyinfeature_configs.pyhave zero production references (only param_resolver/__init__routing + one test).resolve_tool_searchhas zero references anywhere.resolve_toolsIS used (agent.py:2070) — explicitly kept.Keep unchanged
param_resolver.py(canonical resolver) and all its precedence logic.resolve_toolsinfeature_configs.py.*Configdataclasses (MemoryConfig,WebConfig,OutputConfig,MultiAgent*Config, etc.) and the publicconfig.resolve_*names.