Skip to content

Improve autocomplete observability and runtime controls in settings + JSON-RPC#308

Merged
graycyrus merged 4 commits intotinyhumansai:mainfrom
YellowSnnowmann:feat/autocomplete-panel
Apr 6, 2026
Merged

Improve autocomplete observability and runtime controls in settings + JSON-RPC#308
graycyrus merged 4 commits intotinyhumansai:mainfrom
YellowSnnowmann:feat/autocomplete-panel

Conversation

@YellowSnnowmann
Copy link
Copy Markdown
Contributor

@YellowSnnowmann YellowSnnowmann commented Apr 3, 2026

Summary

Improves Inline Autocomplete diagnostics and control flow across UI and core RPC by adding structured logs, better action/error feedback, and end-to-end coverage for runtime settings and accept behavior.


Changes

  • Add MAX_LOG_ENTRIES cap (200) and millisecond-precision timestamps in AutocompletePanel logs

  • Add [ui-flow] logs for key UI actions:

    • save
    • start/stop
    • fetch suggestion
    • accept
    • debug focus
  • Improve start/stop UX states:

    • Disable Start when already running or unsupported
    • Disable Stop when not running
    • Return clearer status messages after start attempts
  • Harden panel error handling with specific failure logs/messages:

    • refresh
    • save
    • start/stop
    • current
    • accept
    • debug focus
  • Accept flow improvements:

    • Pass current suggestion explicitly to openhumanAutocompleteAccept
    • Refresh history after accept
    • Keep status/logs in sync
  • Add skip_apply to autocomplete accept schema metadata

  • Expand Rust RPC logs:

    • Add structured [autocomplete] logs for endpoints
  • Add tests:

    • Vitest suite for AutocompletePanel (happy path, settings, logs)
    • macOS JSON-RPC E2E:
      • set_style → start → status → current → accept(skip_apply) → stop

Problem

  • Autocomplete diagnostics and runtime behavior were hard to trace end-to-end
  • UI logs:
    • Limited
    • Lacked precision
  • Action failures lacked structured, actionable diagnostics
  • Start/stop controls allowed ambiguous states
  • Core RPC logs were minimal for debugging transitions
  • Missing coverage for full runtime settings + accept flow

Solution

Add structured observability and improved runtime feedback across UI and core.

UI (AutocompletePanel)

  • Introduce bounded, timestamped log stream
  • Add explicit UI-flow logs and clearer failure messages
  • Improve start/stop button enablement rules
  • Use explicit suggestion in accept call
  • Refresh status/history after key actions

Core (src/openhuman/autocomplete/ops.rs)

  • Replace single-line logs with richer RpcOutcome::new(...) log sets for:

    • status
    • start
    • stop
    • current
    • debug_focus
    • accept
    • set_style
    • history
    • clear_history
  • Include structured fields:

    • running
    • enabled
    • phase
    • debounce
    • chars
    • reason

Schema (schemas.rs)

  • Add skip_apply input field to autocomplete.accept metadata

Tests

  • Add full AutocompletePanel unit test flow
  • Add macOS JSON-RPC E2E test:
    • Validates:
      • settings persistence
      • structured logs
      • accept behavior with skip_apply

Submission Checklist

Unit Tests

  • Vitest

    • app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx
  • Rust

    • No new unit tests (covered via JSON-RPC E2E)

E2E / Integration

  • Added:

    • tests/json_rpc_e2e.rs
    • macOS test: json_rpc_autocomplete_runtime_settings_and_logs_flow
  • Covers:

    • runtime config updates
    • lifecycle transitions
    • current suggestion flow
    • skip_apply accept behavior
    • structured logging

Doc Comments

  • N/A (no doc-comment specific changes)

Inline Comments

  • Added where needed:
    • test/setup flow
    • UI log behavior

