agentix-cli 0.102.2 → 0.103.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/Character.swift +17 -5
- package/apps/mac-voice/Sources/AgentXVoice/CharacterMath.swift +13 -0
- package/apps/mac-voice/Sources/AgentXVoice/CharacterSim.swift +14 -16
- package/apps/mac-voice/Sources/AgentXVoice/CharacterSimFrame.swift +15 -0
- package/apps/mac-voice/Sources/AgentXVoice/Guide.swift +11 -6
- package/apps/mac-voice/Sources/AgentXVoice/GuideMath.swift +14 -2
- package/apps/mac-voice/Sources/AgentXVoice/IdlePlay.swift +113 -0
- package/apps/mac-voice/Sources/AgentXVoice/SettingsLook.swift +11 -0
- package/apps/mac-voice/Sources/AgentXVoice/SettingsWindow.swift +4 -1
- package/apps/mac-voice/Sources/AgentXVoice/VoiceSettings.swift +8 -2
- package/apps/mac-voice/Sources/AgentXVoice/main.swift +13 -2
- package/dist/{App-EYUDDF6K.js → App-A7WZMOGA.js} +2 -2
- package/dist/{ChatApp-F5LZLBI3.js → ChatApp-EWNT36ZE.js} +2 -2
- package/dist/{agent-XF3BWMOB.js → agent-MUGC4RZP.js} +2 -2
- package/dist/{board-dashboard-TVSOWW32.js → board-dashboard-IRMCGCU5.js} +4 -4
- package/dist/{chunk-ZJXDBVBT.js → chunk-25RQQ55U.js} +2 -2
- package/dist/{chunk-YOCQ2MWL.js → chunk-32BPHJ4I.js} +2 -2
- package/dist/{chunk-AYNZAOJN.js → chunk-76KJXOEV.js} +2 -2
- package/dist/{chunk-CDM4G3CW.js → chunk-7XLCM6CH.js} +185 -185
- package/dist/{chunk-CDM4G3CW.js.map → chunk-7XLCM6CH.js.map} +1 -1
- package/dist/{chunk-V6W3FFW7.js → chunk-BEFKOHRC.js} +2 -2
- package/dist/{chunk-QRD3ZG27.js → chunk-BUAVQUHR.js} +2 -2
- package/dist/{chunk-PYCTWI2I.js → chunk-CUS7WGZT.js} +2 -2
- package/dist/{chunk-EXPIKLUN.js → chunk-FZ7VHFL5.js} +2 -2
- package/dist/{chunk-RWSCQMLD.js → chunk-HE4PDESB.js} +2 -2
- package/dist/{chunk-HMDM5MCR.js → chunk-HVPRCHRG.js} +2 -2
- package/dist/{chunk-ECM2QEXF.js → chunk-IA3BC7M3.js} +10 -10
- package/dist/chunk-IA3BC7M3.js.map +1 -0
- package/dist/{chunk-S337S2M7.js → chunk-IOPAWHKW.js} +2 -2
- package/dist/{chunk-Y6POV2X5.js → chunk-MVLNVMWI.js} +2 -2
- package/dist/{chunk-HQJW3BC5.js → chunk-N4IWNCH3.js} +2 -2
- package/dist/{chunk-MWLX3QCD.js → chunk-NWNVHL57.js} +2 -2
- package/dist/{chunk-5UO6BBDG.js → chunk-OLUAEBHJ.js} +2 -2
- package/dist/{chunk-XO55WKCX.js → chunk-Q57GZPDA.js} +2 -2
- package/dist/{chunk-TXFIMVVF.js → chunk-UXTAK5WD.js} +5 -5
- package/dist/{chunk-GSFB46YC.js → chunk-WTFNEPJ7.js} +2 -2
- package/dist/{chunk-EEZI2K7S.js → chunk-XHUOWYNY.js} +2 -2
- package/dist/{chunk-N57ES35J.js → chunk-ZBKKOUNJ.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/{client-526OCGWD.js → client-ZX7AY7H3.js} +2 -2
- package/dist/config-BXOS2PLC.js +2 -0
- package/dist/config-mutator-KRAUD3CA.js +2 -0
- package/dist/{doctor-AC5ONEO2.js → doctor-P3QQP33C.js} +2 -2
- package/dist/index.d.ts +11 -0
- package/dist/index.js +1 -1
- package/dist/{program-M5LDV6UQ.js → program-2OEZFPW6.js} +169 -169
- package/dist/program-2OEZFPW6.js.map +1 -0
- package/dist/{promote-CNKIINYK.js → promote-FHX4Q62Z.js} +2 -2
- package/dist/{query-A2N2LIR7.js → query-WBK3YEPV.js} +2 -2
- package/dist/{registry-REKWHOHS.js → registry-NQHC7ZAV.js} +2 -2
- package/dist/{request-planner-MS5BS6HY.js → request-planner-3LA5RAKG.js} +2 -2
- package/dist/{review-candidates-2F4QK6QQ.js → review-candidates-QV66TOCL.js} +2 -2
- package/dist/{routing-SU5Q4IPM.js → routing-HF4XVD4Y.js} +2 -2
- package/dist/schedule-tool-V66FX5XL.js +2 -0
- package/dist/scheduler-XVMWASQR.js +2 -0
- package/dist/{seat-PZBFMYQL.js → seat-NQTZUIKH.js} +2 -2
- package/dist/{select-D3XOFXA5.js → select-3GVC5RDA.js} +2 -2
- package/dist/{set-enabled-DNDRQ3CZ.js → set-enabled-SXCE2MZX.js} +2 -2
- package/dist/{tool-FB6SPVIS.js → tool-23GOQNUW.js} +2 -2
- package/dist/{tool-RRGOHJW6.js → tool-E6JBENAN.js} +2 -2
- package/dist/wiki-VM2RTHVF.js +2 -0
- package/package.json +1 -1
- package/dist/chunk-ECM2QEXF.js.map +0 -1
- package/dist/config-HCJ5NZW5.js +0 -2
- package/dist/config-mutator-PGR2OGWC.js +0 -2
- package/dist/program-M5LDV6UQ.js.map +0 -1
- package/dist/schedule-tool-24KHZY2Z.js +0 -2
- package/dist/scheduler-ALDZOUKJ.js +0 -2
- package/dist/wiki-3DH2QYTX.js +0 -2
- /package/dist/{App-EYUDDF6K.js.map → App-A7WZMOGA.js.map} +0 -0
- /package/dist/{ChatApp-F5LZLBI3.js.map → ChatApp-EWNT36ZE.js.map} +0 -0
- /package/dist/{agent-XF3BWMOB.js.map → agent-MUGC4RZP.js.map} +0 -0
- /package/dist/{board-dashboard-TVSOWW32.js.map → board-dashboard-IRMCGCU5.js.map} +0 -0
- /package/dist/{chunk-ZJXDBVBT.js.map → chunk-25RQQ55U.js.map} +0 -0
- /package/dist/{chunk-YOCQ2MWL.js.map → chunk-32BPHJ4I.js.map} +0 -0
- /package/dist/{chunk-AYNZAOJN.js.map → chunk-76KJXOEV.js.map} +0 -0
- /package/dist/{chunk-V6W3FFW7.js.map → chunk-BEFKOHRC.js.map} +0 -0
- /package/dist/{chunk-QRD3ZG27.js.map → chunk-BUAVQUHR.js.map} +0 -0
- /package/dist/{chunk-PYCTWI2I.js.map → chunk-CUS7WGZT.js.map} +0 -0
- /package/dist/{chunk-EXPIKLUN.js.map → chunk-FZ7VHFL5.js.map} +0 -0
- /package/dist/{chunk-RWSCQMLD.js.map → chunk-HE4PDESB.js.map} +0 -0
- /package/dist/{chunk-HMDM5MCR.js.map → chunk-HVPRCHRG.js.map} +0 -0
- /package/dist/{chunk-S337S2M7.js.map → chunk-IOPAWHKW.js.map} +0 -0
- /package/dist/{chunk-Y6POV2X5.js.map → chunk-MVLNVMWI.js.map} +0 -0
- /package/dist/{chunk-HQJW3BC5.js.map → chunk-N4IWNCH3.js.map} +0 -0
- /package/dist/{chunk-MWLX3QCD.js.map → chunk-NWNVHL57.js.map} +0 -0
- /package/dist/{chunk-5UO6BBDG.js.map → chunk-OLUAEBHJ.js.map} +0 -0
- /package/dist/{chunk-XO55WKCX.js.map → chunk-Q57GZPDA.js.map} +0 -0
- /package/dist/{chunk-TXFIMVVF.js.map → chunk-UXTAK5WD.js.map} +0 -0
- /package/dist/{chunk-GSFB46YC.js.map → chunk-WTFNEPJ7.js.map} +0 -0
- /package/dist/{chunk-EEZI2K7S.js.map → chunk-XHUOWYNY.js.map} +0 -0
- /package/dist/{chunk-N57ES35J.js.map → chunk-ZBKKOUNJ.js.map} +0 -0
- /package/dist/{client-526OCGWD.js.map → client-ZX7AY7H3.js.map} +0 -0
- /package/dist/{config-HCJ5NZW5.js.map → config-BXOS2PLC.js.map} +0 -0
- /package/dist/{config-mutator-PGR2OGWC.js.map → config-mutator-KRAUD3CA.js.map} +0 -0
- /package/dist/{doctor-AC5ONEO2.js.map → doctor-P3QQP33C.js.map} +0 -0
- /package/dist/{promote-CNKIINYK.js.map → promote-FHX4Q62Z.js.map} +0 -0
- /package/dist/{query-A2N2LIR7.js.map → query-WBK3YEPV.js.map} +0 -0
- /package/dist/{registry-REKWHOHS.js.map → registry-NQHC7ZAV.js.map} +0 -0
- /package/dist/{request-planner-MS5BS6HY.js.map → request-planner-3LA5RAKG.js.map} +0 -0
- /package/dist/{review-candidates-2F4QK6QQ.js.map → review-candidates-QV66TOCL.js.map} +0 -0
- /package/dist/{routing-SU5Q4IPM.js.map → routing-HF4XVD4Y.js.map} +0 -0
- /package/dist/{schedule-tool-24KHZY2Z.js.map → schedule-tool-V66FX5XL.js.map} +0 -0
- /package/dist/{scheduler-ALDZOUKJ.js.map → scheduler-XVMWASQR.js.map} +0 -0
- /package/dist/{seat-PZBFMYQL.js.map → seat-NQTZUIKH.js.map} +0 -0
- /package/dist/{select-D3XOFXA5.js.map → select-3GVC5RDA.js.map} +0 -0
- /package/dist/{set-enabled-DNDRQ3CZ.js.map → set-enabled-SXCE2MZX.js.map} +0 -0
- /package/dist/{tool-FB6SPVIS.js.map → tool-23GOQNUW.js.map} +0 -0
- /package/dist/{tool-RRGOHJW6.js.map → tool-E6JBENAN.js.map} +0 -0
- /package/dist/{wiki-3DH2QYTX.js.map → wiki-VM2RTHVF.js.map} +0 -0
|
@@ -72,6 +72,8 @@ final class CharacterHost {
|
|
|
72
72
|
/// Sent somewhere, and what its bubble says there (#562).
|
|
73
73
|
var sent: Bool { guide.showing != nil }
|
|
74
74
|
var caption: String? { guide.caption }
|
|
75
|
+
/// The state it was asked to show by name (#570), there or where it rests.
|
|
76
|
+
private var asked: CharacterMath.Mood?
|
|
75
77
|
/// Told when it is sent somewhere, to its next stop or back.
|
|
76
78
|
var onGuide: (() -> Void)?
|
|
77
79
|
/// A still picture: Reduce Motion, or "Animated orb" off.
|
|
@@ -136,6 +138,10 @@ final class CharacterHost {
|
|
|
136
138
|
|
|
137
139
|
/// `voice.stroll`: a slow walk now and then while it has nothing to do.
|
|
138
140
|
var strolls = false
|
|
141
|
+
/// `voice.animations` as the wait between two small animations by
|
|
142
|
+
/// itself (`IdlePlay.gap`), and AgentX's own hold, which stops them.
|
|
143
|
+
var animates = 0.0
|
|
144
|
+
private var quiet = false
|
|
139
145
|
|
|
140
146
|
/// "Animated orb" in the menu.
|
|
141
147
|
func setAnimated(_ on: Bool) {
|
|
@@ -151,8 +157,10 @@ final class CharacterHost {
|
|
|
151
157
|
redraw()
|
|
152
158
|
}
|
|
153
159
|
|
|
154
|
-
/// Go beside `rect` and mark it, or with nil go back to where it
|
|
155
|
-
|
|
160
|
+
/// Go beside `rect` and mark it, or with nil go back to where it
|
|
161
|
+
/// rests; in the state `asked`, or with nil its real one.
|
|
162
|
+
func guide(to rect: NSRect?, mark kind: GuideMath.Mark = .none, caption: String? = nil, asked mood: CharacterMath.Mood? = nil) {
|
|
163
|
+
asked = shown && !hidden ? mood : nil
|
|
156
164
|
if shown, !hidden, carried == nil, let rect {
|
|
157
165
|
guide.show(rect, kind, caption: caption, color: view.stops[2], animated: !still)
|
|
158
166
|
} else {
|
|
@@ -239,10 +247,13 @@ final class CharacterHost {
|
|
|
239
247
|
|
|
240
248
|
let frame: CharacterSim.Frame
|
|
241
249
|
if still {
|
|
242
|
-
frame = CharacterSim.still(activity, home: home)
|
|
250
|
+
frame = CharacterSim.still(activity, asked: asked, sent: guide.showing != nil, home: home)
|
|
243
251
|
} else {
|
|
244
252
|
if activity == .listening, let read = levelSource {
|
|
245
253
|
level = OrbMath.smooth(level, toward: OrbMath.level(fromRMS: read()))
|
|
254
|
+
} else if asked == .listening {
|
|
255
|
+
// Asked to listen, there is no microphone to follow: a slow swell.
|
|
256
|
+
level = 0.45 + 0.3 * sin(now * 5)
|
|
246
257
|
} else {
|
|
247
258
|
level = 0
|
|
248
259
|
}
|
|
@@ -259,11 +270,12 @@ final class CharacterHost {
|
|
|
259
270
|
edgesRead = now
|
|
260
271
|
// The window list counts down from the top of the main screen.
|
|
261
272
|
let top = first.frame.maxY - rest.y
|
|
273
|
+
quiet = animates > 0 && Hold.isOn
|
|
262
274
|
edges = strolls && Config.playMode ? Meets.edges(of: Meets.windows(), band: (top - Self.head)...top) : []
|
|
263
275
|
}
|
|
264
276
|
frame = sim.step(to: now,
|
|
265
|
-
CharacterSim.Input(activity: activity, level: level, pointer: pointer, held: held, sent: guide.showing != nil, strolls: strolls,
|
|
266
|
-
edges: edges, shows: bubbleShows?() ?? false, plays: Config.playMode, down: NSEvent.pressedMouseButtons & 1 != 0,
|
|
277
|
+
CharacterSim.Input(activity: activity, level: level, pointer: pointer, held: held, sent: guide.showing != nil, asked: asked, strolls: strolls,
|
|
278
|
+
edges: edges, shows: bubbleShows?() ?? false, plays: Config.playMode, animates: quiet ? 0 : animates, down: NSEvent.pressedMouseButtons & 1 != 0,
|
|
267
279
|
home: home, range: Double(spot.ends.lowerBound)...Double(spot.ends.upperBound)))
|
|
268
280
|
}
|
|
269
281
|
let origin = NSPoint(x: (CGFloat(frame.x) - Self.size.width / 2).rounded(), y: (rest.y - Self.ground).rounded())
|
|
@@ -31,6 +31,19 @@ enum CharacterMath {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/// The state shown when one was asked for by name, or it was sent to
|
|
35
|
+
/// show something (#570). Someone talking, a ringing call and a call
|
|
36
|
+
/// between turns always show: the real turn comes first. Otherwise
|
|
37
|
+
/// the state asked for; and sent somewhere with none asked for, it
|
|
38
|
+
/// does not take the busy look, which would hide the move.
|
|
39
|
+
static func mood(for activity: Activity, asked: Mood?, sent: Bool) -> Mood {
|
|
40
|
+
switch activity {
|
|
41
|
+
case .listening, .ringing, .waiting: return mood(for: activity)
|
|
42
|
+
case .thinking: return asked ?? (sent ? .idle : .working)
|
|
43
|
+
case .idle, .speaking: return asked ?? mood(for: activity)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
34
47
|
/// The state it goes through on the way from `from` to `to`, if any:
|
|
35
48
|
/// it notices you before it listens and when it wakes, and nods once
|
|
36
49
|
/// it has heard you.
|
|
@@ -44,6 +44,8 @@ struct CharacterSim {
|
|
|
44
44
|
private var met: Double?
|
|
45
45
|
/// Its games with the pointer, and the crouch and hop they give it.
|
|
46
46
|
private(set) var play = PointerPlay()
|
|
47
|
+
/// Its small animations by itself (#571).
|
|
48
|
+
private(set) var idle = IdlePlay()
|
|
47
49
|
private var crouch = 0.0, hop = 0.0
|
|
48
50
|
private var face = 0.0, lean = 0.0
|
|
49
51
|
private var glance = (x: 0.0, y: 0.0)
|
|
@@ -117,8 +119,8 @@ struct CharacterSim {
|
|
|
117
119
|
|
|
118
120
|
// Which state. A change starts from the pose it has now, so a
|
|
119
121
|
// change in the middle of another is still one smooth move.
|
|
120
|
-
if input.activity != .idle { restSince = now }
|
|
121
|
-
var want = M.mood(for: input.activity)
|
|
122
|
+
if input.activity != .idle || input.asked != nil { restSince = now }
|
|
123
|
+
var want = M.mood(for: input.activity, asked: input.asked, sent: input.sent)
|
|
122
124
|
if want == .idle && now - restSince >= Self.dozeAfter { want = .dozing }
|
|
123
125
|
if want != goal {
|
|
124
126
|
goal = want
|
|
@@ -130,6 +132,10 @@ struct CharacterSim {
|
|
|
130
132
|
}
|
|
131
133
|
if let at = pending, now >= at { pending = nil; go(goal, now) }
|
|
132
134
|
var pose = change.pose(at: now)
|
|
135
|
+
// Idle, left alone and standing: a small animation now and then.
|
|
136
|
+
let alone = mood == .idle && input.activity == .idle && input.asked == nil && !input.sent && !input.held && !input.shows
|
|
137
|
+
&& !near && game == PointerPlay.Out() && play.game == nil && abs(speed) < 40 && strolled == 0 && strollTo == 0
|
|
138
|
+
let own = idle.step(now, dt, free: alone, gap: input.animates, dozeIn: restSince + Self.dozeAfter - now)
|
|
133
139
|
|
|
134
140
|
// Along the edge: a spring a little short of critical, so it
|
|
135
141
|
// arrives with a small overshoot.
|
|
@@ -144,11 +150,11 @@ struct CharacterSim {
|
|
|
144
150
|
let stopped = strollTo != 0 && abs(strollTo - strolled) < 0.5 ? met : nil
|
|
145
151
|
let turned = stopped.map { $0 > x ? 0.7 : -0.7 } ?? 0
|
|
146
152
|
toward(&face, min(max(speed / 200 + turned, -1), 1), 10)
|
|
147
|
-
toward(&lean, min(max(speed / 480, -1), 1) * 13, 8)
|
|
153
|
+
toward(&lean, min(max(speed / 480, -1), 1) * 13 + own.tilt, 8)
|
|
148
154
|
// A game's crouch and hop are followed, not taken at once, so a
|
|
149
155
|
// game cut short by work does not snap.
|
|
150
|
-
toward(&crouch, game.crouch, 20)
|
|
151
|
-
toward(&hop, game.hop, 20)
|
|
156
|
+
toward(&crouch, game.crouch + own.crouch, 20)
|
|
157
|
+
toward(&hop, game.hop + own.hop, 20)
|
|
152
158
|
pose.sx *= 1 + 0.14 * crouch
|
|
153
159
|
pose.sy *= 1 - 0.22 * crouch
|
|
154
160
|
pose.lift += hop - 8 * crouch
|
|
@@ -180,8 +186,8 @@ struct CharacterSim {
|
|
|
180
186
|
look = (dx / far * pull, dy / far * pull)
|
|
181
187
|
}
|
|
182
188
|
if stopped != nil { look = (turned * 5, -2) }
|
|
183
|
-
toward(&glance.x, look.x + face * 2, 9)
|
|
184
|
-
toward(&glance.y, look.y, 9)
|
|
189
|
+
toward(&glance.x, look.x + face * 2 + own.gx, 9)
|
|
190
|
+
toward(&glance.y, look.y + own.gy, 9)
|
|
185
191
|
|
|
186
192
|
// What keeps it alive: breath, bob, blinks, and the voice.
|
|
187
193
|
let t = now - (began ?? now)
|
|
@@ -201,6 +207,7 @@ struct CharacterSim {
|
|
|
201
207
|
nextBlink = now + 2.2 + 4.5 * M.rnd(blinks) // uneven, never the same loop twice
|
|
202
208
|
}
|
|
203
209
|
if now >= nextBlink { pose.open *= 1 - sin(.pi * (now - nextBlink) / Self.blink) }
|
|
210
|
+
pose.open *= 1 - own.shut
|
|
204
211
|
|
|
205
212
|
return Frame(pose: pose, x: x, face: face, level: input.level, voice: voice, t: t,
|
|
206
213
|
dots: dots.compactMap { dot(at: now, $0) }, stars: bursts.flatMap { stars(at: now, $0) })
|
|
@@ -248,15 +255,6 @@ struct CharacterSim {
|
|
|
248
255
|
strolled = 0; strollTo = 0; strollNext = nil
|
|
249
256
|
}
|
|
250
257
|
|
|
251
|
-
/// The state alone, where it rests: for Reduce Motion, which shows a
|
|
252
|
-
/// still picture that changes between states and never a loop.
|
|
253
|
-
static func still(_ activity: M.Activity, home: Double) -> Frame {
|
|
254
|
-
// Its marks at full strength, so each state reads without motion:
|
|
255
|
-
// the arcs of its voice only while it speaks.
|
|
256
|
-
let pose = M.pose(M.mood(for: activity))
|
|
257
|
-
return Frame(pose: pose, x: home, level: 1, voice: pose.speak)
|
|
258
|
-
}
|
|
259
|
-
|
|
260
258
|
private mutating func go(_ to: M.Mood, _ now: Double) {
|
|
261
259
|
change = M.Transition(from: change.pose(at: now), to: M.pose(to), start: now, duration: M.duration(into: to))
|
|
262
260
|
mood = to
|
|
@@ -15,6 +15,9 @@ extension CharacterSim {
|
|
|
15
15
|
/// The answering agent sent it to show something (#482): it goes
|
|
16
16
|
/// to `home` at once, awake, whatever the pointer did before.
|
|
17
17
|
var sent = false
|
|
18
|
+
/// The state it was asked to show by name (#570), in place of
|
|
19
|
+
/// what the assistant is doing.
|
|
20
|
+
var asked: M.Mood?
|
|
18
21
|
/// `voice.stroll`: with nothing to do, it takes a slow stroll
|
|
19
22
|
/// beside where it rests now and then (#482).
|
|
20
23
|
var strolls = false
|
|
@@ -26,6 +29,9 @@ extension CharacterSim {
|
|
|
26
29
|
var shows = false
|
|
27
30
|
/// "Play mode" is ticked: idle, it plays with the pointer (#505).
|
|
28
31
|
var plays = false
|
|
32
|
+
/// `voice.animations`: the shortest wait between two small
|
|
33
|
+
/// animations by itself, in seconds (#571). 0: none.
|
|
34
|
+
var animates = 0.0
|
|
29
35
|
/// The mouse button is down.
|
|
30
36
|
var down = false
|
|
31
37
|
/// Where it rests, and how far it may go.
|
|
@@ -56,4 +62,13 @@ extension CharacterSim {
|
|
|
56
62
|
var dots: [Mark] = []
|
|
57
63
|
var stars: [Mark] = []
|
|
58
64
|
}
|
|
65
|
+
|
|
66
|
+
/// The state alone, where it rests: for Reduce Motion, which shows a
|
|
67
|
+
/// still picture that changes between states and never a loop.
|
|
68
|
+
static func still(_ activity: M.Activity, asked: M.Mood? = nil, sent: Bool = false, home: Double) -> Frame {
|
|
69
|
+
// Its marks at full strength, so each state reads without motion:
|
|
70
|
+
// the arcs of its voice only while it speaks.
|
|
71
|
+
let pose = M.pose(M.mood(for: activity, asked: asked, sent: sent))
|
|
72
|
+
return Frame(pose: pose, x: home, level: 1, voice: pose.speak)
|
|
73
|
+
}
|
|
59
74
|
}
|
|
@@ -13,6 +13,9 @@ enum GuideClient {
|
|
|
13
13
|
/// What its bubble says at the stop (#562). Nil: no bubble there,
|
|
14
14
|
/// and a daemon too old to send one.
|
|
15
15
|
let text: String?
|
|
16
|
+
/// The state it shows meanwhile (#570). Nil: its real state, and
|
|
17
|
+
/// a daemon too old to send one.
|
|
18
|
+
let expression: String?
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
/// GET /voice/guide: the command after `seq`, as soon as there is
|
|
@@ -37,8 +40,9 @@ final class GuideWatcher {
|
|
|
37
40
|
private var task: Task<Void, Never>?
|
|
38
41
|
/// The character is on screen.
|
|
39
42
|
var wanted: (() -> Bool)?
|
|
40
|
-
/// Show this, in AppKit coordinates, with this caption
|
|
41
|
-
|
|
43
|
+
/// Show this, in AppKit coordinates, with this caption and in this
|
|
44
|
+
/// state, or go home.
|
|
45
|
+
var onCommand: ((NSRect?, GuideMath.Mark, String?, CharacterMath.Mood?) -> Void)?
|
|
42
46
|
|
|
43
47
|
/// (Re)start the wait. Called again when the character comes on screen
|
|
44
48
|
/// or leaves it, so a wait already open is ended: cancelling it closes
|
|
@@ -56,7 +60,7 @@ final class GuideWatcher {
|
|
|
56
60
|
private func turn() async {
|
|
57
61
|
guard wanted?() == true, let command = await GuideClient.next(after: seq) else {
|
|
58
62
|
// Hidden, or the daemon is gone: nothing is left on screen.
|
|
59
|
-
if away { away = false; onCommand?(nil, .none, nil) }
|
|
63
|
+
if away { away = false; onCommand?(nil, .none, nil, nil) }
|
|
60
64
|
try? await Task.sleep(nanoseconds: 2_000_000_000)
|
|
61
65
|
return
|
|
62
66
|
}
|
|
@@ -66,9 +70,10 @@ final class GuideWatcher {
|
|
|
66
70
|
GuideMath.toAppKit(CGRect(x: $0.x, y: $0.y, width: $0.width, height: $0.height),
|
|
67
71
|
primaryHeight: NSScreen.screens.first?.frame.maxY ?? 0)
|
|
68
72
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
let asked = command.expression.flatMap { CharacterMath.Mood(rawValue: $0) }
|
|
74
|
+
away = rect != nil || asked != nil
|
|
75
|
+
Log.info("guide: \(rect.map { "to \(Int($0.minX)),\(Int($0.minY)) \(Int($0.width))x\(Int($0.height)) \(command.mark)" } ?? "home")\(asked.map { ", \($0.rawValue)" } ?? "")")
|
|
76
|
+
onCommand?(rect, GuideMath.Mark(rawValue: command.mark) ?? .box, rect == nil ? nil : command.text, asked)
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
|
|
@@ -46,9 +46,21 @@ enum GuideMath {
|
|
|
46
46
|
/// At a stop the bubble says the command's caption, and with none
|
|
47
47
|
/// there is no bubble; the idle hint is for where it rests, not for
|
|
48
48
|
/// a stop, the way there or a play. `away`: sent somewhere, or playing.
|
|
49
|
-
|
|
49
|
+
/// `hint`: the hint may show (hintShows).
|
|
50
|
+
static func idle(caption: String?, away: Bool, hint: Bool = true) -> Idle {
|
|
50
51
|
if let caption, !caption.isEmpty { return .caption(caption) }
|
|
51
|
-
return away ? .nothing : .hint
|
|
52
|
+
return away || !hint ? .nothing : .hint
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// Seconds after the app starts that the character's bubble says the hint.
|
|
56
|
+
static let hintSeconds = 6.0
|
|
57
|
+
|
|
58
|
+
/// Whether the idle hint may show (#576). A pill of its own always
|
|
59
|
+
/// says it. The character's bubble says it only for the first seconds
|
|
60
|
+
/// after the app starts, then there is no bubble at idle; "notifications
|
|
61
|
+
/// held" stays, since nothing else on screen says it.
|
|
62
|
+
static func hintShows(character: Bool, sinceStart: Double, held: Bool) -> Bool {
|
|
63
|
+
!character || held || sinceStart < hintSeconds
|
|
52
64
|
}
|
|
53
65
|
|
|
54
66
|
/// What a label needs beyond the width of its words (#569): a text
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Small animations by itself (#571): idle and left alone, the character
|
|
4
|
+
/// now and then looks around, hops or sways, just for the fun of it, and
|
|
5
|
+
/// stretches with a yawn before it dozes. `voice.animations` says how
|
|
6
|
+
/// often, or not at all.
|
|
7
|
+
///
|
|
8
|
+
/// It only decides what an animation adds to the pose; `CharacterSim`
|
|
9
|
+
/// follows it, so one cut short by work does not snap. Foundation only,
|
|
10
|
+
/// and the same animations in the same order on every run, so the tests
|
|
11
|
+
/// can count on them.
|
|
12
|
+
struct IdlePlay {
|
|
13
|
+
typealias M = CharacterMath
|
|
14
|
+
|
|
15
|
+
/// The animations, by name. The yawn comes before it dozes; the
|
|
16
|
+
/// others are picked now and then.
|
|
17
|
+
enum Act: String, CaseIterable { case look, hop, sway, yawn }
|
|
18
|
+
|
|
19
|
+
/// `voice.animations` as the shortest wait between two, in seconds.
|
|
20
|
+
/// The wait is up to twice that. 0: none.
|
|
21
|
+
static func gap(_ often: String?) -> Double {
|
|
22
|
+
switch often {
|
|
23
|
+
case "rarely": return 60
|
|
24
|
+
case "sometimes": return 25
|
|
25
|
+
case "often": return 10
|
|
26
|
+
default: return 0
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// Seconds an animation takes.
|
|
31
|
+
static func length(_ act: Act) -> Double {
|
|
32
|
+
switch act {
|
|
33
|
+
case .look, .yawn: return 2.6
|
|
34
|
+
case .hop: return 0.9
|
|
35
|
+
case .sway: return 1.8
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// This close to dozing, in seconds, no animation starts but the yawn.
|
|
40
|
+
static let calm = 6.0
|
|
41
|
+
|
|
42
|
+
/// What an animation adds to the pose: gaze and height in drawing
|
|
43
|
+
/// units, lean in degrees, 0…1 crouched (below 0: stretched tall) and
|
|
44
|
+
/// 0…1 how far the eyes are shut.
|
|
45
|
+
struct Out: Equatable {
|
|
46
|
+
var gx = 0.0, gy = 0.0, tilt = 0.0, hop = 0.0, crouch = 0.0, shut = 0.0
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private(set) var act: Act?
|
|
50
|
+
private(set) var played = 0
|
|
51
|
+
private var began = 0.0
|
|
52
|
+
private var next: Double?
|
|
53
|
+
private var yawned = false
|
|
54
|
+
private var turn = 0
|
|
55
|
+
private var shut = 0.0
|
|
56
|
+
|
|
57
|
+
/// One frame. `free`: idle, left alone and standing where it is.
|
|
58
|
+
/// `dozeIn`: seconds until it dozes.
|
|
59
|
+
mutating func step(_ now: Double, _ dt: Double, free: Bool, gap: Double, dozeIn: Double) -> Out {
|
|
60
|
+
var out = Out()
|
|
61
|
+
if !free || gap <= 0 {
|
|
62
|
+
act = nil; next = nil
|
|
63
|
+
} else {
|
|
64
|
+
if dozeIn > Self.calm { yawned = false }
|
|
65
|
+
if let on = act, now - began >= Self.length(on) { act = nil; next = nil }
|
|
66
|
+
if act == nil {
|
|
67
|
+
if !yawned && dozeIn <= Self.length(.yawn) {
|
|
68
|
+
yawned = true
|
|
69
|
+
start(.yawn, now)
|
|
70
|
+
} else if next == nil {
|
|
71
|
+
next = now + gap * (1 + M.rnd(played, 5))
|
|
72
|
+
} else if now >= next!, dozeIn > Self.calm {
|
|
73
|
+
// One of the other two, so the same never comes twice.
|
|
74
|
+
turn = (turn + 1 + min(Int(M.rnd(played, 6) * 2), 1)) % 3
|
|
75
|
+
start([Act.look, .hop, .sway][turn], now)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if let on = act { out = Self.shape(on, (now - began) / Self.length(on)) }
|
|
79
|
+
}
|
|
80
|
+
// The eyes are followed here; the rest by the sim.
|
|
81
|
+
shut += (out.shut - shut) * (1 - exp(-dt * 20))
|
|
82
|
+
out.shut = shut
|
|
83
|
+
return out
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// Play `act` now, whatever the wait.
|
|
87
|
+
mutating func start(_ act: Act, _ now: Double) {
|
|
88
|
+
self.act = act
|
|
89
|
+
began = now
|
|
90
|
+
played += 1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// An animation `p` of the way through, 0…1. Each starts and ends at
|
|
94
|
+
/// nothing, so it joins the resting pose at both ends.
|
|
95
|
+
static func shape(_ act: Act, _ p: Double) -> Out {
|
|
96
|
+
switch act {
|
|
97
|
+
case .look:
|
|
98
|
+
// To one side, to the other, and back.
|
|
99
|
+
return Out(gx: 8 * sin(2 * .pi * p), gy: -1.5 * sin(.pi * p))
|
|
100
|
+
case .hop:
|
|
101
|
+
// A short crouch, then up and down again.
|
|
102
|
+
return Out(hop: 26 * sin(.pi * M.span(p, 0.3, 1)),
|
|
103
|
+
crouch: 0.7 * M.ease(p / 0.3) * (1 - M.ease(M.span(p, 0.3, 0.5))))
|
|
104
|
+
case .sway:
|
|
105
|
+
// Two swings from side to side, the widest in the middle.
|
|
106
|
+
return Out(tilt: 10 * sin(4 * .pi * p) * sin(.pi * p))
|
|
107
|
+
case .yawn:
|
|
108
|
+
// It stretches tall, looks up, and shuts its eyes a moment.
|
|
109
|
+
return Out(gy: -2 * sin(.pi * p), crouch: -0.8 * sin(.pi * M.span(p, 0, 0.8)),
|
|
110
|
+
shut: M.ease(M.span(p, 0.15, 0.4)) * (1 - M.ease(M.span(p, 0.75, 1))))
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -59,6 +59,8 @@ struct LookSection: View {
|
|
|
59
59
|
var startReduced: Binding<Bool>?
|
|
60
60
|
/// Nil hides the control: the daemon is older than the stroll.
|
|
61
61
|
var stroll: Binding<Bool>?
|
|
62
|
+
/// Nil hides the control: the daemon is older than the animations.
|
|
63
|
+
var animations: Binding<String>?
|
|
62
64
|
|
|
63
65
|
var body: some View {
|
|
64
66
|
Section {
|
|
@@ -74,6 +76,15 @@ struct LookSection: View {
|
|
|
74
76
|
Toggle("Character strolls when idle", isOn: stroll)
|
|
75
77
|
.disabled(look != "character")
|
|
76
78
|
}
|
|
79
|
+
if let animations {
|
|
80
|
+
Picker("Character plays when idle", selection: animations) {
|
|
81
|
+
Text("Never").tag("off")
|
|
82
|
+
Text("Rarely").tag("rarely")
|
|
83
|
+
Text("Sometimes").tag("sometimes")
|
|
84
|
+
Text("Often").tag("often")
|
|
85
|
+
}
|
|
86
|
+
.disabled(look != "character")
|
|
87
|
+
}
|
|
77
88
|
} header: {
|
|
78
89
|
Text("Assistant")
|
|
79
90
|
} footer: {
|
|
@@ -381,7 +381,10 @@ private struct GeneralTab: View {
|
|
|
381
381
|
set: { model.draft?.general.startReduced = $0 }),
|
|
382
382
|
stroll: draft.general.stroll == nil ? nil
|
|
383
383
|
: Binding(get: { model.draft?.general.stroll ?? false },
|
|
384
|
-
set: { model.draft?.general.stroll = $0 })
|
|
384
|
+
set: { model.draft?.general.stroll = $0 }),
|
|
385
|
+
animations: draft.general.animations == nil ? nil
|
|
386
|
+
: Binding(get: { model.draft?.general.animations ?? "off" },
|
|
387
|
+
set: { model.draft?.general.animations = $0 }))
|
|
385
388
|
}
|
|
386
389
|
if draft.general.card != nil {
|
|
387
390
|
AnswerCardSection(card: Binding(get: { model.draft?.general.card ?? .standard },
|
|
@@ -35,14 +35,18 @@ struct VoiceSettings: Codable, Equatable {
|
|
|
35
35
|
/// The character takes a stroll when it has nothing to do. Nil
|
|
36
36
|
/// from a daemon older than the stroll.
|
|
37
37
|
var stroll: Bool?
|
|
38
|
+
/// How often the character plays a small animation by itself:
|
|
39
|
+
/// "off", "rarely", "sometimes" or "often". Nil from a daemon
|
|
40
|
+
/// older than the animations.
|
|
41
|
+
var animations: String?
|
|
38
42
|
|
|
39
43
|
init(provider: String, fallback: String, stt: String, localStt: String = "mlx-whisper",
|
|
40
44
|
endOfTurn: String = "vad", hotkeys: Hotkeys, card: Card? = nil, look: String? = nil,
|
|
41
|
-
startReduced: Bool? = nil, stroll: Bool? = nil) {
|
|
45
|
+
startReduced: Bool? = nil, stroll: Bool? = nil, animations: String? = nil) {
|
|
42
46
|
self.provider = provider; self.fallback = fallback; self.stt = stt
|
|
43
47
|
self.localStt = localStt; self.endOfTurn = endOfTurn; self.hotkeys = hotkeys
|
|
44
48
|
self.card = card; self.look = look; self.startReduced = startReduced
|
|
45
|
-
self.stroll = stroll
|
|
49
|
+
self.stroll = stroll; self.animations = animations
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
/// A daemon from before these fields leaves them out: the defaults.
|
|
@@ -58,6 +62,7 @@ struct VoiceSettings: Codable, Equatable {
|
|
|
58
62
|
look = try c.decodeIfPresent(String.self, forKey: .look)
|
|
59
63
|
startReduced = try c.decodeIfPresent(Bool.self, forKey: .startReduced)
|
|
60
64
|
stroll = try c.decodeIfPresent(Bool.self, forKey: .stroll)
|
|
65
|
+
animations = try c.decodeIfPresent(String.self, forKey: .animations)
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
struct Voice: Codable, Equatable {
|
|
@@ -119,6 +124,7 @@ struct VoiceSettings: Codable, Equatable {
|
|
|
119
124
|
if let look = self.general.look, look != old.general.look { general["look"] = look }
|
|
120
125
|
if let start = self.general.startReduced, start != old.general.startReduced { general["startReduced"] = start }
|
|
121
126
|
if let stroll = self.general.stroll, stroll != old.general.stroll { general["stroll"] = stroll }
|
|
127
|
+
if let often = self.general.animations, often != old.general.animations { general["animations"] = often }
|
|
122
128
|
var keys: [String: Any] = [:]
|
|
123
129
|
if self.general.hotkeys.talk != old.general.hotkeys.talk { keys["talk"] = self.general.hotkeys.talk }
|
|
124
130
|
if self.general.hotkeys.stop != old.general.hotkeys.stop { keys["stop"] = self.general.hotkeys.stop }
|
|
@@ -88,6 +88,8 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
88
88
|
private let guideWatcher = GuideWatcher()
|
|
89
89
|
/// A play runs, or its picture is being taken (#562).
|
|
90
90
|
private var playing = false
|
|
91
|
+
/// When the app started, for the hint in the character's bubble.
|
|
92
|
+
private let launched = ProcessInfo.processInfo.systemUptime
|
|
91
93
|
private let ringer = Ringer()
|
|
92
94
|
/// The call ringing on the pill now.
|
|
93
95
|
private var ringingCall: IncomingCall?
|
|
@@ -218,7 +220,9 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
218
220
|
panel.setShowsOrb(!asCharacter)
|
|
219
221
|
character.setShown(asCharacter)
|
|
220
222
|
character.strolls = saved.general.stroll == true
|
|
223
|
+
character.animates = IdlePlay.gap(saved.general.animations)
|
|
221
224
|
if !asCharacter { panel.detach() }
|
|
225
|
+
idleWords()
|
|
222
226
|
// voice.startReduced is how the assistant starts: read once.
|
|
223
227
|
if !startApplied {
|
|
224
228
|
startApplied = true
|
|
@@ -240,8 +244,12 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
240
244
|
|
|
241
245
|
/// What the idle bubble says (#562): no hint at a guide stop, on the
|
|
242
246
|
/// way there or during a play; the stop's caption if it has one.
|
|
247
|
+
/// The character's bubble says the hint only just after the app
|
|
248
|
+
/// starts, then there is none at idle (#576).
|
|
243
249
|
private func idleWords() {
|
|
244
|
-
|
|
250
|
+
let hint = GuideMath.hintShows(character: settings?.general.look == "character",
|
|
251
|
+
sinceStart: ProcessInfo.processInfo.systemUptime - launched, held: Hold.isOn)
|
|
252
|
+
panel.setIdle(GuideMath.idle(caption: character.caption, away: character.sent || playing, hint: hint))
|
|
245
253
|
}
|
|
246
254
|
|
|
247
255
|
/// "Play on this page" (#505): one picture of the character's screen, the
|
|
@@ -507,6 +515,7 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
507
515
|
// and this switch is not that.
|
|
508
516
|
statusMenu.onHoldChanged = { [weak self] nowOn in
|
|
509
517
|
guard let self else { return }
|
|
518
|
+
self.idleWords()
|
|
510
519
|
self.panel.render(.idle)
|
|
511
520
|
if !nowOn { Hold.flushHeld() }
|
|
512
521
|
Log.info(nowOn ? "notifications held" : "notifications delivering")
|
|
@@ -526,8 +535,10 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
526
535
|
callWatcher.start()
|
|
527
536
|
// The answering agent sends the character to something (#482).
|
|
528
537
|
guideWatcher.wanted = { [weak self] in self?.character.onScreen == true }
|
|
529
|
-
guideWatcher.onCommand = { [weak self] rect, mark, caption in self?.character.guide(to: rect, mark: mark, caption: caption) }
|
|
538
|
+
guideWatcher.onCommand = { [weak self] rect, mark, caption, asked in self?.character.guide(to: rect, mark: mark, caption: caption, asked: asked) }
|
|
530
539
|
character.onGuide = { [weak self] in self?.idleWords() }
|
|
540
|
+
// The hint has had its seconds: no bubble at idle from here.
|
|
541
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + GuideMath.hintSeconds) { [weak self] in self?.idleWords() }
|
|
531
542
|
guideWatcher.start()
|
|
532
543
|
character.onScreenChanged = { [weak self] in self?.guideWatcher.start() }
|
|
533
544
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{a as F,b as L,c as U,d as N,e as O,f as H,g as j}from"./chunk-U2CKL755.js";import{b as B,c as D,d as A,e as P,g as M}from"./chunk-
|
|
1
|
+
import{a as F,b as L,c as U,d as N,e as O,f as H,g as j}from"./chunk-U2CKL755.js";import{b as B,c as D,d as A,e as P,g as M}from"./chunk-CUS7WGZT.js";import"./chunk-IA3BC7M3.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useEffect as R,useReducer as V,useRef as G}from"react";import{Box as i,Text as o,useApp as W,useInput as J}from"ink";import{randomUUID as z}from"crypto";async function*q(e){let r=[];e.type&&r.push(`type=${encodeURIComponent(e.type)}`);let t=`${e.baseUrl.replace(/\/+$/,"")}/events${r.length?`?${r.join("&")}`:""}`,n={Accept:"text/event-stream"};e.token&&(n.Authorization=`Bearer ${e.token}`);let s=await fetch(t,{headers:n,signal:e.signal});if(!s.ok||!s.body)throw new Error(`SSE connect failed: HTTP ${s.status}`);let u=s.body.getReader(),p=new TextDecoder,y="";try{for(;;){let{done:f,value:l}=await u.read();if(f)return;y+=p.decode(l,{stream:!0});let d;for(;(d=y.indexOf(`
|
|
2
2
|
|
|
3
3
|
`))>=0;){let h=y.slice(0,d);y=y.slice(d+2);let m=X(h);m&&(yield m)}}}finally{try{u.releaseLock()}catch{}}}function X(e){let r="message",t="";for(let s of e.split(`
|
|
4
4
|
`))s.startsWith("event: ")?r=s.slice(7):s.startsWith("data: ")&&(t=s.slice(6));if(!t)return null;let n;try{n=JSON.parse(t)}catch{n=t}return{event:r,data:n}}import{jsx as a,jsxs as c}from"react/jsx-runtime";function $(e,r){return r<=0||e<0?0:e>=r?r-1:e}function E(){return`tui:${z().slice(0,12)}`}function k(e,r){let t=[...e,r];return t.length>50&&t.splice(0,t.length-50),t}function Y(e,r){switch(r.type){case"agents":return{...e,agents:r.data,cursor:{...e.cursor,agents:$(e.cursor.agents,r.data.length)}};case"processes":return{...e,processes:r.data,cursor:{...e.cursor,processes:$(e.cursor.processes,r.data.length)}};case"crons":return{...e,crons:r.data};case"event":{let t=[r.row,...e.events];t.length>200&&(t.length=200);let n=e.channels;return r.channelTally&&(n=new Map(e.channels),n.set(r.channelTally.channel,r.channelTally)),{...e,events:t,channels:n}}case"connError":return{...e,connError:r.error};case"tick":return{...e,lastTick:Date.now()};case"focus":return{...e,focus:r.pane};case"cursor":{let t=r.pane==="agents"?e.agents.length:r.pane==="processes"?e.processes.length:e.events.length;return{...e,cursor:{...e.cursor,[r.pane]:$(e.cursor[r.pane]+r.delta,t)}}}case"bottomRight":return{...e,bottomRight:r.pane};case"chatStart":return{...e,chat:{active:!0,agentId:r.agentId,chatId:E(),history:[],text:"",status:"idle",error:null}};case"chatExit":return{...e,chat:{...e.chat,active:!1}};case"chatClear":return{...e,chat:{...e.chat,chatId:E(),history:[],text:"",status:"idle",error:null}};case"chatText":return{...e,chat:{...e.chat,text:r.text}};case"chatSubmitStart":return{...e,chat:{...e.chat,history:k(e.chat.history,r.you),text:"",status:"sending",error:null}};case"chatSubmitDone":return{...e,chat:{...e.chat,history:k(e.chat.history,r.reply),status:"idle",error:null}};case"chatSubmitError":return{...e,chat:{...e.chat,history:k(e.chat.history,{role:"error",text:r.error,at:Date.now()}),status:"idle",error:r.error}};case"chatStreamStart":{let t=k(e.chat.history,r.you),n=k(t,{role:"agent",text:"",at:Date.now(),streaming:!0,tools:[]});return{...e,chat:{...e.chat,history:n,text:"",status:"sending",error:null}}}case"chatStreamDelta":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]={...n,text:n.text+r.text}),{...e,chat:{...e.chat,history:t}}}case"chatStreamThinking":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]={...n,thinking:(n.thinking??"")+r.text}),{...e,chat:{...e.chat,history:t}}}case"chatStreamTool":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]={...n,tools:[...n.tools??[],{name:r.name,arg:r.arg,error:r.error}]}),{...e,chat:{...e.chat,history:t}}}case"chatStreamEnd":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]=r.error?{...n,streaming:!1,role:"error",text:r.error}:{...n,streaming:!1,elapsedMs:r.elapsedMs,outTokens:r.outTokens}),{...e,chat:{...e.chat,history:t,status:"idle",error:r.error??null}}}case"toast":return{...e,toast:{text:r.text,color:r.color,at:Date.now()}};case"clearToast":return{...e,toast:null}}}var _={agents:[],processes:[],crons:[],events:[],channels:new Map,connError:null,lastTick:0,focus:"agents",cursor:{agents:0,processes:0,events:0},bottomRight:"crons",chat:{active:!1,agentId:null,chatId:E(),history:[],text:"",status:"idle",error:null},toast:null};function be({conn:e,pollMs:r=3e3}){let[t,n]=V(Y,_),{exit:s}=W(),u=G(null),p=G(null),y=t.agents.map(l=>l.id),f=t.chat.active?L(t.chat.text,y,process.cwd()):null;return R(()=>{if(!t.toast)return;let l=setTimeout(()=>n({type:"clearToast"}),3500);return()=>clearTimeout(l)},[t.toast]),J((l,d)=>{if(t.chat.active){if(d.escape){n({type:"chatExit"});return}if(d.ctrl&&l==="l"){n({type:"chatClear"});return}if(d.tab){let m=U(t.chat.text,p,y,process.cwd());m!==null&&n({type:"chatText",text:m});return}if(d.backspace||d.delete){p.current=null,n({type:"chatText",text:t.chat.text.slice(0,-1)});return}if(d.ctrl||d.meta)return;let h=N(l??"",d.return,t.chat.text);if(h.kind==="paste"||h.kind==="type"){p.current=null,n({type:"chatText",text:t.chat.text+h.text});return}if(h.kind==="continue"){n({type:"chatText",text:h.buffer});return}if(h.kind==="submit"){let m=h.text.trim(),g=t.chat.agentId;if(!m||!g||t.chat.status==="sending"){n({type:"chatText",text:""});return}p.current=null;let b=Date.now(),w=t.chat.chatId;n({type:"chatStreamStart",you:{role:"you",text:m,at:b}}),(async()=>{try{let C=await M(e,g,m,{channel:"tui",chatId:w,onText:x=>n({type:"chatStreamDelta",text:x}),onThinking:x=>n({type:"chatStreamThinking",text:x}),onTool:x=>{x.status==="start"&&x.name?n({type:"chatStreamTool",name:x.name,arg:x.arg}):x.status==="result"&&x.error&&n({type:"chatStreamTool",name:x.name??"tool",error:!0})}});n({type:"chatStreamEnd",elapsedMs:Date.now()-b,outTokens:C.usage?.outputTokens,error:C.error})}catch(C){n({type:"chatStreamEnd",elapsedMs:Date.now()-b,error:C?.message||String(C)})}})();return}return}if(l==="q"||d.ctrl&&l==="c"){u.current?.abort(),s();return}if(d.tab){let h=["agents","processes","events"],m=h.indexOf(t.focus);n({type:"focus",pane:h[(m+1)%h.length]});return}if(l==="a"){n({type:"focus",pane:"agents"});return}if(l==="p"){n({type:"focus",pane:"processes"});return}if(l==="e"){n({type:"focus",pane:"events"});return}if(l==="c"){n({type:"bottomRight",pane:t.bottomRight==="crons"?"channels":"crons"});return}if(d.upArrow){n({type:"cursor",pane:t.focus,delta:-1});return}if(d.downArrow){n({type:"cursor",pane:t.focus,delta:1});return}if(d.return&&t.focus==="agents"){let h=t.agents[t.cursor.agents];if(!h){n({type:"toast",text:"no agent selected",color:"yellow"});return}n({type:"chatStart",agentId:h.id});return}if(l==="k"&&t.focus==="processes"){let h=t.processes[t.cursor.processes];if(!h){n({type:"toast",text:"no process selected",color:"yellow"});return}(async()=>{try{await P(e,h.key,"tui"),n({type:"toast",text:`killed ${h.key.agentId}/${h.key.channel}/${h.key.chatId}`,color:"green"})}catch(m){n({type:"toast",text:`kill failed: ${m?.message||m}`,color:"red"})}})();return}}),R(()=>{let l=new AbortController;u.current=l;let d=!1,h=async()=>{try{let[g,b,w]=await Promise.all([B(e,l.signal).catch(()=>[]),D(e,l.signal).catch(()=>[]),A(e,l.signal).catch(()=>[])]);if(d)return;n({type:"agents",data:g}),n({type:"processes",data:b}),n({type:"crons",data:w}),n({type:"tick"}),n({type:"connError",error:null})}catch(g){d||n({type:"connError",error:g?.message||String(g)})}};h();let m=setInterval(h,r);return()=>{d=!0,clearInterval(m),l.abort()}},[e.baseUrl,e.token,r]),R(()=>{let l=!1,d=new AbortController,h=new Map;return(async()=>{let m=500;for(;!l;){try{for await(let g of q({baseUrl:e.baseUrl,token:e.token,signal:d.signal})){let b=ae(g),w;if(g.event==="channel"&&typeof g.data?.channel=="string"){let S=h.get(g.data.channel)??{channel:g.data.channel,inbound:0,outbound:0,lastAt:0,lastPreview:""},C=S.inbound+(g.data.direction==="in"?1:0),x=S.outbound+(g.data.direction==="out"?1:0);w={channel:g.data.channel,inbound:C,outbound:x,lastAt:b.at,lastPreview:(g.data.textPreview||"").slice(0,60)},h.set(g.data.channel,w)}n({type:"event",row:b,channelTally:w}),m=500}}catch(g){if(l)return;n({type:"connError",error:`events: ${g?.message||g}`})}await new Promise(g=>setTimeout(g,m)),m=Math.min(m*2,1e4)}})(),()=>{l=!0,d.abort()}},[e.baseUrl,e.token]),c(i,{flexDirection:"column",width:"100%",children:[a(K,{conn:e,lastTick:t.lastTick,connError:t.connError,chat:t.chat}),c(i,{flexDirection:"row",flexGrow:1,children:[c(i,{flexDirection:"column",width:"50%",children:[a(v,{title:"AGENTS",focused:!t.chat.active&&t.focus==="agents",children:a(Z,{rows:t.agents,cursor:t.cursor.agents,focused:!t.chat.active&&t.focus==="agents",talkingTo:t.chat.active?t.chat.agentId:null})}),a(v,{title:"PROCESSES",focused:!t.chat.active&&t.focus==="processes",children:a(ee,{rows:t.processes,cursor:t.cursor.processes,focused:!t.chat.active&&t.focus==="processes"})})]}),t.chat.active?a(oe,{chat:t.chat,suggest:f,agents:t.agents}):c(i,{flexDirection:"column",width:"50%",children:[a(v,{title:"LIVE EVENTS",focused:t.focus==="events",children:a(ne,{rows:t.events,cursor:t.cursor.events,focused:t.focus==="events"})}),a(v,{title:t.bottomRight==="crons"?"CRONS / SCHEDULES":"CHANNELS",focused:!1,children:t.bottomRight==="crons"?a(te,{rows:t.crons}):a(re,{rows:Array.from(t.channels.values())})})]})]}),a(Q,{focus:t.focus,bottomRight:t.bottomRight,chat:t.chat,toast:t.toast})]})}function K({conn:e,lastTick:r,connError:t,chat:n}){let s=t?c(o,{color:"red",children:["\u25CF ",t]}):r===0?a(o,{color:"yellow",children:"\u25CF connecting\u2026"}):a(o,{color:"green",children:"\u25CF live"}),u=n.active?c(o,{color:"green",bold:!0,children:["CHAT @",n.agentId]}):a(o,{bold:!0,children:"agentx tui"});return c(i,{paddingX:1,justifyContent:"space-between",children:[a(i,{children:u}),a(o,{dimColor:!0,children:e.baseUrl}),a(i,{children:s})]})}function Q({focus:e,bottomRight:r,chat:t,toast:n}){let s=t.active?["[Enter] send","[Esc] exit chat","[Ctrl-L] new session"]:[`[Tab/a/p/e] focus (now: ${e})`,e==="agents"?"[Enter] chat":null,e==="processes"?"[k] kill":null,`[c] ${r==="crons"?"\u2192channels":"\u2192crons"}`,"[\u2191/\u2193] move","[q] quit"].filter(Boolean);return c(i,{paddingX:1,borderStyle:"single",borderTop:!0,borderBottom:!1,borderLeft:!1,borderRight:!1,justifyContent:"space-between",children:[a(o,{dimColor:!0,children:s.join(" \xB7 ")}),n?a(o,{color:n.color,children:n.text}):a(o,{children:" "})]})}function v({title:e,focused:r,children:t}){return c(i,{flexDirection:"column",width:"100%",borderStyle:r?"double":"single",borderColor:r?"cyan":void 0,paddingX:1,children:[c(o,{bold:!0,color:r?"cyan":"white",children:[e,r?" \u25CF":""]}),a(i,{flexDirection:"column",marginTop:1,children:t})]})}function I(e,r){return e&&r?{inverse:!0}:{}}function Z({rows:e,cursor:r,focused:t,talkingTo:n}){return e.length===0?a(o,{dimColor:!0,children:"no agents"}):a(i,{flexDirection:"column",children:e.slice(0,12).map((s,u)=>{let p=I(t,u===r),y=s.errors>0?"red":s.active>0?"yellow":"green",f=s.id===n;return c(i,{children:[a(o,{...p,color:y,children:"\u25CF"}),c(o,{...p,children:[" ",T(s.name,14)]}),c(o,{...p,children:[T(s.tier,6)," "]}),c(o,{...p,children:[s.active,"/",s.total]}),s.errors>0?c(o,{...p,color:"red",children:[" err=",s.errors]}):null,f?a(o,{color:"green",children:" \u2194 chatting"}):null]},s.id)})})}function ee({rows:e,cursor:r,focused:t}){if(e.length===0)return a(o,{dimColor:!0,children:"no live processes"});let n=Date.now();return a(i,{flexDirection:"column",children:e.slice(0,12).map((s,u)=>{let p=I(t,u===r),y=Math.max(0,Math.round((n-(s.lastTurnAt||s.spawnedAt))/1e3)),f=s.state==="dead"?"red":s.state==="warm-hot"?"green":"yellow";return c(i,{children:[a(o,{...p,color:f,children:T(s.state,10)}),a(o,{...p,children:T(s.key.agentId,12)}),a(o,{...p,children:T(s.key.channel,10)}),c(o,{...p,children:[s.turnCount,"t ",y,"s"]})]},`${s.key.agentId}-${s.key.channel}-${s.key.chatId}-${u}`)})})}function te({rows:e}){return e.length===0?a(o,{dimColor:!0,children:"no crons"}):a(i,{flexDirection:"column",children:e.slice(0,12).map(r=>{let t=r.enabled?r.consecutiveErrors>0?a(o,{color:"red",children:"err"}):a(o,{color:"green",children:"ok"}):a(o,{dimColor:!0,children:"off"}),n=r.nextRun?new Date(r.nextRun).toLocaleTimeString():"\u2014";return c(i,{children:[a(o,{children:T(r.id,16)}),a(o,{dimColor:!0,children:T(r.schedule,12)}),a(o,{children:T(n,10)}),a(i,{children:t})]},r.id)})})}function re({rows:e}){if(e.length===0)return a(o,{dimColor:!0,children:"(waiting for channel events\u2026)"});let r=[...e].sort((t,n)=>n.lastAt-t.lastAt);return a(i,{flexDirection:"column",children:r.slice(0,12).map(t=>c(i,{children:[a(o,{children:T(t.channel,12)}),c(o,{color:"cyan",children:["\u2190",T(String(t.inbound),4)]}),c(o,{color:"magenta",children:["\u2192",T(String(t.outbound),4)]}),a(o,{dimColor:!0,children:t.lastPreview})]},t.channel))})}function ne({rows:e,cursor:r,focused:t}){return e.length===0?a(o,{dimColor:!0,children:"(waiting for events\u2026)"}):a(i,{flexDirection:"column",children:e.slice(0,18).map((n,s)=>{let u=I(t,s===r);return c(i,{children:[a(o,{...u,dimColor:!0,children:new Date(n.at).toLocaleTimeString().padEnd(10)}),a(o,{...u,color:ce(n.kind),children:T(n.kind,8)}),a(o,{...u,children:n.line})]},`${n.at}-${s}`)})})}function oe({chat:e,suggest:r,agents:t}){let n=e.history.slice(-14),s=t.find(f=>f.id===e.agentId),u=H(s?.tier??"",s?.model),p=e.status==="sending"?[...e.history].reverse().find(f=>f.role==="agent"&&f.streaming):void 0,y=e.status==="sending"?a(O,{startedAt:p?.at??Date.now(),phase:p?.text?"responding":"thinking",indent:""}):e.error?c(o,{color:"red",children:["\u25CF ",e.error]}):a(o,{dimColor:!0,children:"\u25CF ready"});return c(i,{flexDirection:"column",width:"50%",borderStyle:"double",borderColor:"green",paddingX:1,children:[c(i,{justifyContent:"space-between",children:[c(o,{bold:!0,color:"green",children:["CHAT \xB7 @",e.agentId]}),a(i,{children:y})]}),c(o,{children:[c(o,{color:u.color,bold:!0,children:[u.glyph," ",u.label]}),s?.model?c(o,{dimColor:!0,children:[" ",j(s.model)]}):null,c(o,{dimColor:!0,children:[" \xB7 ",e.chatId]})]}),a(i,{flexDirection:"column",flexGrow:1,marginTop:1,children:n.length===0?a(o,{dimColor:!0,children:"(type a message and press Enter \u2014 Esc exits, Ctrl-L starts fresh)"}):n.map((f,l)=>a(se,{turn:f,agentId:e.agentId},`${f.at}-${l}`))}),r?c(o,{dimColor:!0,children:[a(o,{color:"cyan",children:"\u21B9"})," ",r.items.slice(0,5).map((f,l)=>l===0?a(o,{color:"cyan",children:f},l):c(o,{children:[" ",f]},l))]}):null,c(i,{children:[a(o,{color:"cyan",children:"you \u203A "}),a(o,{children:e.text}),a(o,{inverse:!0,children:" "})]})]})}function se({turn:e,agentId:r}){if(e.role==="you")return c(i,{flexDirection:"column",marginBottom:1,children:[a(o,{color:"cyan",children:"you"}),e.text.split(`
|
|
5
5
|
`).map((s,u)=>c(o,{children:[" ",s]},u))]});if(e.role==="error")return c(i,{flexDirection:"column",marginBottom:1,children:[a(o,{color:"red",children:"error"}),c(o,{color:"red",children:[" ",e.text]})]});let t=e.elapsedMs!=null?` \xB7 ${(e.elapsedMs/1e3).toFixed(1)}s${e.outTokens!=null?`, ${e.outTokens} tok`:""}`:e.streaming?" \xB7 \u2026":"",n=F(e.text,58,{balance:e.streaming});return c(i,{flexDirection:"column",marginBottom:1,children:[c(o,{color:"green",children:["@",r??"agent",a(o,{dimColor:!0,children:t})]}),e.thinking?e.thinking.split(`
|
|
6
6
|
`).filter(s=>s.trim()).slice(-2).map((s,u)=>c(o,{dimColor:!0,italic:!0,children:[" ",s]},`th${u}`)):null,(e.tools??[]).map((s,u)=>c(o,{color:s.error?"red":"green",children:[" \u25CF ",c(o,{bold:!s.error,dimColor:s.error,children:[s.name,s.arg?c(o,{dimColor:!0,children:["(",s.arg,")"]}):null,s.error?" failed":""]})]},`tool${u}`)),n.split(`
|
|
7
7
|
`).slice(0,14).map((s,u)=>c(o,{children:[" ",s]},u))]})}function ae(e){let r=e.data??{},t=typeof r.at=="string"||typeof r.at=="number"?new Date(r.at).getTime():Date.now(),n="";switch(e.event){case"run":n=`${r.phase??""} ${r.workflowId??""} ${(r.runId??"").slice(0,8)} ${r.nodeId??""}`.trim();break;case"task":n=`${r.phase??""} ${r.workflowId??""} ${Array.isArray(r.assignedTo)?r.assignedTo.join(","):""} ${r.title?`"${r.title}"`:""}`.trim();break;case"signal":n=`${r.name??""} (${r.scope??""}) ${r.workflowId??""}`.trim();break;case"mesh":n=`${r.peer??""} ${r.healthy?"healthy":"lost"} ${r.delta??""}`.trim();break;case"channel":{n=`${r.direction==="in"?"\u2190":"\u2192"} ${r.channel??""}:${r.chatId??""} ${r.textPreview??""}`.trim();break}case"status":n=`node=${r.node??""} agents=${r.agents??0} active=${(r.active??[]).length}`;break;default:n=typeof r=="string"?r:JSON.stringify(r).slice(0,80)}return{at:Number.isFinite(t)?t:Date.now(),kind:e.event,line:n}}function ce(e){switch(e){case"run":return"cyan";case"task":return"magenta";case"signal":return"green";case"mesh":return"blue";case"channel":return"yellow";default:return"white"}}function T(e,r){let t=(e??"").toString();return t.length>=r?t.slice(0,r-1)+" ":t+" ".repeat(r-t.length)}export{be as App};
|
|
8
|
-
//# sourceMappingURL=App-
|
|
8
|
+
//# sourceMappingURL=App-A7WZMOGA.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{a as Y,b as Z,c as _,d as ee,e as te,f as ne,g as re}from"./chunk-U2CKL755.js";import{b as Q,g as X}from"./chunk-
|
|
1
|
+
import{a as Y,b as Z,c as _,d as ee,e as te,f as ne,g as re}from"./chunk-U2CKL755.js";import{b as Q,g as X}from"./chunk-CUS7WGZT.js";import"./chunk-IA3BC7M3.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useCallback as oe,useMemo as H,useRef as P,useState as k}from"react";import{Box as g,Text as t,useApp as he,useInput as xe,useStdout as Te}from"ink";import{randomUUID as se}from"crypto";var m={accent:"cyan",agent:"green",working:"magenta",error:"red",muted:"gray"},q="\u25C7 agentx",F="\u258C";import{jsx as c,jsxs as o}from"react/jsx-runtime";var ie="/help /agent <id> /agents /clear /who /exit",be=[{cmd:"/agent",desc:"switch the target agent (/agent <id>)"},{cmd:"/agents",desc:"list registered agents"},{cmd:"/clear",desc:"start a fresh session"},{cmd:"/who",desc:"show agent + chat id"},{cmd:"/help",desc:"list commands"},{cmd:"/exit",desc:"quit the chat"}];function Pe({conn:n,agentId:p,channel:f,chatId:a,agents:h}){let{exit:w}=he(),{stdout:O}=Te(),V=Math.max(40,Math.min((O?.columns||80)-4,100)),[z,U]=k([]),[$,S]=k(null),[T,le]=k(p),[A,ae]=k(h),[E,ue]=k(a),[y,x]=k(""),[J,de]=k(""),W=P([]),u=P(-1),M=P(null),R=P(null),v=$?.live??!1,j=H(()=>Z(y,A.map(s=>s.id),process.cwd()),[y,A]),N=H(()=>{let s=/^\/(\w*)$/.exec(y);if(!s)return null;let e=be.filter(r=>r.cmd.slice(1).startsWith(s[1].toLowerCase()));return e.length?e:null},[y]),b=s=>de(s),K=oe(s=>{let e=se().slice(0,8),r=Date.now(),i=new AbortController;R.current=i;let d={id:e,you:s,agentId:T,segs:[],live:!0,startedAt:r};S({...d});let L=()=>S({...d,segs:d.segs.map(C=>({...C}))});(async()=>{try{let C=await X(n,T,s,{channel:f,chatId:E,signal:i.signal,onText:l=>{let I=d.segs[d.segs.length-1];I&&I.type==="text"?I.content=(I.content??"")+l:d.segs.push({type:"text",content:l}),L()},onThinking:l=>{d.thinking=(d.thinking??"")+l,L()},onTool:l=>{l.status==="start"&&l.name?(d.segs.push({type:"tool",name:l.name,arg:l.arg}),L()):l.status==="result"&&l.error&&(d.segs.push({type:"tool",name:l.name??"tool",error:!0}),L())}});U(l=>[...l,{...d,live:!1,elapsedMs:Date.now()-r,outTokens:C.usage?.outputTokens,error:C.error}]),S(null)}catch(C){let l=i.signal.aborted||C?.name==="AbortError";U(I=>[...I,{...d,live:!1,elapsedMs:Date.now()-r,interrupted:l,error:l?void 0:C?.message||String(C)}]),S(null)}finally{R.current===i&&(R.current=null)}})()},[n,T,f,E]),me=oe(s=>{let e=s.trim();if(e){if(W.current.push(e),u.current=-1,e==="/exit"||e==="/quit"){w();return}if(e==="/help"){b(ie);return}if(e==="/who"){b(`@${T} \xB7 chatId=${E} \xB7 channel=${f}`);return}if(e==="/clear"){let r=`chat-cli:${se().slice(0,12)}`;ue(r),U([]),b(`fresh chatId=${r} (warm process dropped)`);return}if(e==="/agents"){Q(n).then(r=>{ae(r),b(r.map(i=>i.id===T?`[${i.id}]`:i.id).join(" "))}).catch(r=>b(`failed to list agents: ${r?.message||r}`));return}if(e.startsWith("/agent ")){let r=e.slice(7).replace(/^@/,"").trim();if(!r){b("usage: /agent <id>");return}if(!A.find(i=>i.id===r)){b(`unknown agent: @${r}`);return}le(r),b(`now talking to @${r}`);return}if(e.startsWith("/")){b(`unknown command \xB7 ${ie}`);return}K(e)}},[n,T,A,f,E,w,K]);xe((s,e)=>{if(e.ctrl&&s==="c"){w();return}if(e.escape){if(v&&R.current){R.current.abort();return}w();return}if(e.tab){if(N){x(N[0].cmd+" ");return}let i=_(y,M,A.map(d=>d.id),process.cwd());i!==null&&(x(i),u.current=-1);return}if(e.upArrow){let i=W.current;if(!i.length)return;u.current=u.current<0?i.length-1:Math.max(0,u.current-1),x(i[u.current]??"");return}if(e.downArrow){let i=W.current;if(u.current<0)return;if(u.current=u.current+1,u.current>=i.length){u.current=-1,x("");return}x(i[u.current]??"");return}if(e.backspace||e.delete){M.current=null,x(i=>i.slice(0,-1));return}if(e.ctrl||e.meta)return;let r=ee(s??"",e.return,y);switch(r.kind){case"paste":M.current=null,x(i=>i+r.text),u.current=-1;return;case"type":M.current=null,x(i=>i+r.text),u.current=-1;return;case"continue":x(r.buffer);return;case"submit":if(v)return;M.current=null,x(""),me(r.text);return;case"none":return}});let G=v?m.working:m.accent,ge=y.length?y.split(`
|
|
2
2
|
`):[""],B=A.find(s=>s.id===T),D=ne(B?.tier??"",B?.model),pe=O?.rows||24,fe=z.slice(-40);return o(g,{flexDirection:"column",height:pe,children:[o(g,{flexDirection:"column",flexGrow:1,justifyContent:"flex-end",overflow:"hidden",children:[z.length===0&&!$?o(g,{flexDirection:"column",children:[o(t,{children:[c(t,{color:m.accent,bold:!0,children:q}),c(t,{dimColor:!0,children:" \u2014 chat with "}),o(t,{color:m.accent,children:["@",T]}),c(t,{dimColor:!0,children:" via "}),o(t,{color:D.color,bold:!0,children:[D.glyph," ",D.label]}),B?.model?o(t,{dimColor:!0,children:[" (",B.model,")"]}):null]}),c(t,{dimColor:!0,children:"streaming \xB7 markdown \xB7 tools \xB7 type a message, or / for commands"})]}):null,fe.map(s=>c(ce,{turn:s,width:V},s.id)),$?c(ce,{turn:$,width:V}):null]}),N?c(g,{flexDirection:"column",marginTop:1,children:N.map((s,e)=>o(g,{children:[c(t,{color:e===0?m.accent:m.muted,bold:e===0,children:s.cmd.padEnd(10)}),c(t,{dimColor:!0,children:s.desc})]},s.cmd))}):j?o(g,{marginTop:1,children:[c(t,{color:m.accent,children:"\u21B9 "}),j.items.map((s,e)=>o(t,{color:e===0?m.accent:m.muted,children:[s,e<j.items.length-1?" ":""]},e))]}):J?c(g,{marginTop:1,children:c(t,{dimColor:!0,children:J})}):null,c(g,{borderStyle:"single",borderColor:G,borderLeft:!1,borderRight:!1,borderDimColor:!v,width:"100%",children:c(g,{flexDirection:"column",width:"100%",children:ge.map((s,e,r)=>o(g,{children:[c(t,{color:G,bold:!0,children:e===0?"\u203A ":" "}),c(t,{children:s}),e===r.length-1&&!v?c(t,{color:G,children:"\u258F"}):null]},e))})}),o(g,{justifyContent:"space-between",children:[o(t,{children:[c(t,{color:m.accent,bold:!0,children:q}),o(t,{dimColor:!0,children:[" \xB7 @",T," \xB7 "]}),o(t,{color:D.color,bold:!0,children:[D.glyph," ",D.label]}),B?.model?o(t,{dimColor:!0,children:[" ",re(B.model)]}):null]}),o(t,{dimColor:!0,children:["\u21B5 send / cmds @ mention esc ",v?"stop":"exit"]})]})]})}function ce({turn:n,width:p}){let f=H(()=>ye(n,p),[n,p]),a=n.segs.some(h=>h.type==="text"&&h.content);return o(g,{flexDirection:"column",marginBottom:1,children:[o(t,{color:m.accent,bold:!0,children:[F," you"]}),n.you.split(`
|
|
3
3
|
`).map((h,w)=>o(t,{color:"white",children:[" ",h]},`u${w}`)),o(t,{color:m.agent,bold:!0,children:[F," ",n.agentId??"agent"]}),n.thinking?c(g,{flexDirection:"column",children:we(n.thinking,n.live?3:2).map((h,w)=>o(t,{dimColor:!0,italic:!0,children:[" ",h]},`th${w}`))}):null,f,n.live?c(te,{startedAt:n.startedAt,phase:a?"responding":"thinking",hint:"esc to interrupt"}):n.interrupted?o(t,{dimColor:!0,children:[" \u2298 interrupted \xB7 ",(n.elapsedMs/1e3).toFixed(1),"s"]}):n.error?o(t,{color:"red",children:[" \u2717 ",n.error]}):n.elapsedMs!=null?o(t,{dimColor:!0,children:[" \xB7 ",(n.elapsedMs/1e3).toFixed(1),"s",n.outTokens!=null?`, ${n.outTokens} tok`:""]}):null]})}function we(n,p){return n.split(`
|
|
4
4
|
`).filter(a=>a.trim()).slice(-p)}function ye(n,p){let f=[];return n.segs.forEach((a,h)=>{a.type==="tool"?f.push(o(t,{color:a.error?"red":"green",children:[" ","\u25CF ",o(t,{bold:!a.error,dimColor:a.error,children:[a.name,a.arg?o(t,{dimColor:!0,children:["(",a.arg,")"]}):null,a.error?" failed":""]})]},h)):a.content&&f.push(c(t,{children:Ce(Y(a.content,p,{balance:n.live}))},h))}),f}function Ce(n){return n.split(`
|
|
5
5
|
`).map(p=>p.length?" "+p:p).join(`
|
|
6
6
|
`)}export{Pe as ChatApp};
|
|
7
|
-
//# sourceMappingURL=ChatApp-
|
|
7
|
+
//# sourceMappingURL=ChatApp-EWNT36ZE.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{A as a,B as b,C as c}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=agent-
|
|
1
|
+
import{A as a,B as b,C as c}from"./chunk-HVPRCHRG.js";import"./chunk-SFQUP3BP.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import"./chunk-QIJLFPWE.js";export{a as createAgentContext,b as generate,c as generateStream};
|
|
2
|
+
//# sourceMappingURL=agent-MUGC4RZP.js.map
|