fix: implement runtime support for widened type hints in Agent init

- Add string preset handling in _init_autonomy() for autonomy='full_auto' etc.
- Add str/dict support in context_manager property for context='summarize' etc.
- Add dict-to-ApprovalConfig conversion for approval={'backend': ..., 'all_tools': True}
- Add string mode handling in learn parameter for learn='agentic' etc.
- Fix AUTONOMY_PRESETS to use 'level' field (not 'mode') per AutonomyConfig

Resolves type hint/implementation mismatches identified by code reviewers.
All new type hints now have proper runtime support.

Co-authored-by: Mervin Praison <[email protected]>
This commit is contained in:
MervinPraisonandMervin Praison committed 2026-04-05 05:20:44 +00:00
1 parent 9c2f14e042
commit 72e477f4a3
2 files changed
+98 -3

No files matched your search

@@ -1076,6 +1076,18 @@ class Agent(ToolExecutionMixin, ChatHandlerMixin, SessionManagerMixin, ChatMixin
_learn_config = learn
elif isinstance(learn, dict):
_learn_config = LearnConfig(**learn)
elif isinstance(learn, str):
# String mode: "disabled", "agentic", "propose"
from ..memory.learn.protocols import LearnMode
if learn == "disabled":
_learn_config = None
elif learn == "agentic":
_learn_config = LearnConfig(mode=LearnMode.AGENTIC)
elif learn == "propose":
_learn_config = LearnConfig(mode=LearnMode.PROPOSE)
else:
# Unknown string mode, disable learning
_learn_config = None
else:
_learn_config = learn # Pass through
elif _memory_config is not None and isinstance(_memory_config, MemoryConfig):
@@ -1651,6 +1663,12 @@ Your Goal: {self.goal}
self._approval_backend = approval.backend
self._approve_all_tools = approval.all_tools
self._approval_timeout = approval.timeout # None = indefinite, 0 = backend default
elif isinstance(approval, dict):
# Dict config: convert to ApprovalConfig
approval_config = ApprovalConfig(**approval)
self._approval_backend = approval_config.backend
self._approve_all_tools = approval_config.all_tools
self._approval_timeout = approval_config.timeout
else:
# Plain backend object — dangerous tools only, backend default timeout
self._approval_backend = approval
@@ -1958,6 +1976,64 @@ Your Goal: {self.goal}
elif hasattr(self._context_param, 'process'):
# Already a ContextManager instance
self._context_manager = self._context_param
elif isinstance(self._context_param, str):
# String preset: "sliding_window", "summarize", "truncate"
from ..config.presets import CONTEXT_PRESETS
preset_config = CONTEXT_PRESETS.get(self._context_param)
if preset_config is not None:
# Convert preset to ContextConfig, then to ManagerConfig
try:
from ..context.models import ContextConfig as _ContextConfig
context_config = _ContextConfig(**preset_config)
manager_config = ManagerConfig(
auto_compact=context_config.auto_compact,
compact_threshold=context_config.compact_threshold,
strategy=context_config.strategy,
output_reserve=context_config.output_reserve,
default_tool_output_max=context_config.tool_output_max,
protected_tools=list(context_config.protected_tools),
keep_recent_turns=context_config.keep_recent_turns,
monitor_enabled=context_config.monitor.enabled if context_config.monitor else False,
)
self._context_manager = ContextManager(
model=self.llm if isinstance(self.llm, str) else "gpt-4o-mini",
config=manager_config,
agent_name=self.name or "Agent",
session_cache=self._session_dedup_cache,
llm_summarize_fn=None,
)
except Exception as e:
logging.debug(f"Context preset conversion failed: {e}")
self._context_manager = None
else:
# Unknown string preset, disable
self._context_manager = None
elif isinstance(self._context_param, dict):
# Dict config: convert to ContextConfig, then to ManagerConfig
try:
from ..context.models import ContextConfig as _ContextConfig
context_config = _ContextConfig(**self._context_param)
manager_config = ManagerConfig(
auto_compact=context_config.auto_compact,
compact_threshold=context_config.compact_threshold,
strategy=context_config.strategy,
output_reserve=context_config.output_reserve,
default_tool_output_max=context_config.tool_output_max,
protected_tools=list(context_config.protected_tools),
keep_recent_turns=context_config.keep_recent_turns,
monitor_enabled=context_config.monitor.enabled if context_config.monitor else False,
)
llm_summarize_enabled = self._context_param.get('llm_summarize', False)
self._context_manager = ContextManager(
model=self.llm if isinstance(self.llm, str) else "gpt-4o-mini",
config=manager_config,
agent_name=self.name or "Agent",
session_cache=self._session_dedup_cache,
llm_summarize_fn=self._create_llm_summarize_fn() if llm_summarize_enabled else None,
)
except Exception as e:
logging.debug(f"Context dict conversion failed: {e}")
self._context_manager = None
else:
# Unknown type, disable
self._context_manager = None
@@ -2174,6 +2250,25 @@ Summary:"""
# Extract verification_hooks from AutonomyConfig if provided
if autonomy.verification_hooks and not verification_hooks:
self._verification_hooks = autonomy.verification_hooks
elif isinstance(autonomy, str):
# String preset: "suggest", "auto_edit", "full_auto"
from ..config.presets import AUTONOMY_PRESETS
preset_config = AUTONOMY_PRESETS.get(autonomy)
if preset_config is not None:
config = AutonomyConfig.from_dict(preset_config)
else:
# Unknown string preset — disable autonomy
self.autonomy_enabled = False
self.autonomy_config = {}
self._autonomy_trigger = None
self._doom_loop_tracker = None
self._file_snapshot = None
self._snapshot_stack = []
self._redo_stack = []
self._autonomy_turn_tool_count = 0
self._consecutive_no_tool_turns = 0
self._doom_recovery_active = False
return
else:
self.autonomy_enabled = False
self.autonomy_config = {}
@@ -300,9 +300,9 @@ CONTEXT_PRESETS: Dict[str, Dict[str, Any]] = {
# =============================================================================
AUTONOMY_PRESETS: Dict[str, Dict[str, Any]] = {
"suggest": {"mode": "suggest"},
"auto_edit": {"mode": "auto_edit"},
"full_auto": {"mode": "full_auto"},
"suggest": {"level": "suggest"},
"auto_edit": {"level": "auto_edit"},
"full_auto": {"level": "full_auto"},
}