fix(experimental): allow AgentExecutor restore from checkpoint

llm and prompt were declared required with exclude=True, making the
model un-restorable from its own serialized output. Mirror the
CrewAgentExecutor pattern: make them nullable with default None, keep
exclude=True, and re-attach llm on the resume path alongside the other
re-attached fields. Guard the two prompt-deref sites so the runtime
invariant survives the looser type.
This commit is contained in:
Greyson LaLonde
2026-05-22 23:24:12 +08:00
committed by GitHub
parent 179c20b352
commit 88e95befe7
2 changed files with 24 additions and 2 deletions

View File

@@ -1109,9 +1109,14 @@ class Agent(BaseAgent):
"""
if self.agent_executor is None:
raise RuntimeError("Agent executor is not initialized.")
if not isinstance(self.llm, BaseLLM):
raise RuntimeError(
"LLM must be resolved before updating agent executor parameters."
)
if task is not None:
self.agent_executor.task = task
self.agent_executor.llm = self.llm
self.agent_executor.tools = tools
self.agent_executor.original_tools = raw_tools
self.agent_executor.prompt = prompt
@@ -1411,6 +1416,11 @@ class Agent(BaseAgent):
if _is_resuming_agent_executor(self.agent_executor):
executor = self.agent_executor
if not isinstance(self.llm, BaseLLM):
raise RuntimeError(
"LLM must be resolved before resuming agent executor."
)
executor.llm = self.llm
executor.tools = parsed_tools
executor.tools_names = get_tool_names(parsed_tools)
executor.tools_description = render_text_description_and_args(parsed_tools)

View File

@@ -173,8 +173,10 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor):
executor_type: Literal["experimental"] = "experimental"
suppress_flow_events: bool = True # always suppress for executor
llm: BaseLLM = Field(exclude=True)
prompt: SystemPromptResult | StandardPromptResult = Field(exclude=True)
llm: BaseLLM | None = Field(default=None, exclude=True)
prompt: SystemPromptResult | StandardPromptResult | None = Field(
default=None, exclude=True
)
max_iter: int = Field(default=25, exclude=True)
tools: list[CrewStructuredTool] = Field(default_factory=list, exclude=True)
tools_names: str = Field(default="", exclude=True)
@@ -2585,6 +2587,11 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor):
self._kickoff_input = inputs.get("input", "")
if self.llm is None or self.prompt is None:
raise RuntimeError(
"AgentExecutor.llm or .prompt is unset; the executor was "
"not fully restored or initialized before execution."
)
if "system" in self.prompt:
from crewai.llms.cache import mark_cache_breakpoint
@@ -2686,6 +2693,11 @@ class AgentExecutor(Flow[AgentExecutorState], BaseAgentExecutor):
self._kickoff_input = inputs.get("input", "")
if self.llm is None or self.prompt is None:
raise RuntimeError(
"AgentExecutor.llm or .prompt is unset; the executor was "
"not fully restored or initialized before execution."
)
if "system" in self.prompt:
from crewai.llms.cache import mark_cache_breakpoint