Skip to content

Commit 31690bb

Browse files
committed
fix(core): add logs for stuck subagent task completion
1 parent 742105f commit 31690bb

5 files changed

Lines changed: 386 additions & 16 deletions

File tree

src/crates/core/src/agentic/coordination/coordinator.rs

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,6 +2721,19 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
27212721
let initial_deadline =
27222722
timeout_seconds.map(|seconds| Instant::now() + Duration::from_secs(seconds));
27232723
let (deadline_tx, mut deadline_rx) = watch::channel(initial_deadline);
2724+
let subagent_started_at = Instant::now();
2725+
let parent_session_id = subagent_parent_info
2726+
.as_ref()
2727+
.map(|info| info.session_id.as_str())
2728+
.unwrap_or("-");
2729+
let parent_dialog_turn_id = subagent_parent_info
2730+
.as_ref()
2731+
.map(|info| info.dialog_turn_id.as_str())
2732+
.unwrap_or("-");
2733+
let parent_tool_call_id = subagent_parent_info
2734+
.as_ref()
2735+
.map(|info| info.tool_call_id.as_str())
2736+
.unwrap_or("-");
27242737

27252738
let context_profile_policy = self.context_profile_policy_for_subagent(
27262739
&agent_type,
@@ -2909,6 +2922,17 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
29092922
let execution_engine = self.execution_engine.clone();
29102923
let tool_pipeline = self.tool_pipeline.clone();
29112924
let agent_type_for_execution = agent_type.clone();
2925+
debug!(
2926+
"Subagent execution task starting: agent_type={}, session_id={}, dialog_turn_id={}, parent_session_id={}, parent_dialog_turn_id={}, parent_tool_call_id={}, timeout_seconds={:?}, wait_ms={}",
2927+
agent_type,
2928+
session_id,
2929+
dialog_turn_id,
2930+
parent_session_id,
2931+
parent_dialog_turn_id,
2932+
parent_tool_call_id,
2933+
timeout_seconds,
2934+
wait_ms
2935+
);
29122936
let mut execution_task = tokio::spawn(async move {
29132937
execution_engine
29142938
.execute_dialog_turn(
@@ -2974,6 +2998,23 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
29742998
}
29752999
};
29763000

3001+
let execution_outcome_label = match &execution_outcome {
3002+
SubagentExecutionOutcome::Completed(_) => "completed",
3003+
SubagentExecutionOutcome::Cancelled => "cancelled",
3004+
SubagentExecutionOutcome::TimedOut => "timed_out",
3005+
};
3006+
debug!(
3007+
"Subagent execution outcome resolved: agent_type={}, session_id={}, dialog_turn_id={}, parent_session_id={}, parent_dialog_turn_id={}, parent_tool_call_id={}, outcome={}, duration_ms={}",
3008+
agent_type,
3009+
session_id,
3010+
dialog_turn_id,
3011+
parent_session_id,
3012+
parent_dialog_turn_id,
3013+
parent_tool_call_id,
3014+
execution_outcome_label,
3015+
subagent_started_at.elapsed().as_millis()
3016+
);
3017+
29773018
let result = match execution_outcome {
29783019
SubagentExecutionOutcome::Completed(join_result) => match join_result {
29793020
Ok(result) => result,
@@ -3203,21 +3244,69 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
32033244
};
32043245

32053246
// Clean up subagent session resources after successful execution
3206-
debug!("Starting subagent resource cleanup: session={}", session_id);
3247+
debug!(
3248+
"Subagent successful execution produced final text: agent_type={}, session_id={}, dialog_turn_id={}, parent_session_id={}, parent_dialog_turn_id={}, parent_tool_call_id={}, text_len={}, duration_ms={}",
3249+
agent_type,
3250+
session_id,
3251+
dialog_turn_id,
3252+
parent_session_id,
3253+
parent_dialog_turn_id,
3254+
parent_tool_call_id,
3255+
response_text.len(),
3256+
subagent_started_at.elapsed().as_millis()
3257+
);
3258+
let cleanup_started_at = Instant::now();
3259+
debug!(
3260+
"Subagent cleanup starting after successful execution: agent_type={}, session_id={}, dialog_turn_id={}, parent_session_id={}, parent_dialog_turn_id={}, parent_tool_call_id={}",
3261+
agent_type,
3262+
session_id,
3263+
dialog_turn_id,
3264+
parent_session_id,
3265+
parent_dialog_turn_id,
3266+
parent_tool_call_id
3267+
);
32073268
if let Err(e) = self.cleanup_subagent_resources(&session_id).await {
32083269
warn!(
32093270
"Failed to cleanup subagent resources: session={}, error={}",
32103271
session_id, e
32113272
);
32123273
} else {
32133274
debug!(
3214-
"Subagent resource cleanup completed: session={}",
3215-
session_id
3275+
"Subagent cleanup completed after successful execution: agent_type={}, session_id={}, dialog_turn_id={}, parent_session_id={}, parent_dialog_turn_id={}, parent_tool_call_id={}, cleanup_duration_ms={}",
3276+
agent_type,
3277+
session_id,
3278+
dialog_turn_id,
3279+
parent_session_id,
3280+
parent_dialog_turn_id,
3281+
parent_tool_call_id,
3282+
cleanup_started_at.elapsed().as_millis()
32163283
);
32173284
}
3285+
debug!(
3286+
"Subagent timeout registry removal starting: agent_type={}, session_id={}, dialog_turn_id={}",
3287+
agent_type, session_id, dialog_turn_id
3288+
);
32183289
let mut registry = self.subagent_timeout_registry.write().await;
32193290
registry.remove(&session_id);
3291+
debug!(
3292+
"Subagent timeout registry removal completed: agent_type={}, session_id={}, dialog_turn_id={}, total_duration_ms={}",
3293+
agent_type,
3294+
session_id,
3295+
dialog_turn_id,
3296+
subagent_started_at.elapsed().as_millis()
3297+
);
32203298

3299+
debug!(
3300+
"Subagent result returning to caller: agent_type={}, session_id={}, dialog_turn_id={}, parent_session_id={}, parent_dialog_turn_id={}, parent_tool_call_id={}, status=completed, text_len={}, total_duration_ms={}",
3301+
agent_type,
3302+
session_id,
3303+
dialog_turn_id,
3304+
parent_session_id,
3305+
parent_dialog_turn_id,
3306+
parent_tool_call_id,
3307+
response_text.len(),
3308+
subagent_started_at.elapsed().as_millis()
3309+
);
32213310
Ok(SubagentResult::completed(response_text))
32223311
}
32233312

@@ -3442,17 +3531,21 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
34423531
///
34433532
/// Release resources occupied by subagent session (sandbox, etc.) and delete session
34443533
async fn cleanup_subagent_resources(&self, session_id: &str) -> BitFunResult<()> {
3445-
debug!(
3446-
"Starting subagent resource cleanup: session_id={}",
3447-
session_id
3448-
);
3534+
let cleanup_started_at = Instant::now();
3535+
debug!("Starting subagent resource cleanup: session_id={}", session_id);
34493536

34503537
// Clean up snapshot system resources
34513538
if let Some(workspace_path) = self
34523539
.session_manager
34533540
.get_session(session_id)
34543541
.and_then(|session| session.config.workspace_path.map(std::path::PathBuf::from))
34553542
{
3543+
debug!(
3544+
"Subagent cleanup stage starting: session_id={}, stage=snapshot_cleanup, workspace_path={}",
3545+
session_id,
3546+
workspace_path.display()
3547+
);
3548+
let stage_started_at = Instant::now();
34563549
if let Ok(snapshot_manager) =
34573550
crate::service::snapshot::ensure_snapshot_manager_for_workspace(&workspace_path)
34583551
{
@@ -3470,6 +3563,11 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
34703563
);
34713564
}
34723565
}
3566+
debug!(
3567+
"Subagent cleanup stage completed: session_id={}, stage=snapshot_cleanup, duration_ms={}",
3568+
session_id,
3569+
stage_started_at.elapsed().as_millis()
3570+
);
34733571
}
34743572

34753573
// Delete the subagent session itself, including runtime context and persisted turn data.
@@ -3479,6 +3577,12 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
34793577
.and_then(|session| session.config.workspace_path.map(std::path::PathBuf::from));
34803578

34813579
if let Some(workspace_path) = workspace_path {
3580+
debug!(
3581+
"Subagent cleanup stage starting: session_id={}, stage=session_delete, workspace_path={}",
3582+
session_id,
3583+
workspace_path.display()
3584+
);
3585+
let stage_started_at = Instant::now();
34823586
if let Err(e) = self
34833587
.session_manager
34843588
.delete_session(&workspace_path, session_id)
@@ -3491,6 +3595,11 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
34913595
} else {
34923596
debug!("Subagent session deleted: session={}", session_id);
34933597
}
3598+
debug!(
3599+
"Subagent cleanup stage completed: session_id={}, stage=session_delete, duration_ms={}",
3600+
session_id,
3601+
stage_started_at.elapsed().as_millis()
3602+
);
34943603
} else {
34953604
warn!(
34963605
"Failed to delete subagent session because workspace_path is missing: session={}",
@@ -3499,8 +3608,9 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
34993608
}
35003609

35013610
debug!(
3502-
"Subagent resource cleanup completed: session_id={}",
3503-
session_id
3611+
"Subagent resource cleanup completed: session_id={}, duration_ms={}",
3612+
session_id,
3613+
cleanup_started_at.elapsed().as_millis()
35043614
);
35053615
Ok(())
35063616
}

