fix(mac): use gateway main session for WebChat
This commit is contained in:
@@ -60,9 +60,18 @@ final class DeepLinkHandler {
|
||||
|
||||
do {
|
||||
let channel = GatewayAgentChannel(raw: link.channel)
|
||||
let explicitSessionKey = link.sessionKey?
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.nonEmpty
|
||||
let resolvedSessionKey: String
|
||||
if let explicitSessionKey {
|
||||
resolvedSessionKey = explicitSessionKey
|
||||
} else {
|
||||
resolvedSessionKey = await GatewayConnection.shared.mainSessionKey()
|
||||
}
|
||||
let invocation = GatewayAgentInvocation(
|
||||
message: messagePreview,
|
||||
sessionKey: link.sessionKey?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty ?? "main",
|
||||
sessionKey: resolvedSessionKey,
|
||||
thinking: link.thinking?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty,
|
||||
deliver: channel.shouldDeliver(link.deliver),
|
||||
to: link.to?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty,
|
||||
|
||||
@@ -231,6 +231,38 @@ actor GatewayConnection {
|
||||
// MARK: - Typed gateway API
|
||||
|
||||
extension GatewayConnection {
|
||||
struct ConfigGetSnapshot: Decodable, Sendable {
|
||||
struct SnapshotConfig: Decodable, Sendable {
|
||||
struct Inbound: Decodable, Sendable {
|
||||
struct Session: Decodable, Sendable {
|
||||
let mainKey: String?
|
||||
}
|
||||
|
||||
let session: Session?
|
||||
}
|
||||
|
||||
let inbound: Inbound?
|
||||
}
|
||||
|
||||
let config: SnapshotConfig?
|
||||
}
|
||||
|
||||
static func mainSessionKey(fromConfigGetData data: Data) throws -> String {
|
||||
let snapshot = try JSONDecoder().decode(ConfigGetSnapshot.self, from: data)
|
||||
let raw = snapshot.config?.inbound?.session?.mainKey
|
||||
let trimmed = (raw ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return trimmed.isEmpty ? "main" : trimmed
|
||||
}
|
||||
|
||||
func mainSessionKey(timeoutMs: Double = 15000) async -> String {
|
||||
do {
|
||||
let data = try await self.requestRaw(method: "config.get", params: nil, timeoutMs: timeoutMs)
|
||||
return try Self.mainSessionKey(fromConfigGetData: data)
|
||||
} catch {
|
||||
return "main"
|
||||
}
|
||||
}
|
||||
|
||||
func status() async -> (ok: Bool, error: String?) {
|
||||
do {
|
||||
_ = try await self.requestRaw(method: .status)
|
||||
|
||||
@@ -80,9 +80,10 @@ final class HoverHUDController {
|
||||
func openChat() {
|
||||
guard let anchorProvider = self.anchorProvider else { return }
|
||||
self.dismiss(reason: "openChat")
|
||||
WebChatManager.shared.togglePanel(
|
||||
sessionKey: WebChatManager.shared.preferredSessionKey(),
|
||||
anchorProvider: anchorProvider)
|
||||
Task { @MainActor in
|
||||
let sessionKey = await WebChatManager.shared.preferredSessionKey()
|
||||
WebChatManager.shared.togglePanel(sessionKey: sessionKey, anchorProvider: anchorProvider)
|
||||
}
|
||||
}
|
||||
|
||||
func dismiss(reason: String = "explicit") {
|
||||
|
||||
@@ -125,9 +125,12 @@ struct ClawdisApp: App {
|
||||
private func toggleWebChatPanel() {
|
||||
HoverHUDController.shared.setSuppressed(true)
|
||||
self.isMenuPresented = false
|
||||
WebChatManager.shared.togglePanel(
|
||||
sessionKey: WebChatManager.shared.preferredSessionKey(),
|
||||
anchorProvider: { [self] in self.statusButtonScreenFrame() })
|
||||
Task { @MainActor in
|
||||
let sessionKey = await WebChatManager.shared.preferredSessionKey()
|
||||
WebChatManager.shared.togglePanel(
|
||||
sessionKey: sessionKey,
|
||||
anchorProvider: { [self] in self.statusButtonScreenFrame() })
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@@ -235,7 +238,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
// Developer/testing helper: auto-open chat when launched with --chat (or legacy --webchat).
|
||||
if CommandLine.arguments.contains("--chat") || CommandLine.arguments.contains("--webchat") {
|
||||
self.webChatAutoLogger.debug("Auto-opening chat via CLI flag")
|
||||
WebChatManager.shared.show(sessionKey: "main")
|
||||
Task { @MainActor in
|
||||
let sessionKey = await WebChatManager.shared.preferredSessionKey()
|
||||
WebChatManager.shared.show(sessionKey: sessionKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,10 @@ struct MenuContent: View {
|
||||
self.voiceWakeMicMenu
|
||||
}
|
||||
Button("Open Chat") {
|
||||
WebChatManager.shared.show(sessionKey: WebChatManager.shared.preferredSessionKey())
|
||||
Task { @MainActor in
|
||||
let sessionKey = await WebChatManager.shared.preferredSessionKey()
|
||||
WebChatManager.shared.show(sessionKey: sessionKey)
|
||||
}
|
||||
}
|
||||
Button("Open Dashboard") {
|
||||
Task { @MainActor in
|
||||
|
||||
@@ -22,22 +22,31 @@ final class WebChatManager {
|
||||
static let shared = WebChatManager()
|
||||
|
||||
private var windowController: WebChatSwiftUIWindowController?
|
||||
private var windowSessionKey: String?
|
||||
private var panelController: WebChatSwiftUIWindowController?
|
||||
private var panelSessionKey: String?
|
||||
private var cachedPreferredSessionKey: String?
|
||||
|
||||
var onPanelVisibilityChanged: ((Bool) -> Void)?
|
||||
|
||||
func show(sessionKey: String) {
|
||||
self.closePanel()
|
||||
if let controller = self.windowController {
|
||||
controller.show()
|
||||
return
|
||||
if self.windowSessionKey == sessionKey {
|
||||
controller.show()
|
||||
return
|
||||
}
|
||||
|
||||
controller.close()
|
||||
self.windowController = nil
|
||||
self.windowSessionKey = nil
|
||||
}
|
||||
let controller = WebChatSwiftUIWindowController(sessionKey: sessionKey, presentation: .window)
|
||||
controller.onVisibilityChanged = { [weak self] visible in
|
||||
self?.onPanelVisibilityChanged?(visible)
|
||||
}
|
||||
self.windowController = controller
|
||||
self.windowSessionKey = sessionKey
|
||||
controller.show()
|
||||
}
|
||||
|
||||
@@ -75,26 +84,31 @@ final class WebChatManager {
|
||||
self.panelController?.close()
|
||||
}
|
||||
|
||||
func preferredSessionKey() -> String {
|
||||
// The gateway store uses a canonical direct-chat bucket (default: "main").
|
||||
// Avoid reading local session files; in remote mode they are not authoritative.
|
||||
"main"
|
||||
func preferredSessionKey() async -> String {
|
||||
if let cachedPreferredSessionKey { return cachedPreferredSessionKey }
|
||||
let key = await GatewayConnection.shared.mainSessionKey()
|
||||
self.cachedPreferredSessionKey = key
|
||||
return key
|
||||
}
|
||||
|
||||
func resetTunnels() {
|
||||
self.windowController?.close()
|
||||
self.windowController = nil
|
||||
self.windowSessionKey = nil
|
||||
self.panelController?.close()
|
||||
self.panelController = nil
|
||||
self.panelSessionKey = nil
|
||||
self.cachedPreferredSessionKey = nil
|
||||
}
|
||||
|
||||
func close() {
|
||||
self.windowController?.close()
|
||||
self.windowController = nil
|
||||
self.windowSessionKey = nil
|
||||
self.panelController?.close()
|
||||
self.panelController = nil
|
||||
self.panelSessionKey = nil
|
||||
self.cachedPreferredSessionKey = nil
|
||||
}
|
||||
|
||||
private func panelHidden() {
|
||||
|
||||
Reference in New Issue
Block a user