plans/2025-04-02-system-context-rendering-v1.md
Modify the system context rendering mechanism to:
The current implementation renders the system context only once during agent initialization, which means time-sensitive information like current_time is not updated. Additionally, the system context cannot use dynamic variables from the conversation state.
Modify the TemplateService trait in crates/forge_domain/src/services.rs to include variables in the render_system method signature:
async fn render_system(
&self,
agent: &Agent,
prompt: &Template,
variables: &HashMap<String, Value>,
) -> anyhow::Result<String>;
Update the implementation in crates/forge_services/src/template.rs to handle variables in system context rendering:
async fn render_system(
&self,
_agent: &Agent,
prompt: &Template,
variables: &HashMap<String, Value>,
) -> anyhow::Result<String> {
// Existing code...
// Create the context with README content for all agents
let mut ctx = SystemContext {
current_time,
env: Some(env),
tool_information: Some(self.tool_service.usage_prompt()),
tool_supported: _agent.tool_supported.unwrap_or_default(),
files,
readme: README_CONTENT.to_string(),
custom_rules: _agent.custom_rules.as_ref().cloned().unwrap_or_default(),
variables: variables.clone(), // Add the variables
};
// Render the template with the context and variables
let result = self.hb.render_template(prompt.template.as_str(), &ctx)?;
Ok(result)
}
Modify the SystemContext struct in crates/forge_domain/src/system_context.rs to include variables:
#[derive(Debug, Setters, Clone, Serialize, Deserialize)]
#[setters(strip_option)]
pub struct SystemContext {
// Existing fields...
// Variables passed to the template
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub variables: HashMap<String, Value>,
}
Modify the orchestrator's conversation loop in crates/forge_domain/src/orch.rs to re-render the system context on each iteration:
async fn init_agent(&self, agent_id: &AgentId, event: &Event) -> anyhow::Result<()> {
// Existing code...
loop {
// Get up-to-date variables
let conversation_vars = self.conversation.read().await.variables.clone();
// Re-render the system message if system_prompt is present
if let Some(system_prompt) = &agent.system_prompt {
let system_message = self
.services
.template_service()
.render_system(agent, system_prompt, &conversation_vars)
.await?;
// Update the system message in the context
context = context.set_first_system_message(system_message);
}
// Set context for the current loop iteration
self.set_context(&agent.id, context.clone()).await?;
// Existing loop code...
// If no tool results, break the loop as before
if tool_results.is_empty() {
break;
}
}
// Existing code...
}
Ensure the templates can use variables from the context:
In templates/forge-partial-system-info.hbs and other system templates, add support for variables:
<operating_system>{{env.os}}</operating_system>
<current_time>{{current_time}}</current_time>
<current_working_directory>{{env.cwd}}</current_working_directory>
<default_shell>{{env.shell}}</default_shell>
<home_directory>{{env.home}}</home_directory>
<file_list>
{{#each files}} - {{this}}
{{/each}}
</file_list>
{{!-- Add access to variables --}}
{{#if variables}}
<variables>
{{#each variables}}
<{{@key}}>{{this}}</{{@key}}>
{{/each}}
</variables>
{{/if}}
Update relevant tests to verify the changes:
render_system method with variablesThe implementation will be considered successful if:
current_time