mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-22 21:31:17 +00:00
* feat(macos): add Quick Chat power features * docs(macos): document Quick Chat power features * chore(i18n): refresh native locale artifacts for Quick Chat power features * fix(macos): update DEBUG test helper sendProvider to the reasoning-threaded arity
110 lines
4.1 KiB
Swift
110 lines
4.1 KiB
Swift
import AppKit
|
|
import OpenClawChatUI
|
|
|
|
@MainActor
|
|
private final class QuickChatModelMenuTarget: NSObject {
|
|
let onSelectModel: (String) -> Void
|
|
let onSelectThinking: (String?) -> Void
|
|
|
|
init(
|
|
onSelectModel: @escaping (String) -> Void,
|
|
onSelectThinking: @escaping (String?) -> Void)
|
|
{
|
|
self.onSelectModel = onSelectModel
|
|
self.onSelectThinking = onSelectThinking
|
|
}
|
|
|
|
@objc func selectModel(_ sender: NSMenuItem) {
|
|
guard let selectionID = sender.representedObject as? String else { return }
|
|
self.onSelectModel(selectionID)
|
|
}
|
|
|
|
@objc func selectThinking(_ sender: NSMenuItem) {
|
|
guard let level = sender.representedObject as? String else { return }
|
|
self.onSelectThinking(level)
|
|
}
|
|
|
|
@objc func selectAutomaticThinking(_: NSMenuItem) {
|
|
self.onSelectThinking(nil)
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
enum QuickChatModelMenuPresenter {
|
|
static func present(model: QuickChatModel, panel: NSPanel, contentView: NSView) {
|
|
let target = QuickChatModelMenuTarget(
|
|
onSelectModel: { [weak model] selectionID in
|
|
model?.selectModel(selectionID)
|
|
},
|
|
onSelectThinking: { [weak model] level in
|
|
model?.selectThinkingLevel(level)
|
|
})
|
|
let menu = NSMenu()
|
|
let modelHeader = NSMenuItem(
|
|
title: String(localized: "Model"),
|
|
action: nil,
|
|
keyEquivalent: "")
|
|
modelHeader.isEnabled = false
|
|
menu.addItem(modelHeader)
|
|
|
|
let defaultItem = NSMenuItem(
|
|
title: String(localized: "Session default"),
|
|
action: #selector(QuickChatModelMenuTarget.selectModel(_:)),
|
|
keyEquivalent: "")
|
|
defaultItem.target = target
|
|
defaultItem.representedObject = OpenClawChatViewModel.defaultModelSelectionID
|
|
defaultItem.state = model.selectedModelSelectionID == OpenClawChatViewModel.defaultModelSelectionID
|
|
? .on
|
|
: .off
|
|
menu.addItem(defaultItem)
|
|
|
|
for section in model.modelPickerSections.providers {
|
|
let providerItem = NSMenuItem(title: section.displayName, action: nil, keyEquivalent: "")
|
|
let submenu = NSMenu()
|
|
for choice in section.models {
|
|
let item = NSMenuItem(
|
|
title: choice.name,
|
|
action: #selector(QuickChatModelMenuTarget.selectModel(_:)),
|
|
keyEquivalent: "")
|
|
item.target = target
|
|
item.representedObject = choice.selectionID
|
|
item.state = model.displayedModelSelectionID == choice.selectionID ? .on : .off
|
|
submenu.addItem(item)
|
|
}
|
|
providerItem.submenu = submenu
|
|
menu.addItem(providerItem)
|
|
}
|
|
|
|
menu.addItem(.separator())
|
|
let reasoningHeader = NSMenuItem(
|
|
title: String(localized: "Reasoning"),
|
|
action: nil,
|
|
keyEquivalent: "")
|
|
reasoningHeader.isEnabled = false
|
|
menu.addItem(reasoningHeader)
|
|
let automaticItem = NSMenuItem(
|
|
title: String(localized: "Auto"),
|
|
action: #selector(QuickChatModelMenuTarget.selectAutomaticThinking(_:)),
|
|
keyEquivalent: "")
|
|
automaticItem.target = target
|
|
automaticItem.state = model.selectedThinkingLevel == nil ? .on : .off
|
|
menu.addItem(automaticItem)
|
|
for option in model.thinkingOptions {
|
|
let item = NSMenuItem(
|
|
title: option.label,
|
|
action: #selector(QuickChatModelMenuTarget.selectThinking(_:)),
|
|
keyEquivalent: "")
|
|
item.target = target
|
|
item.representedObject = option.id
|
|
item.state = model.selectedThinkingLevel == option.id ? .on : .off
|
|
menu.addItem(item)
|
|
}
|
|
|
|
let windowPoint = panel.convertPoint(fromScreen: NSEvent.mouseLocation)
|
|
let contentPoint = contentView.convert(windowPoint, from: nil)
|
|
withExtendedLifetime(target) {
|
|
_ = menu.popUp(positioning: nil, at: contentPoint, in: contentView)
|
|
}
|
|
}
|
|
}
|