feat(vom): update vom algorithm, fix overlay problem with background state machine

This commit is contained in:
Ljy-0827
2026-07-27 13:46:33 +08:00
parent e14ae9cea0
commit 4fb2e331a6
36 changed files with 2276 additions and 452 deletions
+9 -10
View File
@@ -231,6 +231,7 @@ pub fn full_handler(status: DaemonStatus, state: Arc<DaemonState>) -> RpcHandler
| Method::ToolConsole
| Method::ToolNetwork
| Method::ToolSnapshot
| Method::ToolObserve
| Method::ToolGetHtml
| Method::ToolNavigate
| Method::ToolNavigateBack
@@ -291,16 +292,14 @@ async fn handle_tool_dispatch(
};
// Pre-flight: if the user has clicked the agent-window mask's
// stop button, every session carries a one-shot "pending
// interrupt" marker. The marker is consumed by the next
// *mutating* tool call (which is rejected with `UserAborted`).
// Read-only tools (snapshot / get_html / waits / tab_list) and
// session-lifecycle RPCs pass through transparently — gating
// them would prevent the agent from observing page state
// before asking the user, or from cleanly tearing down the
// session. Classification lives on `Method::is_mutating()` so
// adding a new tool variant requires an explicit
// classification call.
if method.is_mutating() && state.session_interrupts.try_consume(&session_id) {
// interrupt" marker. The marker is consumed by the next method
// that dispatches browser/page input (which is rejected with
// `UserAborted`). Passive reads and control-plane RPCs pass through
// transparently — gating them would prevent the agent from observing
// page state before asking the user, or from cleanly tearing down the
// session. Classification lives on `Method::effect()` so adding a new
// tool variant requires an explicit classification call.
if method.requires_interrupt_gate() && state.session_interrupts.try_consume(&session_id) {
return ResponseBody::Err(RpcError {
code: ErrorCode::UserAborted,
message: "tool dispatch rejected: pending user interrupt. The user explicitly requested to stop. Ask the user how to proceed before issuing further actions.".into(),
@@ -2,13 +2,13 @@
//!
//! Holds a single-use marker per `SessionId` indicating that the
//! user has clicked the agent-window mask's stop button. The next
//! mutating `tool.*` call for that session is rejected with
//! `ErrorCode::UserAborted`; read-only tools and session-lifecycle
//! browser-input-dispatching `tool.*` call for that session is rejected
//! with `ErrorCode::UserAborted`; passive reads and session-lifecycle
//! RPCs pass through transparently and do not consume the marker.
//!
//! The marker is single-use and has no expiry: it sits in the
//! registry until consumed by a mutating call or until the session
//! is torn down. This lets the user's interrupt survive an LLM
//! registry until consumed by an input-dispatching call or until the
//! session is torn down. This lets the user's interrupt survive an LLM
//! thinking phase of arbitrary length — the v1 time-window
//! mechanism dropped interrupts whenever the LLM took longer to
//! respond than the window allowed.
+2 -2
View File
@@ -46,8 +46,8 @@ pub struct DaemonState {
/// Per-session "pending interrupt" signal. The WS event handler
/// `mark`s the session when the user clicks the agent-window
/// mask's stop button; the IPC tool-dispatch handler
/// `try_consume`s on the way in so the next mutating tool call
/// is rejected with `UserAborted`. Independent of
/// `try_consume`s on the way in so the next browser-input-dispatching
/// tool call is rejected with `UserAborted`. Independent of
/// `SessionRegistry` because the signal is a transient runtime
/// control state.
pub session_interrupts: Arc<SessionInterruptRegistry>,