[Bug]: CodeActAgent raises UnboundLocalError at codeact_agent.py:110 when code_act_system_prompt is a BasePromptTemplate and system_prompt is left at None
Bug Description
CodeActAgent.__init__ crashes when code_act_system_prompt is passed as a PromptTemplate/BasePromptTemplate and system_prompt is left at its default of None.
In the elif isinstance(code_act_system_prompt, BasePromptTemplate) branch, the local code_act_system_str is assigned only inside the nested if system_prompt: block (lines 107-109), but it is read unconditionally on line 110. When system_prompt is None, the local is never bound and construction dies with:
UnboundLocalError: cannot access local variable 'code_act_system_str' where it is not associated with a value
The object is never built, so no custom-template CodeActAgent can be constructed without also passing a system_prompt.
Expected behaviour, and the basis for it
Passing a PromptTemplate for code_act_system_prompt without a system_prompt should construct the agent, using the template as the code-act system prompt.
The parameter's own annotation advertises this combination: code_act_system_prompt: Union[str, BasePromptTemplate] in the model field (line 77) and in the __init__ signature (lines 93-95), alongside system_prompt: Optional[str] = None (line 88). The sibling str branch (lines 102-105) handles exactly this combination correctly — it appends system_prompt only when one was given, then builds the PromptTemplate unconditionally. The BasePromptTemplate branch is meant to mirror that: lines 106-109 show the intent, and line 110 sits outside the if system_prompt: guard, so the assignment of code_act_system_str was intended to be unconditional too. The defect is the indentation of lines 107-109.
Root cause
llama-index-core/llama_index/core/agent/workflow/codeact_agent.py:107-110 — code_act_system_str = code_act_system_prompt.get_template() is nested inside the if system_prompt: guard, while its only consumer, code_act_system_prompt = PromptTemplate(code_act_system_str) on line 110, is not.
Related
- #19184 (
[Question]: Use of 'system_prompt' parameter in 'CodeAct' Agent, closed) — users were already confused about howsystem_promptandcode_act_system_promptinteract; this crash is the same parameter pair. Not a duplicate: #19184 is a question about prompt precedence, this is a construction-timeUnboundLocalError. - No existing issue or PR referencing
code_act_system_str/ this traceback was found.
I'm happy to open a PR for this — the fix is a one-line re-indent in that branch (build code_act_system_str from get_template() first, then append system_prompt only if it is set). I've verified locally that it makes the case above construct successfully and leaves tests/agent/workflow/test_code_act_agent.py passing (3 passed).
Version
llama-index-core 0.14.24, commit 7169bcd0dca2e16aecc8e0247f34e50079d9c0d5
Reproduced with Python 3.11.16 on macOS (Darwin 25.6.0). No API key or network access is needed — the repro uses MockLLM.
Steps to Reproduce
from llama_index.core.agent.workflow.codeact_agent import CodeActAgent
from llama_index.core.prompts import PromptTemplate
from llama_index.core.llms.mock import MockLLM
async def execute(code: str) -> dict:
return {"result": "ok"}
# case A: PromptTemplate, no system_prompt (the documented Union[str, BasePromptTemplate] input)
CodeActAgent(
code_execute_fn=execute,
code_act_system_prompt=PromptTemplate("You are a coder. {tool_descriptions}"),
llm=MockLLM(),
)
# case B: PromptTemplate WITH system_prompt (works)
CodeActAgent(
code_execute_fn=execute,
code_act_system_prompt=PromptTemplate("You are a coder. {tool_descriptions}"),
system_prompt="Be terse.",
llm=MockLLM(),
)
# case C: str prompt, no system_prompt (the default path, works)
CodeActAgent(
code_execute_fn=execute,
code_act_system_prompt="You are a coder. {tool_descriptions}",
llm=MockLLM(),
)
Case A fails; cases B and C succeed.
Relevant Logs/Tracebacks
--- case A: PromptTemplate, no system_prompt (documented Union[str, BasePromptTemplate] input) ---
UnboundLocalError: cannot access local variable 'code_act_system_str' where it is not associated with a value
--- case B: PromptTemplate WITH system_prompt (works?) ---
OK, agent built: code_act_agent
--- case C: str prompt, no system_prompt (the default path, for contrast) ---
OK, agent built: code_act_agent
Source: run-llama/llama_index