Skip to content

Commit 1980d95

Browse files
committed
Cover planning hook pre-analysis invalidation
1 parent 777655b commit 1980d95

2 files changed

Lines changed: 96 additions & 1 deletion

File tree

core/src/agent/extra_agent_tests.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,101 @@ async fn test_pre_planning_hook_modification_updates_planner_input() {
330330
assert!(post_planning_task.contains("Hook-modified planning task"));
331331
}
332332

333+
#[tokio::test]
334+
async fn test_pre_planning_hook_modification_discards_pre_analysis_plan() {
335+
use crate::planning::{AgentGoal, Complexity, ExecutionPlan, PreAnalysis, Task};
336+
use crate::prompts::AgentStyle;
337+
338+
let mock_client = Arc::new(MockLlmClient::new(vec![
339+
MockLlmClient::text_response(
340+
r#"{
341+
"goal": "Use the hook-modified plan",
342+
"complexity": "Simple",
343+
"steps": [
344+
{
345+
"id": "step-1",
346+
"description": "Execute the hook-modified plan",
347+
"dependencies": [],
348+
"success_criteria": "The pre-analysis plan is not reused"
349+
}
350+
],
351+
"required_tools": []
352+
}"#,
353+
),
354+
MockLlmClient::text_response("Hook-modified plan executed."),
355+
]));
356+
let tool_executor = Arc::new(ToolExecutor::new("/tmp".to_string()));
357+
let (hook, events) =
358+
planning_hook_recorder(crate::hooks::HookResult::continue_with(serde_json::json!({
359+
"modified_task": "Use the hook-modified plan instead"
360+
})));
361+
let config = AgentConfig {
362+
hook_engine: Some(hook),
363+
..AgentConfig::default()
364+
};
365+
let agent = AgentLoop::new(
366+
mock_client.clone(),
367+
tool_executor,
368+
test_tool_context(),
369+
config,
370+
);
371+
372+
let mut stale_plan = ExecutionPlan::new("Stale pre-analysis plan", Complexity::Simple);
373+
stale_plan.add_step(Task::new(
374+
"stale-step",
375+
"This stale pre-analysis step must not run",
376+
));
377+
let pre_analysis = PreAnalysis {
378+
intent: AgentStyle::GeneralPurpose,
379+
requires_planning: true,
380+
goal: AgentGoal::new("Stale pre-analysis goal"),
381+
execution_plan: stale_plan,
382+
optimized_input: "Stale optimized input".to_string(),
383+
};
384+
385+
let result = agent
386+
.execute_with_planning(
387+
&[],
388+
"Original request with stale pre-analysis",
389+
Some("discard-pre-analysis-session"),
390+
None,
391+
Some(pre_analysis),
392+
)
393+
.await
394+
.unwrap();
395+
396+
assert_eq!(result.text, "Hook-modified plan executed.");
397+
398+
let request_texts = mock_client.request_texts.lock().unwrap().clone();
399+
assert!(
400+
request_texts[0]
401+
.contains("Hook-modified planning task:\nUse the hook-modified plan instead"),
402+
"planner input should be regenerated from the hook-modified task: {}",
403+
request_texts[0]
404+
);
405+
assert!(
406+
!request_texts
407+
.iter()
408+
.any(|text| text.contains("This stale pre-analysis step must not run")),
409+
"stale pre-analysis step should not be sent to execution: {:?}",
410+
request_texts
411+
);
412+
413+
let post_planning_subtasks = events
414+
.lock()
415+
.unwrap()
416+
.iter()
417+
.find_map(|event| match event {
418+
crate::hooks::HookEvent::PostPlanning(event) => Some(event.subtasks.clone()),
419+
_ => None,
420+
})
421+
.expect("PostPlanning should be emitted");
422+
assert_eq!(
423+
post_planning_subtasks,
424+
vec!["Execute the hook-modified plan".to_string()]
425+
);
426+
}
427+
333428
// ========================================================================
334429
// AgentEvent serialization
335430
// ========================================================================

core/src/agent/hook_runtime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl AgentLoop {
7979
/// Fire PrePlanning hook before plan generation.
8080
///
8181
/// This is a blocking hook point: policy engines can stop planning before
82-
/// the planner touches the model or emits PlanningStart.
82+
/// PlanningStart is emitted and before the planning phase chooses a plan.
8383
pub(super) async fn fire_pre_planning(
8484
&self,
8585
session_id: &str,

0 commit comments

Comments
 (0)