Impact

  • Improved debuggability for autocomplete lifecycle and failures

  • More predictable settings panel runtime controls

  • Increased confidence via:

    • UI unit tests
    • JSON-RPC E2E coverage
  • Low risk:

    • Scoped to:
      • Autocomplete panel
      • Autocomplete RPC ops/schemas
      • Test suites

Related

Summary by CodeRabbit

  • New Features

    • Richer live logging in the settings UI (precise timestamps, UI-sourced entries, clear logs)
    • Acceptance can opt to skip applying suggestions (new control flag)
    • UI shows spinner during refresh and disables Start/Stop appropriately
  • Bug Fixes

    • Focus validation relaxed for editable fields to avoid interrupted insertions
  • Improvements

    • Longer refresh/operation timeouts and clearer status/error messages
  • Tests

    • New end-to-end and UI tests covering autocomplete lifecycle and logs

- Introduced MAX_LOG_ENTRIES constant to limit log entries to 200.
- Updated log formatting to include timestamps with milliseconds for better precision.
- Added UI logging for various actions (e.g., saving settings, starting/stopping autocomplete) to improve traceability.
- Enhanced error handling in refreshStatus, acceptSuggestion, and other functions to log specific failure messages.
- Added unit tests for AutocompletePanel to ensure functionality and logging behavior.

This update improves the overall user experience by providing clearer logs and better error handling in the Autocomplete feature.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

Enhanced autocomplete: improved UI logging and lifecycle flows, added millisecond timestamps and capped logs, preserved suggestions on timeouts, added skip_apply to accept, increased timeouts, richer RPC logs, and new frontend and macOS E2E tests covering the full autocomplete lifecycle.

Changes

Cohort / File(s) Summary
React Component & Tests
app/src/components/settings/panels/AutocompletePanel.tsx, app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx
Added MAX_LOG_ENTRIES cap, millisecond timestamps, appendUiLog and clearLogs, refreshed refreshStatus(showSpinner?), adjusted start/stop/accept flows and button enablement; added comprehensive UI test that mocks Tauri commands and validates full suggest→accept workflow and live logs.
Rust Autocomplete Engine
src/openhuman/autocomplete/core/engine.rs
Added REFRESH_TIMEOUT_SECS = 120; on refresh timeout, snapshot context/app/role and only clear suggestion if drifted, set last_error/phase/updated_at_ms; acceptance and tab-accept paths now preserve suggestion on failure, record last_error, update phase based on suggestion presence, and clear last_error on successful terminal accepts.
Rust RPC Handlers & Schemas
src/openhuman/autocomplete/ops.rs, src/openhuman/autocomplete/schemas.rs
Replaced single-line logs with structured RpcOutcome::new(result, Vec<String>) entries containing runtime metadata for status/start/stop/current/accept/set_style/history/clear_history; added optional skip_apply: Option<Bool> input to autocomplete/accept schema.
Rust Accessibility & Local AI Bootstrap
src/openhuman/accessibility/focus.rs, src/openhuman/local_ai/service/bootstrap.rs
On macOS focus role mismatch, allow differing editable roles (AXTextArea/AXTextField) to proceed with a debug log; increased reqwest::Client timeout from 30s to 120s in LocalAiService construction.
Rust E2E Tests
tests/json_rpc_e2e.rs
Added macOS-only helper to write config with local AI disabled and a new Tokio E2E test that drives autocomplete RPCs (set_style → start → status → current → accept → stop) and asserts config values and structured log contents.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI (AutocompletePanel)
    participant RPC as RPC Server
    participant Engine as Autocomplete Engine
    participant OS as Accessibility / Focus

    UI->>RPC: openhuman.autocomplete_set_style(params)
    RPC->>Engine: set_style(params)
    Engine-->>RPC: result + logs
    RPC-->>UI: response + logs

    UI->>RPC: openhuman.autocomplete_start()
    RPC->>Engine: start()
    Engine-->>RPC: started + status logs
    RPC-->>UI: status + logs

    UI->>RPC: openhuman.autocomplete_current(context)
    RPC->>Engine: current(context)
    Engine->>OS: validate_focused_target()
    OS-->>Engine: focus info
    Engine-->>RPC: suggestion + logs
    RPC-->>UI: suggestion + logs

    UI->>RPC: openhuman.autocomplete_accept { suggestion, skip_apply? }
    RPC->>Engine: accept(suggestion, skip_apply)
    Engine->>OS: try_apply_to_focused_field (if not skip_apply)
    OS-->>Engine: apply result / error
    Engine-->>RPC: accept result + logs
    RPC-->>UI: accept response + logs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • #249: E2E coverage request for AutocompletePanel and log/history/clear behavior — this PR adds the UI test and implements the related flows.