src/crates/core/src/agentic/session/session_manager.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ use crate::service::session::{
2424
use crate::service::snapshot::ensure_snapshot_manager_for_workspace;
2525
use crate::util::errors::{BitFunError, BitFunResult};
2626
use crate::util::sanitize_plain_model_output;
27+
use crate::util::timing::elapsed_ms_u64;
2728
use dashmap::DashMap;
2829
use log::{debug, error, info, warn};
2930
use serde_json::json;
3031
use std::collections::HashSet;
3132
use std::path::{Path, PathBuf};
3233
use std::sync::Arc;
34+
use std::time::Instant;
3335
use std::time::{Duration, SystemTime};
3436
use tokio::time;
3537

@@ -1529,7 +1531,20 @@ impl SessionManager {
15291531
workspace_path: &Path,
15301532
session_id: &str,
15311533
) -> BitFunResult<()> {
1534+
let delete_started_at = Instant::now();
1535+
debug!(
1536+
"Session deletion started: session_id={}, workspace_path={}, persistence_enabled={}",
1537+
session_id,
1538+
workspace_path.display(),
1539+
self.config.enable_persistence
1540+
);
1541+
15321542
// 1. Clean up snapshot system resources (including physical snapshot files)
1543+
let snapshot_stage_started_at = Instant::now();
1544+
debug!(
1545+
"Session deletion stage starting: session_id={}, stage=snapshot_cleanup",
1546+
session_id
1547+
);
15331548
if let Ok(snapshot_manager) = ensure_snapshot_manager_for_workspace(workspace_path) {
15341549
let snapshot_service = snapshot_manager.get_snapshot_service();
15351550
let snapshot_service = snapshot_service.read().await;
@@ -1542,17 +1557,47 @@ impl SessionManager {
15421557
);
15431558
}
15441559
}
1560+
debug!(
1561+
"Session deletion stage completed: session_id={}, stage=snapshot_cleanup, duration_ms={}",
1562+
session_id,
1563+
elapsed_ms_u64(snapshot_stage_started_at)
1564+
);
15451565

1566+
let context_stage_started_at = Instant::now();
1567+
debug!(
1568+
"Session deletion stage starting: session_id={}, stage=context_store_delete",
1569+
session_id
1570+
);
15461571
self.context_store.delete_session(session_id);
1572+
debug!(
1573+
"Session deletion stage completed: session_id={}, stage=context_store_delete, duration_ms={}",
1574+
session_id,
1575+
elapsed_ms_u64(context_stage_started_at)
1576+
);
15471577

15481578
// 2. Delete persisted data
15491579
if self.config.enable_persistence {
1580+
let persistence_stage_started_at = Instant::now();
1581+
debug!(
1582+
"Session deletion stage starting: session_id={}, stage=persistence_delete",
1583+
session_id
1584+
);
15501585
self.persistence_manager
15511586
.delete_session(workspace_path, session_id)
15521587
.await?;
1588+
debug!(
1589+
"Session deletion stage completed: session_id={}, stage=persistence_delete, duration_ms={}",
1590+
session_id,
1591+
elapsed_ms_u64(persistence_stage_started_at)
1592+
);
15531593
}
15541594

15551595
if let Some(cron) = crate::service::cron::get_global_cron_service() {
1596+
let cron_stage_started_at = Instant::now();
1597+
debug!(
1598+
"Session deletion stage starting: session_id={}, stage=cron_cleanup",
1599+
session_id
1600+
);
15561601
match cron.delete_jobs_for_session(session_id).await {
15571602
Ok(removed) if removed > 0 => {
15581603
info!(
@@ -1568,12 +1613,23 @@ impl SessionManager {
15681613
);
15691614
}
15701615
}
1616+
debug!(
1617+
"Session deletion stage completed: session_id={}, stage=cron_cleanup, duration_ms={}",
1618+
session_id,
1619+
elapsed_ms_u64(cron_stage_started_at)
1620+
);
15711621
}
15721622

15731623
// 3. Clean up associated Terminal session
15741624
use crate::service::terminal::TerminalApi;
15751625
if let Ok(terminal_api) = TerminalApi::from_singleton() {
15761626
let binding = terminal_api.session_manager().binding();
1627+
let terminal_stage_started_at = Instant::now();
1628+
debug!(
1629+
"Session deletion stage starting: session_id={}, stage=terminal_binding_cleanup, has_binding={}",
1630+
session_id,
1631+
binding.has(session_id)
1632+
);
15771633
if binding.has(session_id) {
15781634
if let Err(e) = binding.remove(session_id).await {
15791635
warn!("Failed to cleanup associated Terminal session: {}", e);
@@ -1584,12 +1640,32 @@ impl SessionManager {
15841640
);
15851641
}
15861642
}
1643+
debug!(
1644+
"Session deletion stage completed: session_id={}, stage=terminal_binding_cleanup, duration_ms={}",
1645+
session_id,
1646+
elapsed_ms_u64(terminal_stage_started_at)
1647+
);
15871648
}
15881649

15891650
// 4. Remove from memory
1651+
let memory_stage_started_at = Instant::now();
1652+
debug!(
1653+
"Session deletion stage starting: session_id={}, stage=in_memory_remove",
1654+
session_id
1655+
);
15901656
self.sessions.remove(session_id);
1657+
debug!(
1658+
"Session deletion stage completed: session_id={}, stage=in_memory_remove, duration_ms={}",
1659+
session_id,
1660+
elapsed_ms_u64(memory_stage_started_at)
1661+
);
15911662

1592-
info!("Session deletion completed: session_id={}", session_id);
1663+
info!(
1664+
"Session deletion completed: session_id={}, workspace_path={}, duration_ms={}",
1665+
session_id,
1666+
workspace_path.display(),
1667+
elapsed_ms_u64(delete_started_at)
1668+
);
15931669

15941670
Ok(())
15951671
}

0 commit comments

Comments
 (0)