diff --git a/clients/macos/vellum-assistant/App/AppDelegate+ConnectionSetup.swift b/clients/macos/vellum-assistant/App/AppDelegate+ConnectionSetup.swift index 38e45bf22f9..915ab11c841 100644 --- a/clients/macos/vellum-assistant/App/AppDelegate+ConnectionSetup.swift +++ b/clients/macos/vellum-assistant/App/AppDelegate+ConnectionSetup.swift @@ -365,6 +365,15 @@ extension AppDelegate { self.featureFlagStore.reloadFromGateway() // Host tool execution — run locally and post results back case .hostBashRequest(let msg): + // Accept if this conversation is locally owned, OR if the request + // is explicitly targeted at this client (cross-client proxy routing). + let localClientId = DeviceIdStore.getOrCreate() + let isLocalConversation = self.mainWindow?.conversationManager + .conversations.contains(where: { $0.conversationId == msg.conversationId }) ?? false + let isTargeted = msg.targetClientId == localClientId + guard isLocalConversation || isTargeted else { + break + } HostToolExecutor.executeHostBashRequest(msg) case .hostFileRequest(let msg): HostToolExecutor.executeHostFileRequest(msg) diff --git a/clients/shared/Network/MessageTypes.swift b/clients/shared/Network/MessageTypes.swift index 7d31d00b839..cd400d20f65 100644 --- a/clients/shared/Network/MessageTypes.swift +++ b/clients/shared/Network/MessageTypes.swift @@ -1538,6 +1538,9 @@ public struct HostBashRequest: Decodable, Sendable { public let timeoutSeconds: Double? /// Extra environment variables to inject into the subprocess (e.g. VELLUM_UNTRUSTED_SHELL). public let env: [String: String]? + /// When set, this request is targeted at a specific client ID. Non-nil only for + /// cross-client proxy requests routed through HostBashProxy. + public let targetClientId: String? private enum CodingKeys: String, CodingKey { case type @@ -1547,6 +1550,7 @@ public struct HostBashRequest: Decodable, Sendable { case workingDir = "working_dir" case timeoutSeconds = "timeout_seconds" case env + case targetClientId } }