Possibly related PRs

Poem

🐰
Logs now tick in milliseconds neat,
Suggestions wait when timeouts meet,
Accept may skip the apply dance,
Tests run through the whole romance,
A rabbit cheers — code hopped to complete!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main changes: improving autocomplete observability through structured logging and enhancing runtime controls in both settings UI and JSON-RPC.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

… handling and logging

- Updated  to log role changes as debug information instead of returning an error, allowing for more flexible handling of role fluctuations.
- Increased the timeout for autocomplete refresh operations from 15 seconds to 120 seconds to accommodate longer processing times, enhancing reliability.
- Improved error handling in the autocomplete engine to preserve previous suggestions and provide clearer error messages when operations are aborted.

These changes enhance the user experience by providing better logging and more robust handling of focus and autocomplete functionalities.
@YellowSnnowmann YellowSnnowmann marked this pull request as ready for review April 6, 2026 06:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/components/settings/panels/AutocompletePanel.tsx`:
- Around line 195-205: refreshStatus is currently appending every
autocomplete_status log (appendLogs(response.logs)) even when called by the 1.2s
poller; change it so only manual/action-triggered refreshes append raw logs—use
the showSpinner boolean to gate appendLogs (call appendLogs(response.logs) only
when showSpinner is true) while leaving trackStatusChanges(response.result) and
setStatus(response.result) unchanged so polling relies on trackStatusChanges
without drowning the log buffer.
- Around line 355-356: The history RPC call after accepting a completion races
the backend write because AutocompleteEngine::accept() persists in a detached
tokio::spawn; update the client-side flow in AutocompletePanel.tsx to avoid
missing the just-accepted entry by replacing the single await loadHistory() call
with a short retry/poll loop (e.g., call loadHistory(), if the expected entry
isn't present sleep a small interval and retry up to N times) after await
refreshStatus(); alternatively, if you prefer server-side change, make
AutocompleteEngine::accept() await the primary history save before returning so
loadHistory() is consistent — reference the loadHistory() and refreshStatus()
calls in AutocompletePanel.tsx and the AutocompleteEngine::accept() persistence
behavior when implementing the fix.
- Around line 345-354: The settings-panel accept path must call
openhumanAutocompleteAccept with skip_apply: true to avoid backend attempting an
AX insertion; update the openhumanAutocompleteAccept invocation (where
appendUiLog is called and suggestion is passed via status?.suggestion?.value) to
include skip_apply: true, keep appendLogs(response.logs) as-is, and change the
success check to use response.result.accepted (and response.result.value) rather
than response.result.applied when deciding the setMessage text and fallback
reason.

In `@src/openhuman/accessibility/focus.rs`:
- Around line 355-361: The current validate_focused_target logic treats any role
mismatch as inconclusive; change it to only relax mismatches between editable
text roles (e.g., "AXTextArea" and "AXTextField") while keeping all other role
changes fatal: inside validate_focused_target, replace the unconditional "role
changed ... proceeding" branch with a conditional that checks if both expected
and actual are text-editable roles (use the exact role string comparisons for
"AXTextArea" and "AXTextField" or a small helper like
is_text_editable_role(expected/actual)); if both are editable, log the debug and
continue, otherwise return the existing error/abort path so callers such as
accept() and try_accept_via_tab() will stop on non-text role mismatches.

In `@src/openhuman/autocomplete/core/engine.rs`:
- Around line 145-149: The timeout branch around time::timeout(...) that calls
engine.refresh(None) can leave a stale `suggestion` that mismatches new focus
metadata; update the timeout handling in the refresh block (and the similar
branch around lines 186-197) to either validate the preserved `suggestion`
against a snapshot of `{context, app, role}` taken before refresh or simply
clear `self.suggestion` when the timeout fires so `accept()` cannot apply an
outdated completion; locate references to engine.refresh(None), the `suggestion`
field, and the accept() path and ensure you only keep the suggestion when the
stored snapshot matches the post-refresh metadata, otherwise set suggestion to
None and avoid writing accepted-history with mismatched metadata.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 65feccd0-0f40-4246-89b6-d39ccac0bd37

📥 Commits

Reviewing files that changed from the base of the PR and between 36e5736 and 5f394be.

📒 Files selected for processing (8)
  • app/src/components/settings/panels/AutocompletePanel.tsx
  • app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx
  • src/openhuman/accessibility/focus.rs
  • src/openhuman/autocomplete/core/engine.rs
  • src/openhuman/autocomplete/ops.rs
  • src/openhuman/autocomplete/schemas.rs
  • src/openhuman/local_ai/service/bootstrap.rs
  • tests/json_rpc_e2e.rs

Comment thread app/src/components/settings/panels/AutocompletePanel.tsx Outdated
Comment thread app/src/components/settings/panels/AutocompletePanel.tsx
Comment thread app/src/components/settings/panels/AutocompletePanel.tsx Outdated
Comment thread src/openhuman/accessibility/focus.rs Outdated
Comment thread src/openhuman/autocomplete/core/engine.rs
- Refactored loadHistory to return an empty array when Tauri is not available, improving error handling.
- Introduced waitForAcceptedHistoryEntry to ensure the history is loaded before accepting suggestions, enhancing user experience.
- Updated the accept suggestion logic to use the new waitForAcceptedHistoryEntry function, ensuring the correct suggestion is applied.
- Modified tests to reflect changes in the accept suggestion API, ensuring accurate functionality.

These changes improve the reliability and responsiveness of the autocomplete feature.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/openhuman/autocomplete/core/engine.rs (1)

145-224: ⚠️ Potential issue | 🟡 Minor

Snapshot comparison may race with partial state updates during refresh.

The pre-refresh snapshot is captured before refresh(None) is called, but refresh() updates app_name, target_role, and updated_at_ms at line 555-557 before inference completes. If inference times out after these updates, the post-snapshot will differ even though the suggestion (if any) was generated for the new context, not the pre-snapshot context.

This could cause unnecessary clearing of valid suggestions or, conversely, retain suggestions that should be cleared. Consider snapshotting after the context capture inside refresh() returns, or accepting that the conservative "clear on any drift" is acceptable for a 120s edge case.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/openhuman/autocomplete/core/engine.rs` around lines 145 - 224, The
pre_refresh_snapshot comparison can race with partial updates because
pre_refresh_snapshot is taken before engine.refresh(None) while refresh()
mutates state.app_name and state.target_role early; as a fix, capture the "pre"
snapshot immediately before calling refresh and capture the "post" snapshot
after refresh returns (i.e., move where post_refresh_snapshot is taken to after
the timeout branch when refresh completes/errs) or alternatively adjust the
logic to compare against the snapshot of metadata that refresh actually began
with by exposing/returning the refresh-start metadata from engine.refresh (e.g.,
have engine.refresh return its initial context/app_name/target_role or provide a
method like refresh_start_snapshot) and use those values instead of reading
state midway; update references around pre_refresh_snapshot,
post_refresh_snapshot, engine.refresh, and
state.suggestion/state.app_name/target_role accordingly.
🧹 Nitpick comments (1)
app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx (1)

