Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion app/src-tauri/src/claude_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ end tell"#;
.args(["-e", script])
.spawn()
.map_err(|e| format!("failed to open Terminal.app: {e}"))?;
return Ok("Terminal.app".into());
Ok("Terminal.app".into())
}

#[cfg(target_os = "linux")]
Expand Down
2 changes: 1 addition & 1 deletion app/src-tauri/src/imessage_scanner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ fn extract_text_from_attributed_body(blob: &[u8]) -> Option<String> {
.filter_map(|r| String::from_utf8(r).ok())
.filter(|s| {
let trimmed = s.trim();
trimmed.len() >= 2 && !ignored_markers.iter().any(|m| trimmed == *m)
trimmed.len() >= 2 && !ignored_markers.contains(&trimmed)
})
.max_by_key(|s| s.len())
.map(|s| s.trim().to_string())
Expand Down
8 changes: 4 additions & 4 deletions app/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@ fn mascot_window_show(app: AppHandle<AppRuntime>) -> Result<(), String> {
log::info!("[mascot-window] show requested");
#[cfg(target_os = "macos")]
{
return mascot_native_window::show(&app);
mascot_native_window::show(&app)
}
#[cfg(not(target_os = "macos"))]
{
Expand Down Expand Up @@ -1258,11 +1258,11 @@ fn notch_window_show(app: AppHandle<AppRuntime>) -> Result<(), String> {
log::info!("[notch-window] show requested");
#[cfg(target_os = "macos")]
{
return dispatch_notch_on_main(app, |app| {
dispatch_notch_on_main(app, |app| {
if let Err(e) = notch_window::show(app) {
log::warn!("[notch-window] show failed: {e}");
}
});
})
}
#[cfg(not(target_os = "macos"))]
{
Expand All @@ -1277,7 +1277,7 @@ fn notch_window_hide(app: AppHandle<AppRuntime>) -> Result<(), String> {
log::info!("[notch-window] hide requested");
#[cfg(target_os = "macos")]
{
return dispatch_notch_on_main(app, |_app| notch_window::hide());
dispatch_notch_on_main(app, |_app| notch_window::hide())
}
#[cfg(not(target_os = "macos"))]
{
Expand Down
5 changes: 4 additions & 1 deletion app/src-tauri/src/mascot_native_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ const DRAG_POLL_SECONDS: f64 = 0.016;
/// dropped webview.
struct MascotPanel {
panel: Retained<NSPanel>,
// RAII keep-alive: never read, but dropping it deallocates the WKWebView and
// blanks the panel. Must outlive the show/hide cycle β€” do not remove.
#[allow(dead_code)]
webview: Retained<WKWebView>,
drag_timer: Retained<NSTimer>,
}
Expand Down Expand Up @@ -389,7 +392,7 @@ unsafe fn build_webview(
let _: () = msg_send![&*webview, setAutoresizingMask: 18u64]; // width|height

// Make the webview the panel's content view so it fills the frame.
let webview_ref: &objc2::runtime::AnyObject = &*webview;
let webview_ref: &objc2::runtime::AnyObject = &webview;
let webview_view: *mut objc2::runtime::AnyObject =
webview_ref as *const _ as *mut objc2::runtime::AnyObject;
let _: () = msg_send![panel, setContentView: webview_view];
Expand Down
4 changes: 2 additions & 2 deletions app/src-tauri/src/native_notifications/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use crate::AppRuntime;
pub fn notification_permission_state() -> Result<String, String> {
#[cfg(target_os = "macos")]
{
return macos::permission_state();
macos::permission_state()
}
#[cfg(not(target_os = "macos"))]
{
Expand All @@ -51,7 +51,7 @@ pub fn notification_permission_state() -> Result<String, String> {
pub fn notification_permission_request() -> Result<String, String> {
#[cfg(target_os = "macos")]
{
return macos::request_permission();
macos::request_permission()
}
#[cfg(not(target_os = "macos"))]
{
Expand Down
6 changes: 1 addition & 5 deletions app/src-tauri/src/notch_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ thread_local! {
static NOTCH: RefCell<Option<NotchPanel>> = const { RefCell::new(None) };
}

pub(crate) fn is_open() -> bool {
NOTCH.with(|cell| cell.borrow().is_some())
}

pub(crate) fn hide() {
NOTCH.with(|cell| {
if let Some(existing) = cell.borrow_mut().take() {
Expand Down Expand Up @@ -262,7 +258,7 @@ unsafe fn build_webview(
// Auto-resize to fill the panel content view.
let _: () = msg_send![&*webview, setAutoresizingMask: 18u64]; // width|height

let webview_ref: &objc2::runtime::AnyObject = &*webview;
let webview_ref: &objc2::runtime::AnyObject = &webview;
let webview_view = webview_ref as *const _ as *mut objc2::runtime::AnyObject;
let _: () = msg_send![panel, setContentView: webview_view];

Expand Down
2 changes: 1 addition & 1 deletion app/src/services/chatService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ export function subscribeChatEvents(listeners: ChatEventListeners): () => void {
}

// Artifact lifecycle events (#2779). The Rust subscriber in
// `channels/providers/web::ArtifactSurfaceSubscriber` packs the
// `web_chat::ArtifactSurfaceSubscriber` packs the
// artifact payload into the generic `args` field of the wire
// envelope (kept the WebChannelEvent struct shape stable to avoid
// touching ~10 existing call sites with `..Default::default()`).
Expand Down
2 changes: 1 addition & 1 deletion docs/TEST-COVERAGE-MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ Canonical mapping of every product feature to its test source(s). Drives gap-fil
| 4.2.1 | User Message Handling | WD+RI | `conversations-web-channel-flow.spec.ts`, `tests/json_rpc_e2e.rs` | βœ… | |
| 4.2.2 | AI Response Generation | WD | `agent-review.spec.ts` | βœ… | Mock LLM |
| 4.2.3 | Streaming Responses | RI | `tests/json_rpc_e2e.rs`, `tests/agent_harness_e2e.rs` | βœ… | `tests/agent_harness_e2e.rs` adds provider-level SSE tool-arg accumulation (chunked args reassembled + parsed) and engine-level delta forwarding (#3471) |
| 4.2.4 | Parallel inference (cross-thread + within-thread forked turns) | RU+VU | `src/openhuman/channels/providers/web_tests.rs`, `app/src/store/__tests__/chatRuntimeSlice.test.ts`, `app/src/providers/__tests__/ChatRuntimeProvider.test.tsx` | 🟑 | Concurrent same-/cross-thread dispatch, cooperative `CancellationToken` teardown, and parallel-lane stream routing covered; dedicated WD E2E is a follow-up |
| 4.2.4 | Parallel inference (cross-thread + within-thread forked turns) | RU+VU | `src/openhuman/web_chat/web_tests.rs`, `app/src/store/__tests__/chatRuntimeSlice.test.ts`, `app/src/providers/__tests__/ChatRuntimeProvider.test.tsx` | 🟑 | Concurrent same-/cross-thread dispatch, cooperative `CancellationToken` teardown, and parallel-lane stream routing covered; dedicated WD E2E is a follow-up |
| 4.2.5 | Per-thread todo list (plan strip above composer) | RU+VU+WD | `src/openhuman/agent/tools/todo.rs`, `app/src/pages/conversations/components/ThreadTodoStrip.test.tsx`, `app/test/e2e/specs/chat-thread-todo-strip.spec.ts` | βœ… | Read-only thread-scoped todo strip fed by `task_board_updated`; agent `todo` tool guidance + thread binding; E2E drives a `todo` tool call and asserts the card renders |
| 4.2.6 | Background-activity panel (chat-header Background tasks button) | VU+WD | `app/src/pages/conversations/hooks/useBackgroundActivity.test.ts`, `app/src/pages/conversations/components/__tests__/BackgroundActivityRows.test.tsx`, `app/test/e2e/specs/chat-background-activity-panel.spec.ts` | βœ… | View-only panel surfacing this chat's async sub-agents + global cron jobs, subconscious/heartbeat status, and memory syncing; freshness-only "Syncing now" labeling; E2E opens the panel and asserts its sections render and close |
| 4.2.7 | Plan-mode review (Approve / Reject / Send-feedback before execute) | RU+RI+VU | `src/openhuman/plan_review/gate.rs`, `src/openhuman/plan_review/tool.rs`, `src/openhuman/plan_review/schemas.rs`, `tests/json_rpc_e2e.rs`, `app/src/pages/conversations/components/PlanReviewCard.test.tsx`, `app/src/pages/__tests__/Conversations.render.test.tsx` | βœ… | Interactive turns call `request_plan_review`, which parks the LIVE turn on the in-memory `PlanReviewGate` (oneshot) until the user decides; `plan_review_request` socket event drives `PlanReviewCard`, which resolves via `openhuman.plan_review_decide` (approve resumes-and-executes / reject resumes-and-stops / revise resumes-with-feedback). RU covers gate park/resolve/timeout + tool auto-approve + parking; RI covers the decide RPC; VU covers the card + provider wiring. WD E2E (agent-driven park flow) tracked as follow-up |
Expand Down
2 changes: 1 addition & 1 deletion src/core/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ fn build_registered_controllers() -> Vec<GroupedController> {
push(
&mut controllers,
DomainGroup::Channels,
crate::openhuman::channels::providers::web::all_web_channel_registered_controllers(),
crate::openhuman::web_chat::all_web_channel_registered_controllers(),
);
push(
&mut controllers,
Expand Down
4 changes: 2 additions & 2 deletions src/core/event_bus/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ pub enum DomainEvent {
/// flow-approval-surface, PR2/PR3). Unlike `ApprovalRequested`, this
/// event carries no `thread_id`/`client_id` β€” a flow run has neither, so
/// the generic chat-routed socket bridge
/// (`channels::providers::web::event_bus::ApprovalSurfaceSubscriber`)
/// (`web_chat::event_bus::ApprovalSurfaceSubscriber`)
/// silently drops it (that gap was the original silent-deadlock bug).
/// Published by `ApprovalGate::intercept_audited` alongside the existing
/// `ApprovalRequested`, bridged by `core::socketio` directly to a
Expand Down Expand Up @@ -611,7 +611,7 @@ pub enum DomainEvent {
///
/// Bridged to the `external_transfer_pending` web-channel socket event by
/// `EgressSurfaceSubscriber` (defined in
/// `src/openhuman/channels/providers/web/event_bus.rs`) when the emitting
/// `src/openhuman/web_chat/event_bus.rs`) when the emitting
/// turn carries chat routing. `thread_id` / `client_id` come from the
/// ambient `APPROVAL_CHAT_CONTEXT` and are `None` for CLI / cron /
/// background transfers (no chat surface to route to).
Expand Down
12 changes: 6 additions & 6 deletions src/core/jsonrpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,7 @@ async fn events_handler(
}

let client_id = query.client_id;
let rx = crate::openhuman::channels::providers::web::subscribe_web_channel_events();
let rx = crate::openhuman::web_chat::subscribe_web_channel_events();
let stream = tokio_stream::wrappers::BroadcastStream::new(rx).filter_map(
move |item| -> Option<Result<Event, std::convert::Infallible>> {
let event = match item {
Expand Down Expand Up @@ -2350,18 +2350,18 @@ pub async fn bootstrap_core_runtime(
// `start_channels` is skipped for web-chat-only cores. Without this an
// unguarded standalone/CLI/Docker core would park a plan review that never
// reaches the UI and dies at the gate TTL. Idempotent (Once-guarded).
crate::openhuman::channels::providers::web::register_approval_surface_subscriber();
crate::openhuman::web_chat::register_approval_surface_subscriber();
// Bridge emergency-stop halt/resume β†’ the `automation_halt` broadcast on the
// same always-run boot path. `start_channels` (which also registers this)
// is skipped on a web-chat-only desktop with no listening integrations, so
// without this a halt/resume initiated from the CLI or another client would
// never reach the UI. Idempotent (Once-guarded). (#4255)
crate::openhuman::channels::providers::web::register_automation_halt_subscriber();
crate::openhuman::web_chat::register_automation_halt_subscriber();
// Egress-surface bridge (privacy epic S2, #4436) β€” registered
// unconditionally alongside the approval surface so external-transfer
// disclosures reach the UI even on cores that skip `start_channels` or run
// with the approval gate disabled. Idempotent (OnceLock-guarded).
crate::openhuman::channels::providers::web::register_egress_surface_subscriber();
crate::openhuman::web_chat::register_egress_surface_subscriber();

if decision.install_gate {
// Per-launch correlation token for the approval gate. This is
Expand All @@ -2382,7 +2382,7 @@ pub async fn bootstrap_core_runtime(
);
// (The approval/plan-review surface bridge is registered unconditionally
// above β€” it must run even when this gate-install branch is skipped.)
crate::openhuman::channels::providers::web::register_artifact_surface_subscriber();
crate::openhuman::web_chat::register_artifact_surface_subscriber();
} else {
log::error!(
"[runtime] approval gate DISABLED (OPENHUMAN_APPROVAL_GATE=0 honored on host={}) β€” \
Expand All @@ -2402,7 +2402,7 @@ pub async fn bootstrap_core_runtime(
// `if approval_gate` block so artifact events still publish when the user
// sets OPENHUMAN_APPROVAL_GATE=0 (CR #3328947323 on PR #3026). Idempotent
// (OnceLock-guarded inside register_artifact_surface_subscriber).
crate::openhuman::channels::providers::web::register_artifact_surface_subscriber();
crate::openhuman::web_chat::register_artifact_surface_subscriber();

// --- Workspace migrations --------------------------------------------
crate::openhuman::startup::run_workspace_migrations(&workspace_dir);
Expand Down
10 changes: 5 additions & 5 deletions src/core/observability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ pub enum ExpectedErrorKind {
/// `agent::run_single` already suppresses the **agent-layer** Sentry
/// event for this condition via the typed
/// `AgentError::EmptyProviderResponse` + `AgentError::skips_sentry()`
/// (PR #2790, TAURI-RUST-4JX). But `channels::providers::web::
/// (PR #2790, TAURI-RUST-4JX). But `web_chat::
/// run_chat_task` **re-reports** the same failure under
/// `domain=web_channel operation=run_chat_task` after the typed error
/// has been flattened to a `String` at the native-bus boundary β€” so the
Expand Down Expand Up @@ -302,7 +302,7 @@ pub enum ExpectedErrorKind {
/// (`api_error`) already demotes its own per-attempt event; this catches
/// the **re-report** when the same flattened error is raised again under
/// `domain=web_channel` / `agent` (the path
/// `channels::providers::web::run_chat_task` β†’
/// `web_chat::run_chat_task` β†’
/// `report_error_or_expected`). The FE surfaces actionable copy via
/// `classify_inference_error`; Sentry must not double-report (F2/F4).
///
Expand Down Expand Up @@ -975,7 +975,7 @@ fn is_memory_store_breaker_open(lower: &str) -> bool {
/// - `"OpenHuman API error (401 Unauthorized): {…\"Session expired. Please
/// log in again.\"…}"` β€” emitted by `providers::ops::api_error` from the
/// OpenHuman backend and re-raised through `agent::run_single` /
/// `channels::providers::web::run_chat_task` (OPENHUMAN-TAURI-26). The
/// `web_chat::run_chat_task` (OPENHUMAN-TAURI-26). The
/// `"session expired"` substring anchors the match to the OpenHuman
/// backend's session-renewal body, not the bare numeric status.
/// - `"OpenHuman API error (401 Unauthorized): {…\"error\":\"Invalid token\"…}"`
Expand Down Expand Up @@ -1870,7 +1870,7 @@ fn is_filesystem_user_path_invalid_message(lower: &str) -> bool {
/// `text_chars=0 thinking_chars=0 tool_calls=0`.
///
/// This catches the **web-channel re-report** (Sentry TAURI-RUST-4Z1):
/// `channels::providers::web::run_chat_task` wraps the failure as
/// `web_chat::run_chat_task` wraps the failure as
/// `"run_chat_task failed client_id=… error=The model returned an empty
/// response. Please try again."` and routes it through
/// `report_error_or_expected` after the typed
Expand Down Expand Up @@ -2598,7 +2598,7 @@ fn all_provider_attempts_are_transient(message: &str) -> bool {
/// Defense-in-depth filter for the Sentry `before_send` hook: the primary
/// suppression lives at the call sites in `agent::harness::session::
/// runtime::run_single`, `channels::runtime::dispatch`, and
/// `channels::providers::web::run_chat_task`, all of which now skip
/// `web_chat::run_chat_task`, all of which now skip
/// `report_error` when this variant is detected. This filter catches any
/// future call site that re-emits the message without going through those
/// funnels β€” e.g. a new wrapper that calls `tracing::error!` directly with
Expand Down
Loading
Loading