Pure decision logic for Codex `SubagentStart` events.
(event_json: &str)
| 212 | |
| 213 | /// Pure decision logic for Codex `SubagentStart` events. |
| 214 | pub fn evaluate_codex_subagent_start(event_json: &str) -> Option<String> { |
| 215 | let parsed: Value = serde_json::from_str(event_json).ok()?; |
| 216 | let agent_type = parsed |
| 217 | .get("agent_type") |
| 218 | .or_else(|| parsed.get("subagent_type")) |
| 219 | .and_then(Value::as_str) |
| 220 | .unwrap_or_default(); |
| 221 | let task = parsed |
| 222 | .get("prompt") |
| 223 | .or_else(|| parsed.get("task")) |
| 224 | .or_else(|| parsed.get("description")) |
| 225 | .and_then(Value::as_str) |
| 226 | .unwrap_or_default(); |
| 227 | |
| 228 | let hint = decide_hint(&ToolHintInput { |
| 229 | agent: HintAgent::Codex, |
| 230 | session_id: event_session_id(&parsed), |
| 231 | tool_name: Some("SubagentStart".to_string()), |
| 232 | command: None, |
| 233 | prompt: (!task.is_empty()).then(|| task.to_string()), |
| 234 | subagent_type: (!agent_type.is_empty()).then(|| agent_type.to_string()), |
| 235 | file_path: None, |
| 236 | hints_enabled: true, |
| 237 | }); |
| 238 | let is_explore = agent_type.eq_ignore_ascii_case("explore"); |
| 239 | let is_research = is_explore || is_code_research_prompt(task); |
| 240 | let needs_context = codex_subagent_needs_context(&parsed); |
| 241 | if is_research || needs_context { |
| 242 | let dedupe_hint = ToolHint { |
| 243 | category: if is_research { |
| 244 | HintCategory::ExploreSubagent |
| 245 | } else { |
| 246 | HintCategory::SubagentStartContext |
| 247 | }, |
| 248 | message: "For Codex subagents, add compact TraceDecay context before isolated work." |
| 249 | .to_string(), |
| 250 | context: CODEX_SUBAGENT_START_CONTEXT.to_string(), |
| 251 | nonblocking: true, |
| 252 | }; |
| 253 | let root = codex_project_root_from_event(event_json); |
| 254 | let hint_id = mint_hint_id(); |
| 255 | record_hint_analytics( |
| 256 | root.as_deref(), |
| 257 | "hint_candidate", |
| 258 | HintAgent::Codex, |
| 259 | event_session_id(&parsed).as_deref(), |
| 260 | &hint_id, |
| 261 | &dedupe_hint, |
| 262 | ); |
| 263 | let _ = deduped_codex_hint(event_json, &parsed, &hint_id, dedupe_hint)?; |
| 264 | let context = codex_subagent_start_context(hint, needs_context); |
| 265 | return Some(codex_additional_context_json("SubagentStart", &context)); |
| 266 | } |
| 267 | None |
| 268 | } |
| 269 | |
| 270 | /// Records a Codex `SubagentStart` and returns the session-local count. |
| 271 | pub fn record_codex_subagent_start(event_json: &str) -> Option<u64> { |