agentix-cli 0.59.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +4 -0
- package/apps/mac-voice/Sources/AgentXVoice/AnswerView.swift +228 -0
- package/apps/mac-voice/Sources/AgentXVoice/Orb.swift +36 -9
- package/apps/mac-voice/Sources/AgentXVoice/Panel.swift +126 -55
- package/apps/mac-voice/Sources/AgentXVoice/PanelAnswer.swift +113 -0
- package/apps/mac-voice/Sources/AgentXVoice/PillPlacement.swift +28 -17
- package/apps/mac-voice/Sources/AgentXVoice/SettingsLook.swift +90 -0
- package/apps/mac-voice/Sources/AgentXVoice/SettingsWindow.swift +10 -3
- package/apps/mac-voice/Sources/AgentXVoice/StatusMenu.swift +9 -0
- package/apps/mac-voice/Sources/AgentXVoice/Surface.swift +105 -0
- package/apps/mac-voice/Sources/AgentXVoice/VoiceSettings.swift +32 -1
- package/apps/mac-voice/Sources/AgentXVoice/main.swift +23 -10
- package/dist/{App-QEJGXZTY.js → App-LQXWKBVY.js} +2 -2
- package/dist/{ChatApp-VKWQN5GM.js → ChatApp-75TL4LKW.js} +2 -2
- package/dist/{agent-MJKLI2L5.js → agent-DH4FMMMY.js} +2 -2
- package/dist/{board-dashboard-2KVT72J7.js → board-dashboard-C6AZHDHU.js} +657 -188
- package/dist/board-dashboard-C6AZHDHU.js.map +1 -0
- package/dist/{chunk-WFPRVZBA.js → chunk-27P5NLTC.js} +2 -2
- package/dist/{chunk-3EVCHRJF.js → chunk-2VQIPJH5.js} +2 -2
- package/dist/{chunk-YRB75GMN.js → chunk-3XVTFNYM.js} +2 -2
- package/dist/{chunk-K62U5EJJ.js → chunk-B3DCYBP4.js} +2 -2
- package/dist/{chunk-ILXW3ERG.js → chunk-BCXKRD5L.js} +159 -153
- package/dist/chunk-BCXKRD5L.js.map +1 -0
- package/dist/{chunk-EJQOKSKP.js → chunk-CRSXKQLZ.js} +2 -2
- package/dist/{chunk-YCIZ2WHX.js → chunk-DTEQNXK3.js} +2 -2
- package/dist/{chunk-N5GOBLUI.js → chunk-E2BJVHBR.js} +2 -2
- package/dist/{chunk-6DUTIPTY.js → chunk-E2PWCU2N.js} +2 -2
- package/dist/{chunk-2XZGHIVP.js → chunk-JO3PSLWL.js} +5 -5
- package/dist/{chunk-YQU74AOL.js → chunk-JORXRF4E.js} +2 -2
- package/dist/{chunk-DAAWUFO4.js → chunk-LXUG2X26.js} +2 -2
- package/dist/{chunk-JUY77L7C.js → chunk-N5KD3TVN.js} +2 -2
- package/dist/{chunk-5OF3EGCZ.js → chunk-NBGNPKAF.js} +2 -2
- package/dist/chunk-RVEMQCWW.js +130 -0
- package/dist/chunk-RVEMQCWW.js.map +1 -0
- package/dist/chunk-S7TCVIET.js +15 -0
- package/dist/chunk-S7TCVIET.js.map +1 -0
- package/dist/{chunk-WI5R64WO.js → chunk-WBGC7MWX.js} +2 -2
- package/dist/{chunk-6ZV2QFXE.js → chunk-WIBMNQKJ.js} +2 -2
- package/dist/{chunk-L5OCF33B.js → chunk-WOPFHKBF.js} +2 -2
- package/dist/{chunk-SDBU6747.js → chunk-Y76THZUQ.js} +178 -276
- package/dist/chunk-Y76THZUQ.js.map +1 -0
- package/dist/{chunk-OIDMPPV5.js → chunk-YQCOX4R3.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/client-QVZIZFV4.js +2 -0
- package/dist/config-3XC7EYB7.js +2 -0
- package/dist/config-mutator-HKU63FJM.js +2 -0
- package/dist/doctor-YFA4ZSRH.js +2 -0
- package/dist/index.d.ts +49 -7
- package/dist/index.js +1 -1
- package/dist/program-L6VAFALE.js +2 -0
- package/dist/{promote-GBR6YSQW.js → promote-UR2GSHKC.js} +2 -2
- package/dist/query-XUP3BMVS.js +2 -0
- package/dist/{registry-P535FNLB.js → registry-PGALUW5L.js} +2 -2
- package/dist/{request-planner-KHTCHF7N.js → request-planner-NHE3IRJN.js} +2 -2
- package/dist/{review-candidates-Y5KCRUNU.js → review-candidates-6GKRSRBQ.js} +2 -2
- package/dist/{routing-RWCCDJ4D.js → routing-AQKHAU3Z.js} +2 -2
- package/dist/schedule-tool-6NMCLTIH.js +2 -0
- package/dist/scheduler-RAYGNDWT.js +2 -0
- package/dist/{seat-PJPKLH6L.js → seat-6FMW2QI4.js} +2 -2
- package/dist/{select-VMTJAX5X.js → select-5VONJMLH.js} +2 -2
- package/dist/{set-enabled-LPXH3ZQP.js → set-enabled-YHD3IJJZ.js} +2 -2
- package/dist/{tool-MWXG44OT.js → tool-MXJGLJZ5.js} +2 -2
- package/dist/wiki-ZQLEYY24.js +2 -0
- package/package.json +1 -1
- package/apps/mac-voice/Sources/AgentXVoice/ResultCard.swift +0 -198
- package/dist/board-dashboard-2KVT72J7.js.map +0 -1
- package/dist/chunk-4ZTV6JV7.js +0 -29
- package/dist/chunk-4ZTV6JV7.js.map +0 -1
- package/dist/chunk-ILXW3ERG.js.map +0 -1
- package/dist/chunk-IW4XIZAZ.js +0 -15
- package/dist/chunk-IW4XIZAZ.js.map +0 -1
- package/dist/chunk-SDBU6747.js.map +0 -1
- package/dist/client-X2PTYKVX.js +0 -2
- package/dist/config-XB2ORKWS.js +0 -2
- package/dist/config-mutator-KMXR3XDG.js +0 -2
- package/dist/doctor-6BIMNEGU.js +0 -2
- package/dist/program-DHDC6XYB.js +0 -2
- package/dist/query-672RGMXO.js +0 -2
- package/dist/schedule-tool-H46AK53H.js +0 -2
- package/dist/scheduler-3XLWBCX7.js +0 -2
- package/dist/wiki-QHMHVFWU.js +0 -2
- /package/dist/{App-QEJGXZTY.js.map → App-LQXWKBVY.js.map} +0 -0
- /package/dist/{ChatApp-VKWQN5GM.js.map → ChatApp-75TL4LKW.js.map} +0 -0
- /package/dist/{agent-MJKLI2L5.js.map → agent-DH4FMMMY.js.map} +0 -0
- /package/dist/{chunk-WFPRVZBA.js.map → chunk-27P5NLTC.js.map} +0 -0
- /package/dist/{chunk-3EVCHRJF.js.map → chunk-2VQIPJH5.js.map} +0 -0
- /package/dist/{chunk-YRB75GMN.js.map → chunk-3XVTFNYM.js.map} +0 -0
- /package/dist/{chunk-K62U5EJJ.js.map → chunk-B3DCYBP4.js.map} +0 -0
- /package/dist/{chunk-EJQOKSKP.js.map → chunk-CRSXKQLZ.js.map} +0 -0
- /package/dist/{chunk-YCIZ2WHX.js.map → chunk-DTEQNXK3.js.map} +0 -0
- /package/dist/{chunk-N5GOBLUI.js.map → chunk-E2BJVHBR.js.map} +0 -0
- /package/dist/{chunk-6DUTIPTY.js.map → chunk-E2PWCU2N.js.map} +0 -0
- /package/dist/{chunk-2XZGHIVP.js.map → chunk-JO3PSLWL.js.map} +0 -0
- /package/dist/{chunk-YQU74AOL.js.map → chunk-JORXRF4E.js.map} +0 -0
- /package/dist/{chunk-DAAWUFO4.js.map → chunk-LXUG2X26.js.map} +0 -0
- /package/dist/{chunk-JUY77L7C.js.map → chunk-N5KD3TVN.js.map} +0 -0
- /package/dist/{chunk-5OF3EGCZ.js.map → chunk-NBGNPKAF.js.map} +0 -0
- /package/dist/{chunk-WI5R64WO.js.map → chunk-WBGC7MWX.js.map} +0 -0
- /package/dist/{chunk-6ZV2QFXE.js.map → chunk-WIBMNQKJ.js.map} +0 -0
- /package/dist/{chunk-L5OCF33B.js.map → chunk-WOPFHKBF.js.map} +0 -0
- /package/dist/{chunk-OIDMPPV5.js.map → chunk-YQCOX4R3.js.map} +0 -0
- /package/dist/{client-X2PTYKVX.js.map → client-QVZIZFV4.js.map} +0 -0
- /package/dist/{config-XB2ORKWS.js.map → config-3XC7EYB7.js.map} +0 -0
- /package/dist/{config-mutator-KMXR3XDG.js.map → config-mutator-HKU63FJM.js.map} +0 -0
- /package/dist/{doctor-6BIMNEGU.js.map → doctor-YFA4ZSRH.js.map} +0 -0
- /package/dist/{program-DHDC6XYB.js.map → program-L6VAFALE.js.map} +0 -0
- /package/dist/{promote-GBR6YSQW.js.map → promote-UR2GSHKC.js.map} +0 -0
- /package/dist/{query-672RGMXO.js.map → query-XUP3BMVS.js.map} +0 -0
- /package/dist/{registry-P535FNLB.js.map → registry-PGALUW5L.js.map} +0 -0
- /package/dist/{request-planner-KHTCHF7N.js.map → request-planner-NHE3IRJN.js.map} +0 -0
- /package/dist/{review-candidates-Y5KCRUNU.js.map → review-candidates-6GKRSRBQ.js.map} +0 -0
- /package/dist/{routing-RWCCDJ4D.js.map → routing-AQKHAU3Z.js.map} +0 -0
- /package/dist/{schedule-tool-H46AK53H.js.map → schedule-tool-6NMCLTIH.js.map} +0 -0
- /package/dist/{scheduler-3XLWBCX7.js.map → scheduler-RAYGNDWT.js.map} +0 -0
- /package/dist/{seat-PJPKLH6L.js.map → seat-6FMW2QI4.js.map} +0 -0
- /package/dist/{select-VMTJAX5X.js.map → select-5VONJMLH.js.map} +0 -0
- /package/dist/{set-enabled-LPXH3ZQP.js.map → set-enabled-YHD3IJJZ.js.map} +0 -0
- /package/dist/{tool-MWXG44OT.js.map → tool-MXJGLJZ5.js.map} +0 -0
- /package/dist/{wiki-QHMHVFWU.js.map → wiki-ZQLEYY24.js.map} +0 -0
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import AppKit
|
|
2
|
-
import WebKit
|
|
3
|
-
|
|
4
|
-
/// What the agent said, in a form you can read, click and copy.
|
|
5
|
-
///
|
|
6
|
-
/// Speech is lossy in one specific way that matters: a URL cannot be
|
|
7
|
-
/// spoken usefully, an image cannot be spoken at all, and a name you have
|
|
8
|
-
/// not seen written is a name you cannot act on. The spoken answer is
|
|
9
|
-
/// deliberately short and stripped of exactly those things — so without a
|
|
10
|
-
/// visual surface, everything worth keeping from a turn is the part that
|
|
11
|
-
/// gets thrown away.
|
|
12
|
-
///
|
|
13
|
-
/// Rich content arrives through the same `agentx:ui` directive Telegram
|
|
14
|
-
/// and WhatsApp already use, parsed server-side, so an agent has one way to
|
|
15
|
-
/// attach a link or a picture regardless of where it is speaking.
|
|
16
|
-
final class ResultCard: NSPanel {
|
|
17
|
-
// A web view, because agents write markdown — headings, bullets,
|
|
18
|
-
// fenced code, tables. An NSTextView shows that as a mess of asterisks
|
|
19
|
-
// and hashes, which defeats the card's only purpose: being MORE
|
|
20
|
-
// readable than the spoken answer, not less.
|
|
21
|
-
private let web = WKWebView()
|
|
22
|
-
private let links = NSStackView()
|
|
23
|
-
private let thumb = NSImageView()
|
|
24
|
-
|
|
25
|
-
/// The pill's frame on screen, which the card attaches to. Set by the app.
|
|
26
|
-
var anchor: (() -> NSRect)?
|
|
27
|
-
|
|
28
|
-
init() {
|
|
29
|
-
super.init(contentRect: NSRect(x: 0, y: 0, width: 380, height: 260),
|
|
30
|
-
styleMask: [.titled, .closable, .resizable, .utilityWindow, .nonactivatingPanel],
|
|
31
|
-
backing: .buffered, defer: false)
|
|
32
|
-
title = "Agent"
|
|
33
|
-
// Brand radius on the utility panel so it matches the pill it
|
|
34
|
-
// sits above rather than defaulting to the system's corner.
|
|
35
|
-
contentView?.wantsLayer = true
|
|
36
|
-
isFloatingPanel = true
|
|
37
|
-
level = .floating
|
|
38
|
-
hidesOnDeactivate = false
|
|
39
|
-
collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
|
|
40
|
-
|
|
41
|
-
let content = NSView(frame: contentRect(forFrameRect: frame))
|
|
42
|
-
content.autoresizingMask = [.width, .height]
|
|
43
|
-
|
|
44
|
-
// Selectable, so the whole point — copying a link or a name out —
|
|
45
|
-
// actually works. Editable would let a stray keystroke destroy the
|
|
46
|
-
// answer before it is read.
|
|
47
|
-
web.setValue(false, forKey: "drawsBackground")
|
|
48
|
-
web.navigationDelegate = self
|
|
49
|
-
web.autoresizingMask = [.width, .height]
|
|
50
|
-
content.addSubview(web)
|
|
51
|
-
|
|
52
|
-
thumb.imageScaling = .scaleProportionallyUpOrDown
|
|
53
|
-
thumb.isHidden = true
|
|
54
|
-
content.addSubview(thumb)
|
|
55
|
-
|
|
56
|
-
links.orientation = .horizontal
|
|
57
|
-
links.spacing = 8
|
|
58
|
-
links.edgeInsets = NSEdgeInsets(top: 6, left: 10, bottom: 6, right: 10)
|
|
59
|
-
content.addSubview(links)
|
|
60
|
-
|
|
61
|
-
contentView = content
|
|
62
|
-
layout(content)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private func layout(_ content: NSView) {
|
|
66
|
-
let w = content.bounds.width, h = content.bounds.height
|
|
67
|
-
let linkH: CGFloat = links.arrangedSubviews.isEmpty ? 0 : 34
|
|
68
|
-
let imgH: CGFloat = thumb.isHidden ? 0 : 120
|
|
69
|
-
thumb.frame = NSRect(x: 10, y: h - imgH - 10, width: w - 20, height: imgH)
|
|
70
|
-
web.frame = NSRect(x: 0, y: linkH, width: w, height: h - linkH - imgH - (imgH > 0 ? 16 : 0))
|
|
71
|
-
links.frame = NSRect(x: 0, y: 0, width: w, height: linkH)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/// Does this turn have anything the spoken answer did not already
|
|
75
|
-
/// deliver?
|
|
76
|
-
///
|
|
77
|
-
/// The card opened on every turn, including "Ok." — a window with one
|
|
78
|
-
/// word in it, appearing and demanding dismissal, for an answer you had
|
|
79
|
-
/// already heard. A surface that adds nothing is worse than no surface:
|
|
80
|
-
/// it trains you to ignore it, so the turn where it DOES carry a link
|
|
81
|
-
/// gets ignored too.
|
|
82
|
-
///
|
|
83
|
-
/// Worth showing when there is rich content, a URL you could click, or
|
|
84
|
-
/// materially more written than was spoken. Otherwise the speech was
|
|
85
|
-
/// the whole answer.
|
|
86
|
-
static func isWorthShowing(spoken: String, written: String?, buttons: [(String, String)], imageURL: String?) -> Bool {
|
|
87
|
-
if !buttons.isEmpty || imageURL != nil { return true }
|
|
88
|
-
let text = (written?.isEmpty == false ? written! : spoken)
|
|
89
|
-
if text.range(of: #"https?://"#, options: .regularExpression) != nil { return true }
|
|
90
|
-
// Speech drops formatting, so written is often a little longer for
|
|
91
|
-
// the same content. Only a real difference counts.
|
|
92
|
-
let spokenLen = spoken.trimmingCharacters(in: .whitespacesAndNewlines).count
|
|
93
|
-
let writtenLen = text.trimmingCharacters(in: .whitespacesAndNewlines).count
|
|
94
|
-
if writtenLen > spokenLen + 80 { return true }
|
|
95
|
-
// Long enough that re-reading it beats re-hearing it.
|
|
96
|
-
return writtenLen > 280
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/// `spoken` is what was said; `written` is the fuller answer with the
|
|
100
|
-
/// URLs and formatting the spoken form had to drop.
|
|
101
|
-
@MainActor
|
|
102
|
-
func show(spoken: String, written: String?, buttons: [(String, String)], imageURL: String?) {
|
|
103
|
-
let source = (written?.isEmpty == false ? written! : spoken)
|
|
104
|
-
web.loadHTMLString(Markdown.page(Markdown.toHTML(source), css: Brand.cardCSS), baseURL: nil)
|
|
105
|
-
|
|
106
|
-
links.arrangedSubviews.forEach { links.removeArrangedSubview($0); $0.removeFromSuperview() }
|
|
107
|
-
for (label, url) in buttons.prefix(4) {
|
|
108
|
-
let b = NSButton(title: label, target: self, action: #selector(openLink(_:)))
|
|
109
|
-
b.bezelStyle = .rounded
|
|
110
|
-
b.toolTip = url
|
|
111
|
-
b.identifier = NSUserInterfaceItemIdentifier(url)
|
|
112
|
-
links.addArrangedSubview(b)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
thumb.isHidden = true
|
|
116
|
-
if let s = imageURL, let u = URL(string: s) {
|
|
117
|
-
// Off the main thread: a slow image must never stall the UI,
|
|
118
|
-
// and the card is useful without it.
|
|
119
|
-
URLSession.shared.dataTask(with: u) { [weak self] data, _, _ in
|
|
120
|
-
guard let data, let img = NSImage(data: data) else { return }
|
|
121
|
-
Task { @MainActor in
|
|
122
|
-
guard let self else { return }
|
|
123
|
-
self.thumb.image = img
|
|
124
|
-
self.thumb.isHidden = false
|
|
125
|
-
if let c = self.contentView { self.layout(c) }
|
|
126
|
-
}
|
|
127
|
-
}.resume()
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if let c = contentView { layout(c) }
|
|
131
|
-
slideIn()
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/// Where the card goes against the pill: above it when there is at
|
|
135
|
-
/// least as much room above as below, else below; right edges aligned.
|
|
136
|
-
@MainActor
|
|
137
|
-
private func placement() -> PillPlacement.Card? {
|
|
138
|
-
guard let pill = anchor?() else { return nil }
|
|
139
|
-
let screen = NSScreen.screens.first { $0.frame.intersects(pill) } ?? NSScreen.main
|
|
140
|
-
guard let visible = screen?.visibleFrame else { return nil }
|
|
141
|
-
return PillPlacement.card(size: frame.size, pill: pill, visible: visible)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/// The pill moved: the open card moves with it, without animation.
|
|
145
|
-
@MainActor
|
|
146
|
-
func follow() {
|
|
147
|
-
guard isVisible, let spot = placement() else { return }
|
|
148
|
-
setFrameOrigin(spot.origin)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/// Slides out of the pill into place: up when it opens above, down
|
|
152
|
-
/// when below. With Reduce Motion it simply appears there.
|
|
153
|
-
@MainActor
|
|
154
|
-
private func slideIn() {
|
|
155
|
-
guard let spot = placement() else { alphaValue = 1; orderFrontRegardless(); return }
|
|
156
|
-
let target = spot.origin
|
|
157
|
-
let wasVisible = isVisible
|
|
158
|
-
guard !wasVisible, !NSWorkspace.shared.accessibilityDisplayShouldReduceMotion else {
|
|
159
|
-
setFrameOrigin(target)
|
|
160
|
-
alphaValue = 1
|
|
161
|
-
orderFrontRegardless()
|
|
162
|
-
return
|
|
163
|
-
}
|
|
164
|
-
setFrameOrigin(NSPoint(x: target.x, y: target.y + (spot.above ? -18 : 18)))
|
|
165
|
-
alphaValue = 0
|
|
166
|
-
orderFrontRegardless()
|
|
167
|
-
NSAnimationContext.runAnimationGroup { ctx in
|
|
168
|
-
ctx.duration = 0.28
|
|
169
|
-
ctx.timingFunction = Brand.ease
|
|
170
|
-
animator().setFrameOrigin(target)
|
|
171
|
-
animator().alphaValue = 1
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
@objc private func openLink(_ sender: NSButton) {
|
|
176
|
-
guard let s = sender.identifier?.rawValue, let u = URL(string: s) else { return }
|
|
177
|
-
NSWorkspace.shared.open(u)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
override var canBecomeKey: Bool { true }
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
extension ResultCard: WKNavigationDelegate {
|
|
184
|
-
/// Links open in the real browser. A 380-point utility panel is not a
|
|
185
|
-
/// place to read a web page, and navigating away would replace the
|
|
186
|
-
/// answer the card exists to hold.
|
|
187
|
-
func webView(_ webView: WKWebView,
|
|
188
|
-
decidePolicyFor navigationAction: WKNavigationAction,
|
|
189
|
-
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
|
190
|
-
if navigationAction.navigationType == .linkActivated,
|
|
191
|
-
let url = navigationAction.request.url {
|
|
192
|
-
NSWorkspace.shared.open(url)
|
|
193
|
-
decisionHandler(.cancel)
|
|
194
|
-
return
|
|
195
|
-
}
|
|
196
|
-
decisionHandler(.allow)
|
|
197
|
-
}
|
|
198
|
-
}
|