208-293: Comprehensive happy-path test covering the full autocomplete lifecycle.

The test validates:

  • Initial status display
  • Settings save with updated debounce/max_chars/accept_with_tab
  • Start and running state reflection
  • Get suggestion with context override
  • Accept with skip_apply: true (matching the schema change)
  • Log display and clear behavior

This provides good end-to-end coverage for the panel's primary flow.

Consider adding a second test case for error/edge paths (e.g., start when enabled=false, accept with no suggestion) to increase resilience against regressions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx`
around lines 208 - 293, Add a second test in AutocompletePanel.test.tsx to cover
error/edge paths: create a new it(...) that simulates starting when the
autocomplete feature is disabled (e.g., ensure Platform supported or Running
toggles to false/disabled) and verifies openhumanAutocompleteStart is not called
and the UI shows the correct error/disabled state, and test accepting with no
current suggestion to confirm openhumanAutocompleteAccept is not called and the
UI shows an appropriate message; reuse the existing helpers/selectors (e.g.,
buttons named 'Start', 'Get Suggestion', 'Accept Suggestion', and functions
openhumanAutocompleteStart/openhumanAutocompleteAccept/openhumanAutocompleteCurrent)
to drive and assert behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/openhuman/autocomplete/core/engine.rs`:
- Around line 145-224: The pre_refresh_snapshot comparison can race with partial
updates because pre_refresh_snapshot is taken before engine.refresh(None) while
refresh() mutates state.app_name and state.target_role early; as a fix, capture
the "pre" snapshot immediately before calling refresh and capture the "post"
snapshot after refresh returns (i.e., move where post_refresh_snapshot is taken
to after the timeout branch when refresh completes/errs) or alternatively adjust
the logic to compare against the snapshot of metadata that refresh actually
began with by exposing/returning the refresh-start metadata from engine.refresh
(e.g., have engine.refresh return its initial context/app_name/target_role or
provide a method like refresh_start_snapshot) and use those values instead of
reading state midway; update references around pre_refresh_snapshot,
post_refresh_snapshot, engine.refresh, and
state.suggestion/state.app_name/target_role accordingly.

