Files
openhuman/overlay/src/parentCoreRpc.ts
T
8627cee960 Feat/overlay (#378)
* feat(autocomplete): add overlay TTL configuration to AutocompletePanel

- Introduced `overlay_ttl_ms` parameter to the Autocomplete configuration, allowing users to set the overlay display duration.
- Updated AutocompletePanel to include a new input field for adjusting the overlay TTL in milliseconds.
- Enhanced parsing and saving logic to handle the new configuration parameter.
- Added corresponding tests to ensure functionality and validate the new overlay TTL feature.

This update improves user control over the autocomplete overlay behavior, enhancing the overall user experience.

* Refactor accessibility code for improved readability and consistency

- Simplified log statements in `precompile_helper_background` for better clarity.
- Reformatted `detect_input_monitoring_permission` check in `keys.rs` for enhanced readability.
- Rearranged imports in `mod.rs` to maintain consistent structure.
- Improved formatting of `ElementBounds` initialization across multiple test cases in `overlay.rs` and `types.rs` for better visual alignment.
- Enhanced test context creation in `types.rs` for improved clarity.

These changes enhance code maintainability and readability across the accessibility module.

* fix(overlay): parent core RPC, voice toggle, and debug for #342

- Pass OPENHUMAN_OVERLAY_PARENT_RPC_URL from sidecar spawn and strip inherited
  OPENHUMAN_CORE_PORT so the overlay no longer fights for the parent listen port.
- Overlay UI uses HTTP JSON-RPC to the parent sidecar for globe, debug, and voice
  STT so state matches the main app; add parentCoreRpc helper mirroring legacy
  method aliases.
- Skip embedded JSON-RPC server when parent URL is set; use
  OPENHUMAN_OVERLAY_EMBEDDED_CORE_PORT (default 7799) for standalone dev.
- Fix screen intelligence status method name; add voice_status polling, STT
  section, collapsible debug summary, and connection banner when core is unreachable.
- Voice capture switch gates the mic with real STT availability from voice_status.

Closes #342

Made-with: Cursor

* fix: address CodeRabbit review on overlay/autocomplete (PR #378)

- helper: correlate JSON-RPC replies with monotonic request ids; discard mismatched
  lines until deadline (fixes stale response after timeout).
- helper: serialize Swift compile via HELPER_COMPILE_LOCK (precompile vs first use).
- Overlay Tab hint: pass tab_hint from Rust from accept_with_tab; Swift hides hint when empty.
- keys: re-check Input Monitoring on an interval when denied so grant without restart works.
- engine: use non-zero confidence placeholder (0.75) until inline_complete returns scores.
- overlay dedupe: suppress identical badge only within 400ms, not for process lifetime.

Co-authored-by: Code review feedback <noreply@github.com>
Made-with: Cursor

* fix(ci): resolve clippy and warning issues for Rust gates

- Use match on anchor_bounds in autocomplete overlay (avoid unnecessary unwrap)
- Drop unused test imports in registry_ops and rpc dispatch
- Prefix unused notion_doc_id in subconscious integration test

Made-with: Cursor

* fix(overlay): improve parent RPC URL handling in App component

- Updated the useEffect hook to manage the parent RPC URL more robustly by introducing a mounted flag to prevent state updates on unmounted components.
- Added error handling to set the parent RPC URL to null in case of invocation failure, enhancing the reliability of the component's behavior.

* feat(overlay): implement timeout handling for parent core RPC requests

- Introduced a default timeout for parent core RPC requests, enhancing reliability by preventing indefinite waiting for responses.
- Added an AbortController to manage request timeouts, throwing a specific error message when a timeout occurs.
- Updated the `callParentCoreRpc` function to accept a customizable timeout parameter, improving flexibility for RPC calls.

* fix(overlay): allow stopping active recording regardless of config state

- Updated the main button handler in the App component to always permit stopping an active recording when the status is "listening", improving user experience and control over the recording process.
- Removed redundant code that previously checked the status before stopping the recording, streamlining the logic.

* feat(overlay): update Cargo.lock with new dependencies and versions

- Added new packages including `alsa`, `alsa-sys`, `arboard`, `block`, `cocoa`, `core-foundation`, `core-graphics`, `coreaudio-rs`, `coreaudio-sys`, `cpal`, `crunchy`, and `dasp_sample` to enhance functionality and support for audio processing and system interactions.
- Updated existing dependencies to their latest versions for improved performance and compatibility.
- Modified the `show_overlay` function in `ops.rs` to include an additional parameter, enhancing the overlay display functionality.

* feat(autocomplete): add overlay_ttl_ms parameter to Autocomplete interfaces

- Introduced a new optional parameter `overlay_ttl_ms` to both `AutocompleteSetStyleParams` and `AutocompleteConfig` interfaces, allowing for customizable overlay timeout settings.
- This enhancement improves the flexibility of the autocomplete feature by enabling developers to specify how long the overlay should remain visible.

---------

Co-authored-by: Code review feedback <noreply@github.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
2026-04-06 21:11:27 -07:00

96 lines
2.5 KiB
TypeScript

/**
* HTTP JSON-RPC to the desktop core sidecar (same process as the main app).
* Mirrors the naming normalization in app/src/services/coreRpcClient.ts (subset).
*/
let nextJsonRpcId = 1;
export function normalizeLegacyMethod(method: string): string {
if (method.startsWith("openhuman.accessibility_")) {
return method.replace("openhuman.accessibility_", "openhuman.screen_intelligence_");
}
return method;
}
/** RpcOutcome with non-empty logs serializes as `{ result, logs }` in the core. */
function unwrapCliCompatibleJson<T>(raw: unknown): T {
if (
raw !== null &&
typeof raw === "object" &&
"result" in raw &&
"logs" in raw &&
Array.isArray((raw as { logs: unknown }).logs)
) {
return (raw as { result: T }).result;
}
return raw as T;
}
interface JsonRpcError {
code: number;
message: string;
data?: unknown;
}
interface JsonRpcResponse<T> {
jsonrpc?: string;
id?: number | string | null;
result?: T;
error?: JsonRpcError;
}
/** Default timeout for parent core RPC requests (ms). */
const DEFAULT_RPC_TIMEOUT_MS = 10_000;
export async function callParentCoreRpc<T>(
rpcUrl: string,
method: string,
params: Record<string, unknown> = {},
timeoutMs: number = DEFAULT_RPC_TIMEOUT_MS,
): Promise<T> {
const normalizedMethod = normalizeLegacyMethod(method);
const payload = {
jsonrpc: "2.0" as const,
id: nextJsonRpcId++,
method: normalizedMethod,
params,
};
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
let response: Response;
try {
response = await fetch(rpcUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
signal: controller.signal,
});
} catch (err) {
clearTimeout(timer);
if (err instanceof DOMException && err.name === "AbortError") {
throw new Error(`Core RPC request timed out after ${timeoutMs}ms (method: ${normalizedMethod})`);
}
throw err;
} finally {
clearTimeout(timer);
}
if (!response.ok) {
const text = await response.text();
throw new Error(`Core RPC HTTP ${response.status}: ${text || response.statusText}`);
}
const json = (await response.json()) as JsonRpcResponse<unknown>;
if (json.error) {
throw new Error(json.error.message || "Core RPC returned an error");
}
if (!Object.prototype.hasOwnProperty.call(json, "result")) {
throw new Error("Core RPC response missing result");
}
return unwrapCliCompatibleJson<T>(json.result);
}