use std::{path::Path, sync::Arc};
use agent_client_protocol::schema::v1::SessionModeState;
use rho_sdk::{provider::ModelProvider, ApprovalSession, SessionOptions};
use super::super::{permission, AcpHost, AcpStartup};
use crate::{
added_dirs::AddedDirs,
app::{
agent_binding::BoundAgent,
automation::ensure_headless_auto_classifier_model,
interactive_runtime::startup::{
approval_channel_for, ApprovalChannel, ApprovalChannelOptions,
},
session_assembly::{
assemble_session, ApprovalInputs, SessionApproval, SessionAssembly,
SessionAssemblyOptions,
},
tools_prompt::McpSamplingSupport,
},
config::Config,
permission::PermissionMode,
};
pub(super) async fn build_session(
startup: &AcpStartup,
agent: &BoundAgent,
config: &Config,
workspace: &Path,
added_dirs: &AddedDirs,
session_options: impl FnOnce(Arc<dyn ModelProvider>) -> anyhow::Result<SessionOptions>,
) -> anyhow::Result<SessionAssembly> {
ensure_headless_auto_classifier_model(config)?;
let mut host_tools: anyhow::Result<()> = Ok(());
let assembly = assemble_session(SessionAssemblyOptions {
config,
config_path: startup.config_path.clone(),
cwd: workspace,
no_system_prompt: startup.no_system_prompt,
no_tools: startup.no_tools,
no_subagents: startup.no_subagents,
questionnaire_enabled: false,
mcp_elicitation: crate::tools::mcp::McpElicitationSupport::Unavailable,
mcp_sampling: McpSamplingSupport::Unavailable,
mcp_attach: crate::app::tools_prompt::McpAttach::Connect,
diagnostics: &startup.diagnostics,
agent,
max_steps: None,
usage_purpose: "agent",
usage_parent_session_id: None,
hook_host_labels: rho_sdk::hooks::HookHostLabels::new(),
added_dirs,
extend_tools: |mut tools| {
match startup.host {
AcpHost::Generic => {}
AcpHost::T3Code => {
host_tools = crate::tools::agent::install_host_delegation(
&mut tools,
workspace,
config.max_output_bytes,
);
}
}
tools
},
system_prompt_suffix: None,
approval: |inputs: ApprovalInputs| {
let ApprovalChannel {
handler, receiver, ..
} = approval_channel_for(
inputs.config.permission_mode,
ApprovalChannelOptions {
config: inputs.config,
workspace_path: inputs.workspace_root,
usage_recording: inputs.usage_recording,
session_writes: inputs.session_writes,
},
);
Ok(SessionApproval {
session: handler.map(ApprovalSession::from_shared),
receiver,
})
},
session_options,
})
.await?;
if let Err(error) = host_tools {
assembly.built.teardown().await;
return Err(error);
}
Ok(assembly)
}
pub(super) fn mode_state(mode: PermissionMode) -> SessionModeState {
SessionModeState::new(permission::mode_id(mode), permission::mode_list())
}
pub(super) fn session_config(
process: &Config,
host_servers: &[agent_client_protocol::schema::v1::McpServer],
) -> Config {
let mut config = process.clone();
super::super::host_mcp::overlay_host_mcp(&mut config.mcp, host_servers);
config
}