Improve daemon RPC resiliency and diff handling
This commit is contained in:
@@ -45,7 +45,7 @@ import type { AgentPermissionResponse } from "@server/server/agent/agent-sdk-typ
|
||||
import type { Agent } from "@/contexts/session-context";
|
||||
import { useSessionStore } from "@/stores/session-store";
|
||||
import { useFileExplorerActions } from "@/hooks/use-file-explorer-actions";
|
||||
import type { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
import { parseToolCallDisplay } from "@/utils/tool-call-parsers";
|
||||
import { ToolCallDetailsContent } from "./tool-call-details";
|
||||
import { ToolCallSheetProvider } from "./tool-call-sheet";
|
||||
@@ -760,7 +760,7 @@ function PermissionRequestCard({
|
||||
client,
|
||||
}: {
|
||||
permission: PendingPermission;
|
||||
client: DaemonClientV2 | null;
|
||||
client: DaemonClient | null;
|
||||
}) {
|
||||
const { theme } = useUnistyles();
|
||||
const isMobile =
|
||||
|
||||
@@ -26,7 +26,7 @@ import Animated, {
|
||||
} from "react-native-reanimated";
|
||||
import { useDictation } from "@/hooks/use-dictation";
|
||||
import { DictationOverlay } from "./dictation-controls";
|
||||
import type { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
import { usePanelStore } from "@/stores/panel-store";
|
||||
import { useVoiceOptional } from "@/contexts/voice-context";
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface MessageInputProps {
|
||||
images?: ImageAttachment[];
|
||||
onPickImages?: () => void;
|
||||
onRemoveImage?: (index: number) => void;
|
||||
client: DaemonClientV2 | null;
|
||||
client: DaemonClient | null;
|
||||
placeholder?: string;
|
||||
autoFocus?: boolean;
|
||||
disabled?: boolean;
|
||||
|
||||
@@ -20,7 +20,7 @@ import type {
|
||||
} from "@server/shared/messages";
|
||||
import type { AgentLifecycleStatus } from "@server/shared/agent-lifecycle";
|
||||
import type { AgentPermissionRequest } from "@server/server/agent/agent-sdk-types";
|
||||
import type { DaemonClientV2, ConnectionState } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonClient, ConnectionState } from "@server/client/daemon-client";
|
||||
import { File } from "expo-file-system";
|
||||
import { useDaemonConnections } from "./daemon-connections-context";
|
||||
import {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { generateMessageId } from "@/types/stream";
|
||||
import type { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
|
||||
export type DictationStreamSenderParams = {
|
||||
client: DaemonClientV2 | null;
|
||||
client: DaemonClient | null;
|
||||
format: string;
|
||||
createDictationId?: () => string;
|
||||
};
|
||||
@@ -22,7 +22,7 @@ type DictationFinishResult = { dictationId: string; text: string };
|
||||
* so enqueues can't "miss" a flush due to in-flight await/coalescing bugs.
|
||||
*/
|
||||
export class DictationStreamSender {
|
||||
private client: DaemonClientV2 | null;
|
||||
private client: DaemonClient | null;
|
||||
private readonly format: string;
|
||||
private readonly createDictationId: () => string;
|
||||
|
||||
@@ -40,7 +40,7 @@ export class DictationStreamSender {
|
||||
this.createDictationId = params.createDictationId ?? generateMessageId;
|
||||
}
|
||||
|
||||
setClient(client: DaemonClientV2 | null): void {
|
||||
setClient(client: DaemonClient | null): void {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useEffect, useRef, useCallback } from "react";
|
||||
import { AppState, Platform } from "react-native";
|
||||
import type { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
|
||||
const HEARTBEAT_INTERVAL_MS = 15_000;
|
||||
const ACTIVITY_HEARTBEAT_THROTTLE_MS = 5_000;
|
||||
|
||||
interface ClientActivityOptions {
|
||||
client: DaemonClientV2;
|
||||
client: DaemonClient;
|
||||
focusedAgentId: string | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { AppState } from "react-native";
|
||||
import { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import { DaemonClient } from "@server/client/daemon-client";
|
||||
import { createTauriWebSocketTransportFactory } from "@/utils/tauri-daemon-transport";
|
||||
|
||||
function runDaemonRequest(label: string, promise: Promise<unknown>): void {
|
||||
@@ -9,11 +9,11 @@ function runDaemonRequest(label: string, promise: Promise<unknown>): void {
|
||||
});
|
||||
}
|
||||
|
||||
export function useDaemonClient(url: string): DaemonClientV2 {
|
||||
export function useDaemonClient(url: string): DaemonClient {
|
||||
const client = useMemo(
|
||||
() => {
|
||||
const tauriTransportFactory = createTauriWebSocketTransportFactory();
|
||||
return new DaemonClientV2({
|
||||
return new DaemonClient({
|
||||
url,
|
||||
suppressSendErrors: true,
|
||||
...(tauriTransportFactory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type DictationStatus = "idle" | "recording" | "uploading" | "failed";
|
||||
|
||||
export type UseDictationOptions = {
|
||||
client: import("@server/client/daemon-client-v2").DaemonClientV2 | null;
|
||||
client: import("@server/client/daemon-client").DaemonClient | null;
|
||||
onTranscript: (text: string, meta: { requestId: string }) => void;
|
||||
onPartialTranscript?: (text: string, meta: { requestId: string }) => void;
|
||||
onError?: (error: Error) => void;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Platform } from "react-native";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import * as Notifications from "expo-notifications";
|
||||
import Constants from "expo-constants";
|
||||
import type { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
|
||||
const STORAGE_PREFIX = "@paseo:expo-push-token:";
|
||||
|
||||
@@ -26,7 +26,7 @@ async function ensurePushPermission(): Promise<boolean> {
|
||||
}
|
||||
|
||||
export function usePushTokenRegistration(params: {
|
||||
client: DaemonClientV2;
|
||||
client: DaemonClient;
|
||||
serverId: string;
|
||||
}): void {
|
||||
const { client, serverId } = params;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { create } from "zustand";
|
||||
import { subscribeWithSelector } from "zustand/middleware";
|
||||
import type { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
import type { useAudioPlayer } from "@/hooks/use-audio-player";
|
||||
import type { AgentDirectoryEntry } from "@/types/agent-directory";
|
||||
import type { StreamItem } from "@/types/stream";
|
||||
@@ -150,7 +150,7 @@ export interface SessionState {
|
||||
serverId: string;
|
||||
|
||||
// Daemon client (immutable reference)
|
||||
client: DaemonClientV2 | null;
|
||||
client: DaemonClient | null;
|
||||
|
||||
// Connection snapshot (mutable)
|
||||
connection: DaemonConnectionSnapshot;
|
||||
@@ -205,10 +205,10 @@ interface SessionStoreState {
|
||||
// Action types
|
||||
interface SessionStoreActions {
|
||||
// Session management
|
||||
initializeSession: (serverId: string, client: DaemonClientV2, audioPlayer: ReturnType<typeof useAudioPlayer>) => void;
|
||||
initializeSession: (serverId: string, client: DaemonClient, audioPlayer: ReturnType<typeof useAudioPlayer>) => void;
|
||||
clearSession: (serverId: string) => void;
|
||||
getSession: (serverId: string) => SessionState | undefined;
|
||||
updateSessionClient: (serverId: string, client: DaemonClientV2) => void;
|
||||
updateSessionClient: (serverId: string, client: DaemonClient) => void;
|
||||
updateSessionConnection: (serverId: string, connection: DaemonConnectionSnapshot) => void;
|
||||
|
||||
// Audio state
|
||||
@@ -280,7 +280,7 @@ function logSessionStoreUpdate(
|
||||
}
|
||||
|
||||
|
||||
function createDefaultConnectionSnapshot(client?: DaemonClientV2 | null): DaemonConnectionSnapshot {
|
||||
function createDefaultConnectionSnapshot(client?: DaemonClient | null): DaemonConnectionSnapshot {
|
||||
if (!client) {
|
||||
return { isConnected: false, isConnecting: false, lastError: null };
|
||||
}
|
||||
@@ -293,7 +293,7 @@ function createDefaultConnectionSnapshot(client?: DaemonClientV2 | null): Daemon
|
||||
}
|
||||
|
||||
// Helper to create initial session state
|
||||
function createInitialSessionState(serverId: string, client: DaemonClientV2, audioPlayer: ReturnType<typeof useAudioPlayer>): SessionState {
|
||||
function createInitialSessionState(serverId: string, client: DaemonClient, audioPlayer: ReturnType<typeof useAudioPlayer>): SessionState {
|
||||
return {
|
||||
serverId,
|
||||
client,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DaemonTransport, DaemonTransportFactory } from "@server/client/daemon-client-v2";
|
||||
import type { DaemonTransport, DaemonTransportFactory } from "@server/client/daemon-client";
|
||||
|
||||
type TauriWebSocketMessage =
|
||||
| { type: "Text"; data: string }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DaemonClientV2 } from "@server/client/daemon-client-v2";
|
||||
import type { ConnectionState } from "@server/client/daemon-client-v2";
|
||||
import { DaemonClient } from "@server/client/daemon-client";
|
||||
import type { ConnectionState } from "@server/client/daemon-client";
|
||||
import { buildDaemonWebSocketUrl } from "./daemon-endpoints";
|
||||
|
||||
function normalizeNonEmptyString(value: unknown): string | null {
|
||||
@@ -45,7 +45,7 @@ export async function testDaemonEndpointConnection(
|
||||
const timeoutMs = options?.timeoutMs ?? 6000;
|
||||
const url = buildDaemonWebSocketUrl(endpoint);
|
||||
|
||||
const client = new DaemonClientV2({
|
||||
const client = new DaemonClient({
|
||||
url,
|
||||
suppressSendErrors: true,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user