use crate::cm_agent::agent_turn::{
AssessTurnRoutingParams, TurnRouteDriver, TurnStartSnapshot, assess_turn_routing,
};
use crate::agent::per_coord::PerCoordinator;
use crate::agent::agent_turn::errors::RunAgentTurnError;
use super::orchestration_entry::{TurnOrchestrationTransition, log_orchestration_transition};
use super::orchestration_route::record_and_emit_turn_route_decision;
use super::react_turn::run_react_turn;
use crate::agent::agent_turn::intent_at_turn_start;
use crate::agent::agent_turn::params::RunLoopParams;
fn turn_start_snapshot_or_unknown(p: &RunLoopParams<'_>) -> TurnStartSnapshot {
p.turn
.turn_planner_hints
.turn_start_snapshot
.clone()
.unwrap_or(TurnStartSnapshot::Disabled)
}
pub(crate) async fn dispatch_react_turn(
p: &mut RunLoopParams<'_>,
per_coord: &mut PerCoordinator,
) -> Result<(), RunAgentTurnError> {
intent_at_turn_start::run_act_turn_start_heuristics(p);
if crate::session_mode_turn::session_mode_requires_readonly_tools(p.ctx.attach.session_mode) {
p.turn.turn_planner_hints.step_executor_constraint =
Some(crate::cm_agent::plan_artifact::PlanStepExecutorKind::ReviewReadonly);
tracing::info!(
target: "crabmate::agent_turn",
session_mode = %p.ctx.attach.session_mode,
"session_mode applied ReviewReadonly after act heuristics"
);
}
let assessed = assess_turn_routing(AssessTurnRoutingParams {
cfg: p.ctx.core.cfg.as_ref(),
turn_start: turn_start_snapshot_or_unknown(p),
});
record_and_emit_turn_route_decision(p, &assessed.decision).await;
match assessed.driver {
TurnRouteDriver::ReAct => {
let mode = assessed.decision.orchestration_mode.as_str();
log_orchestration_transition(
TurnOrchestrationTransition::ReActEntryResolved,
Some(mode),
&[],
);
tracing::info!(
target: "crabmate::agent_turn",
turn_orchestration_mode = mode,
freeform_because = assessed.decision.freeform_because.as_deref(),
planner_executor_mode = p.ctx.core.cfg.per_plan_policy.planner_executor_mode.as_str(),
"dispatch_react_turn"
);
run_react_turn(p, per_coord).await
}
}
}