@@ -105,6 +105,8 @@ class ArcOverlay {
|
||||
this.entry.clutter_text.connect('activate', () => { const text = this.entry.get_text().trim(); if (text) { this.onAsk?.(text); this.entry.set_text(''); } });
|
||||
this.root.add_child(this.entry); this.root.add_child(this.controls);
|
||||
this.reducedMotion = false;
|
||||
this.streamingReply = false;
|
||||
this.replyFinalized = false;
|
||||
}
|
||||
attach() { Main.layoutManager.addChrome(this.root, { affectsStruts: false, trackFullscreen: false }); this.halo = new St.Widget({ style_class: 'jarvis-halo', reactive: false }); Main.layoutManager.addChrome(this.halo, { affectsStruts: false, trackFullscreen: false }); this.halo.hide(); this.hide(); }
|
||||
show(force = false) {
|
||||
@@ -123,7 +125,7 @@ class ArcOverlay {
|
||||
hide() { this.onTalk?.(false); this.root.visible = false; this.minimized = false; }
|
||||
minimize() { this.onTalk?.(false); this.root.visible = false; this.minimized = true; }
|
||||
toggle() { this.root.visible ? this.hide() : this.show(true); }
|
||||
clear() { this.transcript.destroy_all_children(); this.thinking.text = ''; this.thinking.visible = false; this.thinkingToggle.visible = false; }
|
||||
clear() { this.transcript.destroy_all_children(); this.thinking.text = ''; this.thinking.visible = false; this.thinkingToggle.visible = false; this.streamingReply = false; this.replyFinalized = false; }
|
||||
_followConversation() {
|
||||
const adjustment = this.scroll?.get_vadjustment?.() || this.scroll?.vadjustment;
|
||||
if (!adjustment) return;
|
||||
@@ -133,22 +135,24 @@ class ArcOverlay {
|
||||
});
|
||||
}
|
||||
addRow(who, text) { const body = safeText(text); const row = new St.Label({ text: `${who === 'J' ? 'J' : 'YOU'} ${body}`, style_class: `jarvis-row jarvis-row-${who === 'J' ? 'jarvis' : 'user'}`, can_focus: true }); row.accessible_name = `${who === 'J' ? 'Jarvis' : 'You'}: ${body}`; if (row.clutter_text) { row.clutter_text.line_wrap = true; row.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR; row.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; } this.transcript.add_child(row); if (this.transcript.get_n_children() > 100) this.transcript.get_first_child().destroy(); this.show(); this._followConversation(); return row; }
|
||||
token(text) { const chunk = safeText(text); if (!chunk) return; let row = this.transcript.get_last_child?.(); if (!row || !String(row.style_class || '').includes('jarvis-row-jarvis')) { row = this.addRow('J', ''); } row.text = `${row.text}${chunk}`; row.accessible_name = `Jarvis: ${row.text}`; this.show(); this._followConversation(); }
|
||||
token(text) { const chunk = safeText(text); if (!chunk) return; let row = this.transcript.get_last_child?.(); if (!this.streamingReply || !row || !String(row.style_class || '').includes('jarvis-row-jarvis')) { row = this.addRow('J', ''); this.streamingReply = true; this.replyFinalized = false; } row.text = `${row.text}${chunk}`; row.accessible_name = `Jarvis: ${row.text}`; this.show(); this._followConversation(); }
|
||||
updateThinking(text) { const chunk = safeText(text); if (!chunk) return; this.thinking.text = `${this.thinking.text || ''}${chunk}`; this.thinkingToggle.visible = true; this.thinking.visible = true; this.thinkingToggle.label = 'Thinking ▾'; this.show(); }
|
||||
toggleThinking() { this.thinking.visible = !this.thinking.visible; this.thinkingToggle.label = this.thinking.visible ? 'Thinking ▾' : 'Thinking ▸'; }
|
||||
finishThinking() { if (this.thinking.text) { this.thinkingToggle.visible = true; this.thinkingToggle.label = 'Thinking ▸'; this.thinking.visible = false; } }
|
||||
addToolCall(json) { try { const call = JSON.parse(json); this.addRow('J', `Using ${safeText(call.name || 'tool')}…`); } catch { this.addRow('J', `Using ${safeText(json)}…`); } this.finishThinking(); }
|
||||
addToolResult(json) { try { const result = JSON.parse(json); this.addRow('J', `${safeText(result.name || 'tool')} complete`); } catch { this.addRow('J', 'Tool complete'); } this.finishThinking(); }
|
||||
addToolCall(json) { this.streamingReply = false; try { const call = JSON.parse(json); this.addRow('J', `Using ${safeText(call.name || 'tool')}…`); } catch { this.addRow('J', `Using ${safeText(json)}…`); } this.finishThinking(); }
|
||||
addToolResult(json) { this.streamingReply = false; try { const result = JSON.parse(json); this.addRow('J', `${safeText(result.name || 'tool')} complete`); } catch { this.addRow('J', 'Tool complete'); } this.finishThinking(); }
|
||||
finalizeReply(text) {
|
||||
this.finishThinking();
|
||||
const spoken = safeText(text);
|
||||
if (this.replyFinalized) return;
|
||||
let row = this.transcript.get_last_child?.();
|
||||
if (row && String(row.style_class || '').includes('jarvis-row-jarvis')) {
|
||||
if (this.streamingReply && row && String(row.style_class || '').includes('jarvis-row-jarvis')) {
|
||||
const body = String(row.text || '').replace(/^J\s+/, '');
|
||||
if (spoken && !body.trim()) { row.text = `J ${spoken}`; row.accessible_name = `Jarvis: ${spoken}`; }
|
||||
this.show(); return;
|
||||
this.streamingReply = false; this.replyFinalized = true; this.show(); return;
|
||||
}
|
||||
if (spoken) this.addRow('J', spoken);
|
||||
this.replyFinalized = true;
|
||||
}
|
||||
setConnectionStatus(kind) {
|
||||
const labels = { local: 'LOCAL', offline: 'LOCAL · daemon unavailable', 'voice-unavailable': 'LOCAL · voice unavailable' };
|
||||
|
||||
Reference in New Issue
Block a user