Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 21 additions & 30 deletions src/apps/desktop/src/api/agentic_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ pub async fn update_session_model(
#[tauri::command]
pub async fn start_dialog_turn(
_app: AppHandle,
coordinator: State<'_, Arc<ConversationCoordinator>>,
_coordinator: State<'_, Arc<ConversationCoordinator>>,
scheduler: State<'_, Arc<DialogScheduler>>,
request: StartDialogTurnRequest,
) -> Result<StartDialogTurnResponse, String> {
Expand All @@ -250,40 +250,31 @@ pub async fn start_dialog_turn(
image_contexts,
} = request;

if let Some(image_contexts) = image_contexts
let policy = DialogSubmissionPolicy::for_source(DialogTriggerSource::DesktopUi);
let resolved_images = if let Some(image_contexts) = image_contexts
.as_ref()
.filter(|images| !images.is_empty())
.cloned()
{
let resolved_image_contexts = resolve_missing_image_payloads(image_contexts)?;
coordinator
.start_dialog_turn_with_image_contexts(
session_id,
user_input,
original_user_input,
resolved_image_contexts,
turn_id,
agent_type,
workspace_path,
DialogSubmissionPolicy::for_source(DialogTriggerSource::DesktopUi),
)
.await
.map_err(|e| format!("Failed to start dialog turn: {}", e))?;
Some(resolve_missing_image_payloads(image_contexts)?)
} else {
scheduler
.submit(
session_id,
user_input,
original_user_input,
turn_id,
agent_type,
workspace_path,
DialogSubmissionPolicy::for_source(DialogTriggerSource::DesktopUi),
None,
)
.await
.map_err(|e| format!("Failed to start dialog turn: {}", e))?;
}
None
};

scheduler
.submit(
session_id,
user_input,
original_user_input,
turn_id,
agent_type,
workspace_path,
policy,
None,
resolved_images,
)
.await
.map_err(|e| format!("Failed to start dialog turn: {}", e))?;

Ok(StartDialogTurnResponse {
success: true,
Expand Down
1 change: 1 addition & 0 deletions src/apps/desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,7 @@ async fn init_agentic_system() -> anyhow::Result<(
let scheduler =
coordination::DialogScheduler::new(coordinator.clone(), session_manager.clone());
coordinator.set_scheduler_notifier(scheduler.outcome_sender());
coordinator.set_round_preempt_source(scheduler.preempt_monitor());
coordination::set_global_scheduler(scheduler.clone());

let cron_service =
Expand Down
1 change: 1 addition & 0 deletions src/apps/server/src/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub async fn initialize(workspace: Option<String>) -> anyhow::Result<Arc<ServerA
let scheduler =
coordination::DialogScheduler::new(coordinator.clone(), session_manager.clone());
coordinator.set_scheduler_notifier(scheduler.outcome_sender());
coordinator.set_round_preempt_source(scheduler.preempt_monitor());
coordination::set_global_scheduler(scheduler.clone());

// Cron service
Expand Down
1 change: 1 addition & 0 deletions src/apps/server/src/rpc_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ pub async fn dispatch(
workspace_path,
DialogSubmissionPolicy::for_source(DialogTriggerSource::DesktopUi),
None,
None,
)
.await
.map_err(|e| anyhow!("{}", e))?;
Expand Down
1 change: 0 additions & 1 deletion src/crates/core/src/agentic/agents/agentic_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ impl AgenticMode {
"WebSearch".to_string(),
"TodoWrite".to_string(),
"MermaidInteractive".to_string(),
"view_image".to_string(),
"Skill".to_string(),
"AskUserQuestion".to_string(),
"Git".to_string(),
Expand Down
11 changes: 11 additions & 0 deletions src/crates/core/src/agentic/coordination/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::agentic::events::{
AgenticEvent, EventPriority, EventQueue, EventRouter, EventSubscriber,
};
use crate::agentic::execution::{ExecutionContext, ExecutionEngine};
use crate::agentic::round_preempt::DialogRoundPreemptSource;
use crate::agentic::image_analysis::ImageContextData;
use crate::agentic::session::SessionManager;
use crate::agentic::tools::pipeline::{SubagentParentInfo, ToolPipeline};
Expand Down Expand Up @@ -105,6 +106,8 @@ pub struct ConversationCoordinator {
event_router: Arc<EventRouter>,
/// Notifies DialogScheduler of turn outcomes; injected after construction
scheduler_notify_tx: OnceLock<mpsc::Sender<(String, TurnOutcome)>>,
/// Round-boundary yield (same source as scheduler's yield flags); injected after construction
round_preempt_source: OnceLock<Arc<dyn DialogRoundPreemptSource>>,
}

impl ConversationCoordinator {
Expand Down Expand Up @@ -247,6 +250,7 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
event_queue,
event_router,
scheduler_notify_tx: OnceLock::new(),
round_preempt_source: OnceLock::new(),
}
}

Expand All @@ -256,6 +260,11 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
let _ = self.scheduler_notify_tx.set(tx);
}

/// Wire round-boundary preempt (typically the scheduler's [`SessionRoundYieldFlags`](crate::agentic::round_preempt::SessionRoundYieldFlags)).
pub fn set_round_preempt_source(&self, source: Arc<dyn DialogRoundPreemptSource>) {
let _ = self.round_preempt_source.set(source);
}

/// Create a new session
pub async fn create_session(
&self,
Expand Down Expand Up @@ -1126,6 +1135,7 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
subagent_parent_info: None,
skip_tool_confirmation: submission_policy.skip_tool_confirmation,
workspace_services,
round_preempt: self.round_preempt_source.get().cloned(),
};

// Auto-generate session title on first message
Expand Down Expand Up @@ -1659,6 +1669,7 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
subagent_parent_info: Some(subagent_parent_info),
skip_tool_confirmation: false,
workspace_services: subagent_services,
round_preempt: self.round_preempt_source.get().cloned(),
};

let initial_messages = vec![Message::user(task_description)];
Expand Down
Loading
Loading