Description
Description
The current implementation of Agent._execute_event_loop_cycle()
removes kwargs parameters including system_prompt
, making it impossible to dynamically override the system prompt when calling the agent.
See agent-builder: https://github.com/strands-agents/agent-builder/blob/main/src/strands_agents_builder/strands.py#L178
Current Behavior
In src/strands/agent/agent.py
, the _execute_event_loop_cycle
method removes several kwargs:
def _execute_event_loop_cycle(self, callback_handler: Callable, kwargs: dict[str, Any]) -> AgentResult:
# ... docstring ...
kwargs.pop("agent", None)
kwargs.pop("model", None)
kwargs.pop("system_prompt", None) # <-- This prevents dynamic override
kwargs.pop("tool_execution_handler", None)
kwargs.pop("event_loop_metrics", None)
kwargs.pop("callback_handler", None)
kwargs.pop("tool_handler", None)
kwargs.pop("messages", None)
kwargs.pop("tool_config", None)
# ... rest of the method uses self.system_prompt instead
This means calls like agent(query, system_prompt="new prompt")
are ignored.
Expected Behavior
Users should be able to dynamically override the system prompt (and other parameters) on a per-call basis:
agent = Agent(system_prompt="Default prompt")
response = agent("Hello", system_prompt="Custom prompt for this call")
Proposed Solution
Instead of removing the kwargs, extract them with fallbacks to instance values:
def _execute_event_loop_cycle(self, callback_handler: Callable, kwargs: dict[str, Any]) -> AgentResult:
# Extract parameters with fallbacks to instance values
system_prompt = kwargs.pop("system_prompt", self.system_prompt)
model = kwargs.pop("model", self.model)
tool_execution_handler = kwargs.pop("tool_execution_handler", self.thread_pool_wrapper)
event_loop_metrics = kwargs.pop("event_loop_metrics", self.event_loop_metrics)
callback_handler = kwargs.pop("callback_handler", callback_handler)
tool_handler = kwargs.pop("tool_handler", self.tool_handler)
messages = kwargs.pop("messages", self.messages)
tool_config = kwargs.pop("tool_config", self.tool_config)
kwargs.pop("agent", None) # Remove agent to avoid conflicts
try:
# Execute the main event loop cycle with extracted parameters
stop_reason, message, metrics, state = event_loop_cycle(
model=model,
system_prompt=system_prompt, # Use extracted value
messages=messages,
tool_config=tool_config,
callback_handler=callback_handler,
tool_handler=tool_handler,
tool_execution_handler=tool_execution_handler,
event_loop_metrics=event_loop_metrics,
agent=self,
event_loop_parent_span=self.trace_span,
**kwargs,
)
# ... rest of method
Use Case Example
This enhancement would enable powerful patterns like dynamic system prompt switching:
#!/usr/bin/env python3
from strands import Agent
agent = Agent(system_prompt="You are a helpful assistant.")
# Use default system prompt
response1 = agent("Hello")
# Override system prompt for specific interaction
response2 = agent("Analyze this code", system_prompt="You are a senior code reviewer.")
# Use different prompt for creative tasks
response3 = agent("Write a poem", system_prompt="You are a creative poet.")
Real-World Impact
This feature is particularly valuable for:
- Multi-purpose agents that need different personas/expertise per interaction
- Conversation management where system prompts include dynamic context
- CLI tools that want to inject conversation history into system prompts
- Testing scenarios where different prompts need to be evaluated
Current Workaround
Currently, users must create new Agent instances for different system prompts, which is inefficient and loses conversation context.
Files Affected
src/strands/agent/agent.py
- Main fix in_execute_event_loop_cycle
method- Potentially related test files for validation
Breaking Changes
This change should be backwards compatible as it maintains existing behavior while adding new functionality.