---

Nitpick comments:
In `@app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx`:
- Around line 208-293: Add a second test in AutocompletePanel.test.tsx to cover
error/edge paths: create a new it(...) that simulates starting when the
autocomplete feature is disabled (e.g., ensure Platform supported or Running
toggles to false/disabled) and verifies openhumanAutocompleteStart is not called
and the UI shows the correct error/disabled state, and test accepting with no
current suggestion to confirm openhumanAutocompleteAccept is not called and the
UI shows an appropriate message; reuse the existing helpers/selectors (e.g.,
buttons named 'Start', 'Get Suggestion', 'Accept Suggestion', and functions
openhumanAutocompleteStart/openhumanAutocompleteAccept/openhumanAutocompleteCurrent)
to drive and assert behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bcc0b070-5ed2-4519-958b-c9b95314912b

📥 Commits

Reviewing files that changed from the base of the PR and between 5f394be and 0bbf026.

📒 Files selected for processing (4)
  • app/src/components/settings/panels/AutocompletePanel.tsx
  • app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx
  • src/openhuman/accessibility/focus.rs
  • src/openhuman/autocomplete/core/engine.rs

@graycyrus graycyrus merged commit 0c14aea into tinyhumansai:main Apr 6, 2026
8 of 9 checks passed
YellowSnnowmann added a commit to YellowSnnowmann/openhuman that referenced this pull request Apr 6, 2026
Brings in Discord server/channel picker (tinyhumansai#349) and autocomplete
observability improvements (tinyhumansai#308) from main. Resolves conflict in
tests/json_rpc_e2e.rs by keeping both the screen intelligence tests
(this branch) and the autocomplete runtime settings test (main).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai coderabbitai Bot mentioned this pull request Apr 6, 2026
5 tasks
@YellowSnnowmann YellowSnnowmann linked an issue Apr 7, 2026 that may be closed by this pull request
23 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Complete Inline Autocomplete E2E (runtime, settings, logs)

2 participants