#![cfg_attr(rustfmt, rustfmt::skip)]
#![allow(unused_imports)]
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use agent_client_protocol as acp;
use tokio::sync::{Notify, mpsc, oneshot};
use tokio_util::sync::CancellationToken;
use crate::extensions::notification::{SessionNotification, SessionUpdate};
use crate::session::{
    self, SessionCommand, SessionHandle, SessionThread,
    commands::{PromptCompletionKind, PromptTurnResult as SubagentPromptTurnResult},
    fs_watch::FsWatchCapabilities, info::Info as SessionInfo,
};
use crate::terminal::AsyncTerminalRunner;
use crate::tools::ToolContext;
use kigi_acp_lib::AcpAgentGatewaySender as GatewaySender;
use kigi_tools::implementations::kigi::task::types::*;
use kigi_workspace::file_system::AsyncFileSystem;
use kigi_hunk_tracker::HunkTrackerHandle;
use super::*;
pub(super) fn task_model_override_error(
    requested: Option<&str>,
    provenance: ModelOverrideProvenance,
    is_resume: bool,
    available: &indexmap::IndexMap<String, crate::agent::config::ModelEntry>,
    is_session_auth: bool,
) -> Option<String> {
    if provenance != ModelOverrideProvenance::Tool || is_resume {
        return None;
    }
    let requested = requested?;
    crate::agent::models::task_model_error_for_catalog(
        requested,
        available,
        is_session_auth,
    )
}
/// This is a free async function, NOT a method on MvpAgent. It receives
/// a `SubagentSpawnContext` with everything it needs, and a mutable
/// reference to the coordinator for tracking.
///
/// Returns when the child session completes (or fails/cancels).
#[tracing::instrument(
    name = "subagent.handle_request",
    skip_all,
    fields(
        subagent_id = %request.id,
        parent_session_id = %ctx.parent_session_id,
        subagent_type = %request.subagent_type,
    )
)]
pub(crate) async fn handle_subagent_request(
    mut request: SubagentRequest,
    mut ctx: SubagentSpawnContext,
    coordinator: &std::cell::RefCell<SubagentCoordinator>,
    gateway: &GatewaySender,
) {
    let start = std::time::Instant::now();
    let mut parent_wait_guard = (!request.run_in_background)
        .then(|| crate::tools::tool_context::BlockingWaitGuard::enter(
            ctx.parent_blocking_wait_depth.clone(),
        ));
    let Some(mut definition) = resolve_agent_definition(&request.subagent_type, &ctx)
    else {
        let msg = format!("Unknown subagent type: {}", request.subagent_type);
        send_pre_spawn_failure(request, &msg, coordinator, &ctx, gateway);
        return;
    };
    match gate_subagent_type(&request.subagent_type, &ctx) {
        SubagentValidateTypeOutcome::Disabled => {
            let msg = format!(
                "Subagent '{}' is disabled via [subagents.toggle] in config.toml",
                request.subagent_type
            );
            send_pre_spawn_failure(request, &msg, coordinator, &ctx, gateway);
            return;
        }
        SubagentValidateTypeOutcome::NotAllowed { allowed } => {
            let msg = format!(
                "agent can only spawn: {}; '{}' not allowed", allowed.join(", "), request
                .subagent_type
            );
            send_pre_spawn_failure(request, &msg, coordinator, &ctx, gateway);
            return;
        }
        _ => {}
    }
    let run_in_background = request.run_in_background
        || definition.background.unwrap_or(false);
    let cancel_token = CancellationToken::new();
    coordinator
        .borrow_mut()
        .insert_pending(PendingSubagent {
            subagent_id: request.id.clone(),
            subagent_type: request.subagent_type.clone(),
            description: request.description.clone(),
            persona: request.runtime_overrides.persona.clone(),
            parent_prompt_id: request.parent_prompt_id.clone(),
            parent_session_id: ctx.parent_session_id.clone(),
            started_at: start,
            run_in_background,
            surface_completion: request.surface_completion,
            color: definition.color,
            cancel_token: cancel_token.clone(),
        });
    let mut pending_guard = PendingGuard {
        coordinator,
        id: request.id.clone(),
        defused: false,
        error: None,
    };
    resolve_subagent_toolset(
        &request.subagent_type,
        request.runtime_overrides.harness_agent_type.as_deref(),
        &ctx,
        &mut definition,
    );
    let (role, role_key) = {
        let by_type = ctx.subagent_roles.get(&request.subagent_type);
        if by_type.is_some() {
            (by_type, Some(request.subagent_type.clone()))
        } else {
            let by_persona = request
                .runtime_overrides
                .persona
                .as_deref()
                .and_then(|p| ctx.subagent_roles.get(p));
            let key = if by_persona.is_some() {
                request.runtime_overrides.persona.clone()
            } else {
                None
            };
            (by_persona, key)
        }
    };
    let cwd = ctx.parent_session_info.as_ref().map(|i| std::path::Path::new(&i.cwd));
    let effective_runtime = resolve_effective_overrides(
        &request.runtime_overrides,
        role,
        &ctx.subagent_personas,
        cwd,
        role_key,
    );
    let mut effective_runtime = effective_runtime;
    if effective_runtime.reasoning_effort.is_none() {
        effective_runtime.reasoning_effort = definition
            .effort
            .map(|e| <&str>::from(e).to_string());
    }
    {
        use kigi_tool_types::SubagentIsolationMode;
        if effective_runtime.isolation == SubagentIsolationMode::None
            && definition.isolation
                == Some(kigi_agent::config::IsolationMode::Worktree)
        {
            effective_runtime.isolation = SubagentIsolationMode::Worktree;
        }
    }
    let prompt = request.prompt.clone();
    if let Some(ref err) = effective_runtime.persona_error {
        tracing::error!(
            subagent_id = % request.id, error = err,
            "Persona resolution failed, aborting subagent spawn"
        );
        pending_guard.set_error(err.clone());
        send_failure(request, err);
        return;
    }
    if let Some(ref warn) = effective_runtime.role_prompt_warning {
        tracing::warn!(
            subagent_id = % request.id, warning = warn,
            "Role prompt_file degraded, continuing without role prompt"
        );
    }
    let resume_source = if let Some(resume_id) = request
        .resume_from
        .as_deref()
        .filter(|s| is_valid_resume_id(s))
    {
        let coord = coordinator.borrow();
        if coord.is_active(resume_id) {
            let msg = format!(
                "Cannot resume from subagent '{resume_id}': it is still running. \
                 Wait for it to complete before resuming."
            );
            drop(coord);
            send_failure(request, &msg);
            return;
        }
        match coord
            .resumable_source_for(resume_id, &ctx.parent_session_id, &ctx.parent_cwd)
        {
            Some(info) => {
                drop(coord);
                Some(info)
            }
            None => {
                let msg = format!(
                    "Cannot resume from subagent '{resume_id}': not found. \
                     The subagent may have been evicted or the ID is invalid."
                );
                drop(coord);
                send_failure(request, &msg);
                return;
            }
        }
    } else {
        None
    };
    if let Some(ref source) = resume_source {
        if request.runtime_overrides.model.is_some() {
            tracing::debug!(
                subagent_id = % request.id,
                "Ignoring caller model override on resume; source model will be pinned"
            );
        }
        effective_runtime.model = None;
        if let Err(e) = kigi_subagent_resolution::validate_resume_identity(
            &request.subagent_type,
            request.runtime_overrides.persona.as_deref(),
            source,
        ) {
            send_failure(request, &e.to_string());
            return;
        }
    }
    if let Some(error) = task_model_override_error(
        request.runtime_overrides.model.as_deref(),
        request.runtime_overrides.model_override_provenance,
        resume_source.is_some(),
        &ctx.available_models,
        ctx.auth_manager.current_or_expired().is_some_and(|a| a.is_session_auth()),
    ) {
        pending_guard.set_error(error.clone());
        send_failure(request, &error);
        return;
    }
    let worktree_path = if let Some(ref source) = resume_source {
        if effective_runtime.isolation != kigi_tool_types::SubagentIsolationMode::None
            && source.worktree_path.is_none()
        {
            tracing::info!(
                subagent_id = % request.id,
                "Ignoring isolation=worktree override: resumed source had no worktree"
            );
        }
        match source.worktree_path.as_deref() {
            None => None,
            Some(dest) => {
                match resume_worktree_action(
                    dest.is_dir(),
                    source.snapshot_ref.as_deref(),
                ) {
                    ResumeWorktreeAction::Reuse => Some(dest.to_path_buf()),
                    ResumeWorktreeAction::Rehydrate => {
                        let snapshot_ref = source
                            .snapshot_ref
                            .clone()
                            .unwrap_or_default();
                        let source_repo = resolve_subagent_source_repo(&ctx);
                        match crate::session::worktree::rehydrate_subagent_worktree(
                                dest,
                                &source_repo,
                                &snapshot_ref,
                                Some(source.subagent_id.as_str()),
                            )
                            .await
                        {
                            Ok(path) => {
                                tracing::info!(
                                    subagent_id = % request.id, worktree_path = % path
                                    .display(), snapshot_ref = % snapshot_ref,
                                    "Rehydrated subagent worktree from snapshot for resume"
                                );
                                Some(path)
                            }
                            Err(e) => {
                                tracing::warn!(
                                    subagent_id = % request.id, error = % e,
                                    "Failed to rehydrate subagent worktree, falling back to shared workspace"
                                );
                                None
                            }
                        }
                    }
                    ResumeWorktreeAction::Shared => {
                        tracing::warn!(
                            subagent_id = % request.id, worktree = % dest.display(),
                            "Resumed subagent worktree dir missing with no snapshot; using shared workspace"
                        );
                        None
                    }
                }
            }
        }
    } else if effective_runtime.isolation != kigi_tool_types::SubagentIsolationMode::None
    {
        let source_cwd = parent_source_cwd(&ctx);
        let dest = match crate::session::worktree::worktree_base_dir_for_source(
            &source_cwd,
        ) {
            Ok(base) => base.join(format!("subagent-{}", request.id)),
            Err(e) => {
                tracing::warn!(
                    subagent_id = % request.id, error = % e,
                    "Could not resolve worktree base dir, using temp dir for subagent worktree"
                );
                std::env::temp_dir().join("kigi-subagent-worktrees").join(&request.id)
            }
        };
        let source_clone = source_cwd;
        let subagent_id = request.id.clone();
        let creation_mode: kigi_fast_worktree::CreationMode = ctx.worktree_type.into();
        let btrfs_delegate = crate::session::worktree::btrfs_delegate_from_env();
        match tokio::task::spawn_blocking(move || {
                let mut builder = kigi_fast_worktree::WorktreeBuilder::new(
                        &source_clone,
                        &dest,
                    )
                    .working_tree_mode(
                        kigi_fast_worktree::WorkingTreeMode::PreserveWorkingTree,
                    )
                    .creation_mode(creation_mode)
                    .worktree_kind(kigi_fast_worktree::WorktreeKind::Subagent)
                    .session_id(subagent_id);
                if let Some(delegate) = btrfs_delegate {
                    builder = builder.btrfs_delegate(delegate);
                }
                builder.create()
            })
            .await
        {
            Ok(Ok(report)) => {
                tracing::info!(
                    subagent_id = % request.id, worktree_path = % report.worktree_path
                    .display(), commit = % report.commit,
                    "Created isolated worktree for subagent"
                );
                Some(report.worktree_path)
            }
            Ok(Err(e)) => {
                tracing::warn!(
                    subagent_id = % request.id, error = % e,
                    "Failed to create worktree, falling back to shared workspace"
                );
                None
            }
            Err(e) => {
                tracing::warn!(
                    subagent_id = % request.id, error = % e,
                    "Worktree creation task panicked, falling back to shared workspace"
                );
                None
            }
        }
    } else {
        None
    };
    let worktree_freshly_created = resume_source.is_none() && worktree_path.is_some();
    if let Some(raw_cwd) = request.cwd.as_deref() {
        match sanitize_cwd_value(raw_cwd) {
            Some(cwd_path) => {
                if worktree_path.is_none() && resume_source.is_none() {
                    let p = Path::new(&cwd_path);
                    if !p.is_dir() {
                        let msg = if p.exists() {
                            format!("cwd \"{cwd_path}\" exists but is not a directory")
                        } else {
                            format!("cwd \"{cwd_path}\" does not exist")
                        };
                        send_failure(request, &msg);
                        return;
                    }
                }
                request.cwd = Some(cwd_path);
            }
            None => request.cwd = None,
        }
    }
    if effective_runtime.reasoning_effort.is_some()
        || effective_runtime.capability_mode.is_some()
    {
        tracing::info!(
            subagent_id = % request.id, reasoning_effort = ? effective_runtime
            .reasoning_effort, capability_mode = ? effective_runtime.capability_mode,
            "Resolved runtime overrides for subagent"
        );
    }
    if let Some(mode) = effective_runtime.capability_mode {
        mode.filter_tool_config(&mut definition.tool_config);
        tracing::info!(
            subagent_id = % request.id, capability_mode = ? mode, tools_remaining =
            definition.tool_config.tools.len(),
            "Applied capability mode filter to agent tool config"
        );
    }
    {
        use kigi_tools::implementations::kigi::task::MAX_SUBAGENT_DEPTH;
        use kigi_tools::types::tool::ToolKind;
        let child_depth = ctx.parent_depth + 1;
        if child_depth >= MAX_SUBAGENT_DEPTH {
            let before = definition.tool_config.tools.len();
            definition.tool_config.tools.retain(|tc| tc.kind != Some(ToolKind::Task));
            if definition.tool_config.tools.len() < before {
                tracing::info!(
                    subagent_id = % request.id, child_depth, max_depth =
                    MAX_SUBAGENT_DEPTH, "Stripped task tool from child at max depth"
                );
            }
            prune_orphaned_background_task_tools(&mut definition.tool_config);
        }
    }
    if request.fork_context {
        effective_runtime.model = Some(ctx.model_id.0.to_string());
    }
    let (mut effective_sampling_config, mut effective_model_id) = resolve_effective_model_config(
            effective_runtime.model.as_deref(),
            &request.subagent_type,
            &definition.model,
            &ctx,
        )
        .await;
    let subagent_max_turns = resolve_subagent_max_turns(
        definition.max_turns,
        ctx.parent_max_turns,
    );
    {
        let model_str = &effective_sampling_config.model;
        let model_unknown = !model_str.is_empty() && !ctx.available_models.is_empty()
            && !ctx.available_models.contains_key(model_str)
            && !ctx.available_models.values().any(|e| e.info().model == *model_str);
        if model_unknown {
            let (parent_config, parent_mid) = read_parent_sampling_config(&ctx).await;
            tracing::warn!(
                subagent_id = % request.id, resolved_model = % model_str, parent_model =
                % parent_config.model,
                "Resolved subagent model not found in available models — \
                 falling back to parent model"
            );
            effective_sampling_config = parent_config;
            effective_model_id = parent_mid;
        }
    }
    if let Some(ref source) = resume_source
        && let Some(ref source_model) = source.model_id
        && effective_model_id.0.as_ref() != source_model.as_str()
    {
        if let Some(resolved) = resolve_model_override_to_config(source_model, &ctx) {
            tracing::info!(
                subagent_id = % request.id, resolved_model = % effective_model_id.0,
                source_model = source_model, "Pinning resumed child to source model"
            );
            effective_sampling_config = resolved.0;
            effective_model_id = resolved.1;
        } else {
            let msg = format!(
                "Cannot resume from subagent '{}': source model '{source_model}' \
                 is no longer available in the model catalogue.",
                source.subagent_id,
            );
            send_failure(request, &msg);
            return;
        }
    }
    if let Some(raw) = effective_runtime.reasoning_effort.as_deref()
        && ctx
            .models_manager
            .model_supports_reasoning_effort(effective_model_id.0.as_ref())
    {
        use kigi_sampling_types::ReasoningEffort;
        match raw.parse::<ReasoningEffort>() {
            Ok(eff) => effective_sampling_config.reasoning_effort = Some(eff),
            Err(err) => {
                tracing::warn!(
                    value = raw, error = % err,
                    "subagent reasoning_effort: parse failed, ignoring override"
                )
            }
        }
    }
    let subagent_id = request.id.clone();
    let child_session_id = acp::SessionId::new(subagent_id.clone());
    let override_cwd = select_override_cwd(
        resume_source.as_ref(),
        request.cwd.as_deref(),
    );
    let effective_cwd = resolve_child_cwd(
            worktree_path.as_deref(),
            override_cwd,
            &ctx.parent_cwd,
        )
        .to_string_lossy()
        .into_owned();
    let child_session_info = SessionInfo {
        id: child_session_id.clone(),
        cwd: effective_cwd,
    };
    let child_session_dir = session::persistence::session_dir(&child_session_info);
    let parent_session_dir = session::persistence::session_dir(
        &SessionInfo {
            id: acp::SessionId::new(ctx.parent_session_id.clone()),
            cwd: ctx.parent_cwd.to_string_lossy().to_string(),
        },
    );
    let subagent_meta_dir = parent_session_dir.join("subagents").join(&subagent_id);
    let InitialContext {
        source: context_source,
        copy_error: fork_copy_error,
        prefix_len: inherited_prefix_len,
        conversation: forked_conversation,
        verbatim_fork: context_verbatim_fork,
    } = match bootstrap_initial_context(
            &request,
            resume_source.as_ref(),
            &ctx,
            &child_session_info,
            &child_session_dir,
            effective_model_id.0.as_ref(),
            effective_sampling_config.context_window,
        )
        .await
    {
        BootstrapInitialContext::Ready(ctx) => ctx,
        BootstrapInitialContext::ResumeAbort(msg) => {
            tracing::error!(
                subagent_id = % request.id, error = % msg,
                "Resume-copy failed, aborting subagent spawn"
            );
            send_failure(request, &msg);
            return;
        }
    };
    let verbatim_mirror_fork = context_source == InitialContextSource::Forked
        && context_verbatim_fork;
    let task_prompt_text = prompt.clone();
    let (mut forked_conversation, mut inherited_prefix_len) = (
        forked_conversation,
        inherited_prefix_len.unwrap_or(0),
    );
    if crate::session::is_cursor_user_template(&definition.user_message_template)
        && context_source != InitialContextSource::Resumed && !verbatim_mirror_fork
    {} else if context_source != InitialContextSource::Resumed && !verbatim_mirror_fork
        && let Some(ref pi) = effective_runtime.persona_instructions {
            let reminder = kigi_sampling_types::conversation::ConversationItem::system_reminder(
                format!("<system-reminder>\n{pi}\n</system-reminder>"),
            );
            let insert_at = inherited_prefix_len.min(forked_conversation.len());
            forked_conversation.insert(insert_at, reminder);
            inherited_prefix_len += 1;
        }
    let effective_source_str = match &context_source {
        InitialContextSource::New => "new",
        InitialContextSource::Forked => "forked",
        InitialContextSource::Resumed => "resumed",
    };
    let subagent_meta = SubagentMeta {
        subagent_id: subagent_id.clone(),
        parent_session_id: ctx.parent_session_id.clone(),
        child_session_id: child_session_id.0.to_string(),
        subagent_type: request.subagent_type.clone(),
        description: request.description.clone(),
        prompt: request.prompt.clone(),
        status: "running".to_string(),
        started_at: chrono::Utc::now(),
        completed_at: None,
        duration_ms: None,
        tool_calls: None,
        turns: None,
        error: None,
        effective_context_source: Some(effective_source_str.to_string()),
        context_normalized: fork_context_normalized(
            &context_source,
            context_verbatim_fork,
        ),
        fork_copy_error: fork_copy_error.clone(),
        persona: effective_runtime.persona.clone(),
        resumed_from: request.resume_from.clone(),
        child_cwd: Some(child_session_info.cwd.clone()),
        worktree_path: worktree_path.as_ref().map(|p| p.to_string_lossy().to_string()),
        snapshot_ref: None,
        effective_model_id: Some(effective_model_id.0.to_string()),
    };
    write_subagent_meta(&subagent_meta_dir, &subagent_meta);
    emit_subagent_notification(
        gateway,
        &ctx.parent_session_id,
        SessionUpdate::SubagentSpawned {
            subagent_id: subagent_id.clone(),
            child_session_id: child_session_id.0.to_string(),
            parent_session_id: ctx.parent_session_id.clone(),
            parent_prompt_id: request.parent_prompt_id.clone(),
            subagent_type: request.subagent_type.clone(),
            description: request.description.clone(),
            effective_context_source: Some(effective_source_str.to_string()),
            context_normalized: fork_context_normalized(
                &context_source,
                context_verbatim_fork,
            ),
            capability_mode: effective_runtime
                .capability_mode
                .and_then(|m| serde_json::to_value(m).ok())
                .and_then(|v| v.as_str().map(String::from)),
            persona: effective_runtime.persona.clone(),
            role: effective_runtime.role_name.clone(),
            model: Some(effective_model_id.0.to_string()),
            resumed_from: request.resume_from.clone(),
        },
        ctx.parent_cmd_tx.as_ref(),
    );
    let sampling_client = match crate::sampling::Client::new(
        effective_sampling_config.clone(),
    ) {
        Ok(c) => c,
        Err(e) => {
            let msg = format!("Sampling client error: {e}");
            pending_guard.set_error(msg.clone());
            fail_subagent(
                request,
                &msg,
                &subagent_id,
                &child_session_id,
                &subagent_meta_dir,
                gateway,
                &ctx.parent_session_id,
                ctx.parent_cmd_tx.as_ref(),
                0,
            );
            return;
        }
    };
    let persistence = match session::persistence::new_with_explicit_dir(
            &child_session_info,
            child_session_dir.clone(),
            effective_model_id.clone(),
            sampling_client,
            effective_sampling_config.model.clone(),
        )
        .await
    {
        Ok(p) => p,
        Err(e) => {
            let msg = format!("Persistence error: {e}");
            pending_guard.set_error(msg.clone());
            fail_subagent(
                request,
                &msg,
                &subagent_id,
                &child_session_id,
                &subagent_meta_dir,
                gateway,
                &ctx.parent_session_id,
                ctx.parent_cmd_tx.as_ref(),
                0,
            );
            return;
        }
    };
    let child_cwd = resolve_child_cwd(
        worktree_path.as_deref(),
        override_cwd,
        &ctx.parent_cwd,
    );
    let cwd_outside_parent = match (
        dunce::canonicalize(&child_cwd),
        dunce::canonicalize(&ctx.parent_cwd),
    ) {
        (Ok(child), Ok(parent)) => !child.starts_with(&parent),
        _ => child_cwd != ctx.parent_cwd,
    };
    let subagent_fs_watch = FsWatchCapabilities {
        hunk_tracking: ctx.hunk_tracking_enabled && cwd_outside_parent,
        ..FsWatchCapabilities::none()
    };
    let child_cwd_abs = kigi_paths::AbsPathBuf::new(child_cwd)
        .unwrap_or_else(|_| {
            kigi_paths::AbsPathBuf::new(std::env::current_dir().unwrap_or_default())
                .expect("current_dir should be absolute")
        });
    let mut tool_ctx = ToolContext::with_preloaded_env(
            child_cwd_abs,
            Some(gateway.clone()),
            Some(child_session_id.clone()),
            ctx.fs.clone(),
            ctx.terminal.clone(),
            ctx.hunk_tracker_handle.clone(),
            (*ctx.session_env).clone(),
        )
        .with_hunk_tracking_enabled(ctx.hunk_tracking_enabled);
    tool_ctx.subagent_event_tx = Some(ctx.subagent_event_tx.clone());
    tool_ctx.monitor_event_buffer = Some(MonitorEventBuffer::default());
    tool_ctx.subagent_depth = ctx.parent_depth + 1;
    tool_ctx.lsp = ctx.lsp.clone();
    let parent_traceparent = kigi_file_utils::trace_context::current_traceparent();
    let tracker_child_cwd = child_session_info.cwd.clone();
    let tracker_model_id = effective_model_id.0.to_string();
    let initial_child_tokens = kigi_chat_state::estimate_conversation_tokens(
        &forked_conversation,
    );
    let model_entry = crate::agent::config::find_model_by_id(
        &ctx.available_models,
        effective_model_id.0.as_ref(),
    );
    let model_has_own_creds = model_entry
        .is_some_and(|entry| entry.has_own_credentials());
    let inherited_auth_type = subagent_auth_type(model_entry, &ctx.auth_method_id);
    let credentials = kigi_chat_state::Credentials {
        api_key: effective_sampling_config.api_key.clone(),
        auth_type: inherited_auth_type,
        alpha_test_key: ctx.alpha_test_key.clone(),
    };
    kigi_log::unified_log::info(
        "subagent spawn credentials",
        None,
        Some(
            serde_json::json!(
                { "subagent_id" : & request.id, "subagent_type" : & request
                .subagent_type, "effective_model" : effective_model_id.0.as_ref(),
                "effective_model_raw" : & effective_sampling_config.model, "base_url" : &
                effective_sampling_config.base_url, "key_prefix" : key_prefix(&
                effective_sampling_config.api_key), "auth_type" : format!("{:?}",
                inherited_auth_type), "model_has_own_creds" : model_has_own_creds,
                "auth_method_id" : ctx.auth_method_id.0.as_ref(), "parent_model" : ctx
                .model_id.0.as_ref(), "parent_key_prefix" : key_prefix(& ctx
                .sampling_config.api_key), "context_window" : effective_sampling_config
                .context_window, }
            ),
        ),
    );
    let attribution_callback: Option<kigi_sampler::SharedAttributionCallback> = effective_sampling_config
        .attribution_callback
        .clone();
    let tracker_color = definition.color;
    let agent_memory_scope = definition.memory;
    let agent_name_for_memory = definition.name.clone();
    let is_plugin_agent = definition.plugin_name.is_some();
    let yolo_policy_block = kigi_workspace::permission::resolution::yolo_disabled_by_policy();
    let agent_permission_mode = resolve_subagent_permission_mode(
        definition.permission_mode.clone(),
        is_plugin_agent,
        yolo_policy_block,
    );
    if agent_permission_mode != definition.permission_mode {
        if is_plugin_agent {
            tracing::warn!(
                agent = % definition.name, plugin = ? definition.plugin_name,
                "ignoring permissionMode on plugin agent (not supported for security)"
            );
        } else {
            tracing::warn!(
                agent = % definition.name,
                "ignoring subagent permissionMode=bypassPermissions: always-approve disabled by managed policy"
            );
        }
    }
    if let Some(scope) = agent_memory_scope {
        use kigi_tools::implementations::kigi;
        use kigi_tools::implementations::opencode;
        let memory_tools: Vec<kigi_tools::registry::types::ToolConfig> = vec![
            (& kigi::ReadFileTool).into(), (& kigi::SearchReplaceTool)
            .into(), (& opencode::OpenCodeWriteTool).into(),
        ];
        for tc in memory_tools {
            if !definition.tool_config.tools.iter().any(|t| t.id == tc.id) {
                definition.tool_config.tools.push(tc);
            }
        }
        let resolved_mem = scope.resolve_dir(&agent_name_for_memory, &ctx.parent_cwd);
        let memory_dir = &resolved_mem.path;
        let memory_md = memory_dir.join("MEMORY.md");
        if memory_md.is_file() && let Ok(content) = std::fs::read_to_string(&memory_md) {
            const MAX_LINES: usize = 200;
            const MAX_BYTES: usize = 25 * 1024;
            let truncated: String = content
                .lines()
                .take(MAX_LINES)
                .collect::<Vec<_>>()
                .join("\n");
            let truncated = kigi_tools::util::truncate::truncate_str(
                    &truncated,
                    MAX_BYTES,
                )
                .to_string();
            if !truncated.is_empty() {
                let injection = format!(
                    "\n\n<agent-memory>\nMemory directory: {}\n\n{truncated}\n</agent-memory>",
                    memory_dir.display()
                );
                definition.prompt_body = Some(
                    definition.prompt_body.unwrap_or_default() + &injection,
                );
            }
        }
    }
    let is_plugin_agent = definition.plugin_name.is_some();
    if let Some(ref hooks_config) = definition.hooks {
        if is_plugin_agent {
            tracing::warn!(
                agent = % definition.name, plugin = ? definition.plugin_name,
                "ignoring hooks on plugin agent (not supported for security)"
            );
        } else if !crate::agent::folder_trust::agent_inline_hooks_allowed(
            definition.scope,
            || crate::agent::folder_trust::project_scope_allowed(&ctx.parent_cwd),
        ) {
            tracing::warn!(
                agent = % definition.name,
                "ignoring hooks on untrusted project agent (folder not trusted; re-run with --trust)"
            );
        } else {
            let hooks_val = hooks_config.as_value();
            let (specs, errors) = kigi_hooks::config::parse_hooks_from_value_with_dir(
                &hooks_val,
                &format!("agent:{}", definition.name),
                &ctx.parent_cwd,
            );
            for e in &errors {
                tracing::warn!(
                    agent = % definition.name, error = ? e, "agent hook parse error"
                );
            }
            if !specs.is_empty() {
                let specs: Vec<_> = specs
                    .into_iter()
                    .map(|mut s| {
                        if s.event == kigi_hooks::event::HookEventName::Stop {
                            s.event = kigi_hooks::event::HookEventName::SubagentStop;
                        }
                        s
                    })
                    .collect();
                let mut registry = ctx
                    .hook_registry
                    .as_ref()
                    .map(|r| (**r).clone())
                    .unwrap_or_default();
                registry.append_specs(specs);
                ctx.hook_registry = Some(std::sync::Arc::new(registry));
            }
        }
    }
    let agent_mcp_servers: Vec<_> = if is_plugin_agent {
        if !definition.mcp_servers.is_empty() {
            tracing::warn!(
                agent = % definition.name, plugin = ? definition.plugin_name,
                "ignoring mcpServers on plugin agent (not supported for security)"
            );
        }
        vec![]
    } else {
        definition
                .mcp_servers
                .iter()
                .filter_map(|entry| match entry {
                    kigi_agent::config::McpServerRef::Named(name) => {
                        ctx.parent_mcp_configs
                            .iter()
                            .find(|s| {
                                crate::session::mcp_servers::mcp_server_name(s) == name
                            })
                            .cloned()
                            .or_else(|| {
                                tracing::warn!(
                                    agent = % definition.name, server = name,
                                    "mcpServers: named ref not found in parent"
                                );
                                None
                            })
                    }
                    kigi_agent::config::McpServerRef::Inline { name, config } => {
                        if let serde_json::Value::Object(obj) = config
                            && obj.contains_key("type")
                        {
                            let mut flat = obj.clone();
                            flat.insert(
                                "name".to_string(),
                                serde_json::Value::String(name.clone()),
                            );
                            if let Ok(server) = serde_json::from_value::<
                                agent_client_protocol::McpServer,
                            >(serde_json::Value::Object(flat)) {
                                return Some(server);
                            }
                            tracing::debug!(
                                agent = % definition.name, server = name,
                                "ACP wire format parse failed, trying map-keyed"
                            );
                        }
                        if let Some(inner_obj) = config.as_object() {
                            let mut flat = inner_obj.clone();
                            flat.insert(
                                "name".to_string(),
                                serde_json::Value::String(name.clone()),
                            );
                            if let Ok(server) = serde_json::from_value::<
                                agent_client_protocol::McpServer,
                            >(serde_json::Value::Object(flat)) {
                                return Some(server);
                            }
                        }
                        tracing::warn!(
                            agent = % definition.name, server = name,
                            "mcpServers: inline config could not be parsed"
                        );
                        None
                    }
                })
                .collect()
    };
    let parent_mcp_pool = if is_plugin_agent {
        if ctx.parent_mcp_pool.is_some() {
            tracing::debug!(
                agent = % definition.name,
                "skipping MCP pool inheritance for plugin agent"
            );
        }
        None
    } else {
        ctx.parent_mcp_pool
                .take()
                .and_then(|pool| filter_pool_by_inheritance(
                    pool,
                    &definition.mcp_inheritance,
                ))
    };
    let mcp_inherited_count = parent_mcp_pool
        .as_ref()
        .map(|p| p.len() as u32)
        .unwrap_or(0);
    if mcp_inherited_count > 0 {
        tracing::info!(
            subagent_id = % request.id, mcp_count = mcp_inherited_count,
            "Subagent inherited MCP servers from parent pool"
        );
    }
    let inherit_skills = definition.inherit_skills;
    if inherit_skills && ctx.parent_skills.is_none() {
        let parent_cwd_str = ctx.parent_cwd.to_string_lossy().to_string();
        ctx.parent_skills = Some(
            kigi_agent::prompt::skills::list_skills_with_plugins(
                    Some(&parent_cwd_str),
                    &ctx.parent_skills_config,
                    ctx.plugin_registry.as_deref(),
                    ctx.parent_compat,
                )
                .await,
        );
    }
    let skills_inherited_count = if inherit_skills {
        ctx.parent_skills.as_ref().map(|s| s.len() as u32).unwrap_or(0)
    } else {
        0
    };
    if skills_inherited_count > 0 {
        tracing::info!(
            subagent_id = % request.id, skills_count = skills_inherited_count,
            "Subagent inherited skills from parent"
        );
    }
    let mcp_owned_count = agent_mcp_servers.len() as u32;
    let subagent_session_default_agent_profile = Some(definition.name.clone());
    let subagent_model_id = effective_sampling_config.model.clone();
    let _ = persistence
        .tx
        .send(crate::session::persistence::PersistenceMsg::CurrentModel {
            model_id: effective_model_id.clone(),
            agent_name: Some(definition.name.clone()),
            reasoning_effort: Some(effective_sampling_config.reasoning_effort),
        });
    let forked_tool_override = if verbatim_mirror_fork {
        ctx.parent_tool_snapshot.clone()
    } else {
        None
    };
    let spawn_result = session::spawn_session_on_thread(
            child_session_info,
            gateway.clone(),
            effective_sampling_config,
            credentials,
            crate::agent::auth_method::new_shared_auth_method_id(
                Some(ctx.auth_method_id.clone()),
            ),
            Some(ctx.auth_manager.clone()),
            attribution_callback,
            tool_ctx,
            agent_mcp_servers,
            vec![],
            Default::default(),
            parent_mcp_pool,
            Vec::new(),
            true,
            None,
            persistence,
            forked_conversation,
            None,
            None,
            initial_child_tokens,
            crate::session::StartupHints {
                inherited_prefix_len: Some(inherited_prefix_len),
                is_subagent: true,
                parent_session_id: Some(ctx.parent_session_id.clone()),
                subagent_type: Some(request.subagent_type.clone()),
                preserve_inherited_system: verbatim_mirror_fork,
                ..Default::default()
            },
            kigi_workspace::permission::ClientType::Generic,
            ctx.resolve_auto_compact_threshold_percent(&subagent_model_id),
            kigi_agent::DEFAULT_SYSTEM_PROMPT_LABEL.to_string(),
            kigi_chat_state::CompactionMode::Summary,
            ctx.resolve_compaction_verbatim_input(),
            false,
            None,
            None,
            std::sync::Arc::new(
                parking_lot::Mutex::new(
                    kigi_workspace::file_system::CodebaseIndexManager::new(),
                ),
            ),
            false,
            subagent_fs_watch,
            None,
            false,
            false,
            std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true)),
            definition,
            subagent_session_default_agent_profile,
            if inherit_skills {
                ctx.parent_skills_config.clone()
            } else {
                kigi_agent::prompt::skills::SkillsConfig::default()
            },
            if inherit_skills { ctx.parent_skills.take() } else { None },
            ctx.parent_compat,
            false,
            None,
            None,
            None,
            None,
            None,
            if verbatim_mirror_fork {
                None
            } else if let Some(scope) = agent_memory_scope {
                ctx.memory_config
                    .as_ref()
                    .map(|mc| {
                        let mut c = mc.clone();
                        let resolved = scope
                            .resolve_dir(&agent_name_for_memory, &ctx.parent_cwd);
                        c.enabled = true;
                        c.root_dir_override = Some(resolved.path);
                        c.flat_memory_root = resolved.is_project_scoped;
                        c
                    })
            } else {
                ctx.memory_config.clone()
            },
            Default::default(),
            effective_model_id,
            ctx.yolo_mode
                || matches!(
                    agent_permission_mode,
                    kigi_agent::config::PermissionMode::BypassPermissions
                ),
            false,
            None,
            ctx.inference_idle_timeout_secs,
            None,
            ctx.web_search_config.clone(),
            ctx.web_fetch_config.clone(),
            ctx.app_builder_deployer_config.clone(),
            ctx.write_file_enabled,
            ctx.goal_enabled,
            // Graph mode is a depth-0 harness; child sessions never drive it.
            false,
            true,
            ctx.ask_user_question_enabled,
            ctx.client_hooks.clone(),
            None,
            std::collections::HashMap::new(),
            ctx.persona_io_summaries.clone(),
            kigi_agent::prompt::context::PromptAudience::Subagent,
            effective_runtime.role_prompt.clone(),
            None,
            ctx.disable_web_search,
            ctx.backend_tools_enabled,
            ctx.respect_gitignore,
            ctx.path_not_found_hints,
            ctx.resolve_tool_params_json(),
            ctx.plugin_registry.clone(),
            None,
            ctx.models_manager.clone(),
            parent_traceparent,
            ctx.permission_handle.clone(),
            ctx.api_key_provider.clone(),
            ctx.image_description_model.clone(),
            ctx.hook_registry.clone(),
            ctx.workspace_ops.clone(),
            vec![],
            ctx.todo_gate,
            std::mem::take(&mut ctx.remote_settings),
            std::mem::take(&mut ctx.laziness_debug_log),
            ctx.parent_terminal_backend.clone(),
            ctx.parent_scheduler_handle.clone(),
            subagent_max_turns,
            forked_tool_override,
        )
        .await;
    let (child_handle, _system_prompt, child_thread) = match spawn_result {
        Ok(r) => r,
        Err(e) => {
            let msg = format!("Failed to spawn child session: {e}");
            pending_guard.set_error(msg.clone());
            fail_subagent(
                request,
                &msg,
                &subagent_id,
                &child_session_id,
                &subagent_meta_dir,
                gateway,
                &ctx.parent_session_id,
                ctx.parent_cmd_tx.as_ref(),
                start.elapsed().as_millis() as u64,
            );
            return;
        }
    };
    if cancel_token.is_cancelled() {
        pending_guard.defuse();
        cancel_pending_subagent_at_promote(
                request,
                &child_handle,
                &subagent_id,
                &child_session_id,
                &subagent_meta_dir,
                coordinator,
                gateway,
                &ctx.parent_session_id,
                ctx.parent_cmd_tx.as_ref(),
                worktree_path.as_deref(),
                worktree_freshly_created,
                start.elapsed().as_millis() as u64,
            )
            .await;
        return;
    }
    pending_guard.defuse();
    coordinator
        .borrow_mut()
        .insert(SubagentTracker {
            subagent_id: request.id.clone(),
            parent_session_id: ctx.parent_session_id.clone(),
            parent_prompt_id: request.parent_prompt_id.clone(),
            child_session_id: child_session_id.clone(),
            subagent_type: request.subagent_type.clone(),
            persona: effective_runtime.persona.clone(),
            description: request.description.clone(),
            started_at: start,
            child_handle: child_handle.clone(),
            child_thread,
            cancel_token: cancel_token.clone(),
            resumed_from: request.resume_from.clone(),
            child_cwd: tracker_child_cwd,
            worktree_path: worktree_path.clone(),
            effective_model_id: tracker_model_id,
            run_in_background,
            surface_completion: request.surface_completion,
            color: tracker_color,
            block_waited: false,
            explicitly_killed: false,
        });
    spawn_progress_publisher(
        child_handle.signals_handle.clone(),
        gateway.clone(),
        ctx.parent_session_id.clone(),
        request.id.clone(),
        child_session_id.0.to_string(),
        start,
        cancel_token.clone(),
        goal_tick_cmd_tx(ctx.goal_enabled, ctx.parent_cmd_tx.as_ref()),
    );
    let (prompt_tx, prompt_rx) = oneshot::channel();
    let prompt_text = task_prompt_text;
    let child_prompt_id = uuid::Uuid::now_v7().to_string();
    let _ = child_handle
        .cmd_tx
        .send(SessionCommand::Prompt {
            prompt_id: child_prompt_id.clone(),
            prompt_blocks: vec![
                acp::ContentBlock::Text(acp::TextContent::new(prompt_text))
            ],
            prompt_mode: crate::session::plan_mode::PromptMode::Agent,
            client_identifier: None,
            screen_mode: None,
            verbatim: true,
            traceparent: kigi_file_utils::trace_context::current_traceparent(),
            json_schema: None,
            send_now: false,
            respond_to: prompt_tx,
            persist_ack: None,
        });
    let mut result_tx = {
        let (dummy_tx, _) = oneshot::channel();
        Some(std::mem::replace(&mut request.result_tx, dummy_tx))
    };
    let wait_outcome = {
        let fut = await_subagent_turn_or_cancellation(prompt_rx, cancel_token.clone());
        tokio::pin!(fut);
        if !request.run_in_background {
            /// How the bounded foreground wait ended.
            enum ForegroundWait {
                /// The child finished (or was cancelled) within the budget.
                Done(SubagentWaitOutcome),
                /// The spawning tool's `result_rx` was dropped — parent turn died mid-await.
                ParentGone,
                /// `subagent_await_budget()` expired.
                Budget,
            }
            let first = {
                let parent_await_dropped = async {
                    match result_tx.as_mut() {
                        Some(tx) => tx.closed().await,
                        None => std::future::pending::<()>().await,
                    }
                };
                tokio::select! {
                    biased; outcome = & mut fut => ForegroundWait::Done(outcome), _ =
                    parent_await_dropped => ForegroundWait::ParentGone, _ =
                    tokio::time::sleep(subagent_await_budget()) =>
                    ForegroundWait::Budget,
                }
            };
            match first {
                ForegroundWait::Done(outcome) => {
                    if matches!(outcome, SubagentWaitOutcome::Cancelled) {
                        parent_wait_guard.take();
                    }
                    outcome
                }
                ForegroundWait::ParentGone => {
                    parent_wait_guard.take();
                    tracing::info!(
                        subagent_id = % request.id,
                        "foreground subagent await abandoned by its parent turn; detaching child to background (child keeps running)",
                    );
                    if !cancel_token.is_cancelled() {
                        request.run_in_background = true;
                        coordinator.borrow_mut().mark_backgrounded(&request.id);
                    }
                    fut.await
                }
                ForegroundWait::Budget => {
                    tracing::info!(
                        subagent_id = % request.id, budget_ms = subagent_await_budget()
                        .as_millis() as u64,
                        "foreground subagent exceeded await budget; auto-backgrounding (child keeps running)",
                    );
                    if let Some(tx) = result_tx.take() {
                        let _ = tx
                            .send(SubagentResult {
                                backgrounded: true,
                                subagent_id: request.id.clone(),
                                child_session_id: child_session_id.0.to_string(),
                                ..Default::default()
                            });
                    }
                    parent_wait_guard.take();
                    request.run_in_background = true;
                    coordinator.borrow_mut().mark_backgrounded(&request.id);
                    fut.await
                }
            }
        } else {
            fut.await
        }
    };
    let duration_ms = start.elapsed().as_millis() as u64;
    let mut result = match wait_outcome {
        SubagentWaitOutcome::Cancelled => {
            let (tool_calls, turns) = signals_snapshot_counts(&child_handle).await;
            SubagentResult {
                success: false,
                cancelled: true,
                error: Some("Subagent was cancelled".to_string()),
                subagent_id: request.id.clone(),
                child_session_id: child_session_id.0.to_string(),
                tool_calls,
                turns,
                duration_ms,
                worktree_path: worktree_path
                    .as_ref()
                    .map(|p| p.to_string_lossy().to_string()),
                ..Default::default()
            }
        }
        SubagentWaitOutcome::TurnResult(turn_result) => {
            let was_cancelled = cancel_token.is_cancelled();
            let (tool_calls, turns) = match &*turn_result {
                Ok(
                    Ok(
                        crate::session::commands::PromptTurnOk {
                            turn_snapshot: Some(snapshot),
                            ..
                        },
                    ),
                ) => (snapshot.current.tool_call_count, snapshot.current.turn_count),
                _ => signals_snapshot_counts(&child_handle).await,
            };
            let final_text = child_handle
                .chat_state_handle
                .get_last_assistant_text()
                .await
                .unwrap_or_default();
            let result_tokens = child_handle.chat_state_handle.get_total_tokens().await;
            match *turn_result {
                Ok(
                    Ok(
                        crate::session::commands::PromptTurnOk {
                            completion_kind: PromptCompletionKind::Cancelled {
                                category,
                                context,
                            },
                            ..
                        },
                    ),
                ) => {
                    let reason = cancellation_error_message(category, context.as_ref());
                    SubagentResult {
                        success: false,
                        cancelled: true,
                        error: Some(reason),
                        output: if final_text.is_empty() {
                            std::sync::Arc::from(
                                format!(
                                    "Subagent '{}' ({}) was cancelled. {} tool calls, {} turns.",
                                    request.description, request.subagent_type, tool_calls,
                                    turns
                                ),
                            )
                        } else {
                            std::sync::Arc::from(final_text)
                        },
                        subagent_id: request.id.clone(),
                        child_session_id: child_session_id.0.to_string(),
                        tool_calls,
                        turns,
                        duration_ms,
                        tokens_used: result_tokens,
                        worktree_path: worktree_path
                            .as_ref()
                            .map(|p| p.to_string_lossy().to_string()),
                        backgrounded: false,
                    }
                }
                Ok(
                    Ok(
                        crate::session::commands::PromptTurnOk {
                            completion_kind: PromptCompletionKind::MaxTurnsReached {
                                limit,
                            },
                            ..
                        },
                    ),
                ) => {
                    SubagentResult {
                        success: false,
                        cancelled: true,
                        error: Some(format!("max turns reached (limit: {limit})")),
                        output: if final_text.is_empty() {
                            std::sync::Arc::from(
                                format!(
                                    "Subagent '{}' ({}) hit max-turns limit ({limit}). {} tool calls, {} turns.",
                                    request.description, request.subagent_type, tool_calls,
                                    turns
                                ),
                            )
                        } else {
                            std::sync::Arc::from(final_text)
                        },
                        subagent_id: request.id.clone(),
                        child_session_id: child_session_id.0.to_string(),
                        tool_calls,
                        turns,
                        duration_ms,
                        tokens_used: result_tokens,
                        worktree_path: worktree_path
                            .as_ref()
                            .map(|p| p.to_string_lossy().to_string()),
                        backgrounded: false,
                    }
                }
                Ok(Ok(_)) => {
                    SubagentResult {
                        success: true,
                        output: if final_text.is_empty() {
                            std::sync::Arc::from(
                                format!(
                                    "Subagent '{}' ({}) completed successfully. {} tool calls, {} turns.",
                                    request.description, request.subagent_type, tool_calls,
                                    turns
                                ),
                            )
                        } else {
                            std::sync::Arc::from(final_text)
                        },
                        subagent_id: request.id.clone(),
                        child_session_id: child_session_id.0.to_string(),
                        tool_calls,
                        turns,
                        duration_ms,
                        tokens_used: result_tokens,
                        worktree_path: worktree_path
                            .as_ref()
                            .map(|p| p.to_string_lossy().to_string()),
                        ..Default::default()
                    }
                }
                Ok(Err(e)) => {
                    SubagentResult {
                        success: false,
                        cancelled: was_cancelled,
                        error: Some(
                            if was_cancelled {
                                "Subagent was cancelled".to_string()
                            } else {
                                format!("Session error: {e}")
                            },
                        ),
                        subagent_id: request.id.clone(),
                        child_session_id: child_session_id.0.to_string(),
                        tool_calls,
                        turns,
                        duration_ms,
                        worktree_path: worktree_path
                            .as_ref()
                            .map(|p| p.to_string_lossy().to_string()),
                        ..Default::default()
                    }
                }
                Err(_) => {
                    SubagentResult {
                        success: false,
                        cancelled: was_cancelled,
                        error: Some(
                            if was_cancelled {
                                "Subagent was cancelled".to_string()
                            } else {
                                "Child session dropped unexpectedly".to_string()
                            },
                        ),
                        subagent_id: request.id.clone(),
                        child_session_id: child_session_id.0.to_string(),
                        tool_calls,
                        turns,
                        duration_ms,
                        worktree_path: worktree_path
                            .as_ref()
                            .map(|p| p.to_string_lossy().to_string()),
                        ..Default::default()
                    }
                }
            }
        }
    };
    update_subagent_meta_completed(&subagent_meta_dir, &result);
    let final_status = result.status().to_string();
    let snapshot_dispose_enabled = ctx.resolve_subagent_worktree_snapshot_enabled();
    let telemetry_tokens = if result.tool_calls > 0 || result.success {
        child_handle.chat_state_handle.get_total_tokens().await
    } else {
        0
    };
    let (subagent_usage_by_model, subagent_usage_incomplete) = match child_handle
        .chat_state_handle
        .try_get_session_usage()
        .await
    {
        Ok(u) => (Some(u.by_model.into_iter().collect::<Vec<_>>()), u.incomplete),
        Err(()) => (None, true),
    };
    let fold_acked = match subagent_usage_by_model {
        None => false,
        Some(ref by_model) if by_model.is_empty() && !subagent_usage_incomplete => true,
        Some(by_model) => {
            if let Some(cmd_tx) = ctx.parent_cmd_tx.as_ref() {
                let (respond_to, ack) = tokio::sync::oneshot::channel();
                match cmd_tx
                    .send(crate::session::commands::SessionCommand::RecordSubagentUsage {
                        by_model,
                        parent_prompt_id: request.parent_prompt_id.clone(),
                        incomplete: subagent_usage_incomplete,
                        respond_to,
                    })
                {
                    Ok(()) => ack.await.is_ok(),
                    Err(_) => false,
                }
            } else {
                false
            }
        }
    };
    if !fold_acked {
        tracing::warn!(
            subagent_id = % request.id, parent_prompt_id = ? request.parent_prompt_id,
            "subagent usage not applied; parent bill marked incomplete"
        );
        let sticky_prompt = request
            .parent_prompt_id
            .clone()
            .or_else(|| coordinator.borrow().parent_prompt_id_for(&request.id));
        if let Some(cmd_tx) = ctx.parent_cmd_tx.as_ref() {
            let (respond_to, ack) = tokio::sync::oneshot::channel();
            if cmd_tx
                .send(crate::session::commands::SessionCommand::MarkSubagentUsageNotApplied {
                    parent_prompt_id: sticky_prompt,
                    respond_to,
                })
                .is_ok()
            {
                let _ = ack.await;
            }
        } else if let Some(ref pid) = sticky_prompt {
            coordinator.borrow_mut().mark_subagent_usage_not_applied(pid);
        }
    }
    match (&ctx.parent_terminal_backend, &ctx.parent_notification_handle) {
        (Some(parent_tb), Some(parent_notif_handle)) => {
            if !request.surface_completion {
                let reparented_task_ids: Vec<String> = parent_tb
                    .list_tasks()
                    .await
                    .into_iter()
                    .filter(|t| {
                        !t.completed
                            && t.owner_session_id.as_deref()
                                == Some(&*child_session_id.0)
                    })
                    .map(|t| t.task_id)
                    .collect();
                if !reparented_task_ids.is_empty()
                    && let Some(cmd_tx) = ctx.parent_cmd_tx.as_ref()
                {
                    let _ = cmd_tx
                        .send(SessionCommand::RecordGoalTurnTaskIds {
                            task_ids: reparented_task_ids,
                        });
                }
            }
            let parent_backend_weak = std::sync::Arc::downgrade(parent_tb);
            parent_tb
                .reparent_notifications(
                    &child_session_id.0,
                    &ctx.parent_session_id,
                    parent_notif_handle.clone(),
                    parent_backend_weak,
                )
                .await;
        }
        (Some(_), None) | (None, Some(_)) => {
            tracing::warn!(
                child_session_id = % child_session_id.0, parent_session_id = % ctx
                .parent_session_id, has_terminal_backend = ctx.parent_terminal_backend
                .is_some(), has_notification_handle = ctx.parent_notification_handle
                .is_some(),
                "skipping reparent_notifications: parent_terminal_backend and \
                 parent_notification_handle must both be Some"
            );
        }
        (None, None) => {}
    }
    let _ = child_handle.cmd_tx.send(SessionCommand::Shutdown);
    let mut disposed_snapshot_ref: Option<String> = None;
    let mut worktree_removed = false;
    if let Some(ref wt_path) = worktree_path {
        if snapshot_dispose_enabled {
            let ref_name = format!("refs/kigi/subagents/{}", request.id);
            let source_repo = resolve_subagent_source_repo(&ctx);
            match crate::session::worktree::snapshot_subagent_worktree(
                    wt_path,
                    &source_repo,
                    &ref_name,
                )
                .await
            {
                Ok(snapshot_ref) => {
                    let persisted = update_subagent_meta_snapshot_ref(
                        &subagent_meta_dir,
                        &snapshot_ref,
                        &final_status,
                    );
                    if persisted {
                        disposed_snapshot_ref = Some(snapshot_ref);
                        match crate::session::worktree::remove_subagent_worktree(wt_path)
                            .await
                        {
                            Ok(()) => {
                                worktree_removed = true;
                                tracing::info!(
                                    subagent_id = % request.id, worktree_path = % wt_path
                                    .display(), "snapshotted and removed subagent worktree"
                                );
                            }
                            Err(e) => {
                                tracing::warn!(
                                    subagent_id = % request.id, worktree_path = % wt_path
                                    .display(), error = % e,
                                    "snapshotted subagent worktree but removal failed; ref persisted for resume"
                                )
                            }
                        }
                    } else {
                        tracing::warn!(
                            subagent_id = % request.id, worktree_path = % wt_path
                            .display(),
                            "snapshot_ref not persisted; preserving worktree for resume"
                        );
                    }
                }
                Err(e) => {
                    tracing::warn!(
                        subagent_id = % request.id, worktree_path = % wt_path.display(),
                        error = % e,
                        "Failed to snapshot subagent worktree; preserving for review"
                    );
                }
            }
        } else {
            tracing::info!(
                subagent_id = % request.id, worktree_path = % wt_path.display(),
                "Worktree preserved for review"
            );
        }
    }
    if worktree_removed {
        result.worktree_path = None;
    }
    let (block_waited, explicitly_killed) = {
        let mut coord = coordinator.borrow_mut();
        (
            coord.block_wait_delivered_or_live(&request.id),
            coord.is_explicitly_killed(&request.id),
        )
    };
    let will_wake = should_auto_wake_subagent(
        request.run_in_background,
        result.cancelled,
        ctx.auto_wake_enabled,
        block_waited,
        explicitly_killed,
        ctx.goal_loop_active.load(std::sync::atomic::Ordering::Relaxed),
        ctx.parent_cmd_tx.is_some(),
    );
    emit_subagent_notification(
        gateway,
        &ctx.parent_session_id,
        SessionUpdate::SubagentFinished {
            subagent_id: request.id.clone(),
            child_session_id: result.child_session_id.clone(),
            status: result.status().to_string(),
            error: result.error.clone(),
            tool_calls: result.tool_calls,
            turns: result.turns,
            duration_ms: result.duration_ms,
            tokens_used: telemetry_tokens,
            output: if result.success { Some(result.output.to_string()) } else { None },
            will_wake,
        },
        ctx.parent_cmd_tx.as_ref(),
    );
    coordinator
        .borrow_mut()
        .move_to_completed(
            &request.id,
            request.description.clone(),
            request.subagent_type.clone(),
            result.clone(),
        );
    if let Some(snapshot_ref) = disposed_snapshot_ref {
        coordinator.borrow_mut().set_completed_snapshot_ref(&request.id, snapshot_ref);
    }
    if will_wake {
        inject_subagent_completed_prompt(
            &request.id,
            &result,
            &request,
            &ctx.auto_wake_delivered,
            ctx.parent_cmd_tx.as_ref(),
            &ctx.task_output_tool_name,
        );
    }
    if let Some(tx) = result_tx.take() {
        let _ = tx.send(result);
    }
}
