This commit is contained in:
2026-09-11 14:26:44 -04:00
parent 78cb03e6cb
commit b264c31b86
16 changed files with 181 additions and 19 deletions
+3 -2
View File
@@ -5,11 +5,12 @@ import { createPhase2Tools } from '../skills/phase2-tools.js';
import { createQvacTools } from '../skills/qvac-tools.js';
import { VOICE_SYSTEM_PROMPT, parseHudSidecar } from '../skills/voice-prompt.js';
import { createComputerObserveTools } from '../skills/computer-observe.js';
import { createComputerActTools } from '../skills/computer-act.js';
export class HarnessBridge extends EventEmitter {
constructor({ cwd = process.cwd(), model = 'qwen3.5-4b', tools = [], computer, observer, permissionMode = 'ask' } = {}) {
constructor({ cwd = process.cwd(), model = 'qwen3.5-4b', tools = [], computer, observer, actuator, permissionMode = 'ask' } = {}) {
super();
this.options = { cwd, model, tools: [...createRuntimeTools({ computer }), ...createPhase2Tools({ cwd, computer }), ...createComputerObserveTools({ computer, observer }), ...createQvacTools(), ...tools], permissionMode, origin: 'jarvis-qvac', system: VOICE_SYSTEM_PROMPT };
this.options = { cwd, model, tools: [...createRuntimeTools({ computer }), ...createPhase2Tools({ cwd, computer }), ...createComputerObserveTools({ computer, observer }), ...createComputerActTools({ actuator }), ...createQvacTools(), ...tools], permissionMode, origin: 'jarvis-qvac', system: VOICE_SYSTEM_PROMPT };
this.session = null;
}
+10 -4
View File
@@ -10,6 +10,9 @@ import { QvacVoiceAdapter } from './voice-adapters.js';
import { createWakeEngine } from './wake-engine.js';
import { DesktopObserver } from '../computer-use/observer.js';
import { QvacPerception } from './perception.js';
import { ComputerAudit } from '../computer-use/audit.js';
import { PortalInputBackend } from '../computer-use/portal-input.js';
import { ComputerActuator } from '../computer-use/actuator.js';
export class JarvisDaemon extends EventEmitter {
constructor() {
@@ -17,10 +20,13 @@ export class JarvisDaemon extends EventEmitter {
this.state = 'ARMED';
this.voice = new VoiceStateMachine();
this.scheduler = new QvacScheduler({ concurrency: 1 });
this.computer = new ComputerUseSession();
this.audit = new ComputerAudit();
this.computer = new ComputerUseSession({ audit: this.audit });
this.input = new PortalInputBackend();
this.perception = new QvacPerception();
this.observer = new DesktopObserver({ ocr: (image) => this.perception.ocr(image) });
this.harness = new HarnessBridge({ cwd: process.cwd(), computer: this.computer, observer: this.observer });
this.actuator = new ComputerActuator({ session: this.computer, input: this.input, find: ({ ref }) => this.observer.lastTree.filter((node) => node.ref === ref), atspiAction: (target, action) => this.observer.atspi.action(target, action), highlight: async (target, action) => this.emit('ComputerHighlight', JSON.stringify({ rect: target?.rect || null, label: `${action} ${target?.name || ''}` })) , audit: this.audit });
this.harness = new HarnessBridge({ cwd: process.cwd(), computer: this.computer, observer: this.observer, actuator: this.actuator });
this.log = new PrivacyLog();
this.locked = false;
this.lastReply = '';
@@ -46,8 +52,8 @@ export class JarvisDaemon extends EventEmitter {
}
}
cancel() { this.harness.cancel(); this.scheduler.cancelQueued((job) => job.lane === 'voice'); this.computer.revoke(); this.voice.cancel(); this.setState('ARMED'); cancelQvac().catch((error) => this.emit('Error', 'QVAC_CANCEL', error.message)); }
computerGrant(persist = false) { const result = this.computer.grant({ persist }); this.emit('ComputerStep', JSON.stringify({ action: 'grant', ...result })); return result; }
computerRevoke() { this.computer.revoke(); this.emit('ComputerStep', JSON.stringify({ action: 'revoke' })); }
computerGrant(persist = false) { const result = this.computer.grant({ persist }); this.emit('ComputerStep', JSON.stringify({ action: 'grant', ...result })); this.input.grant({ persist }).then((backend) => { this.computer.setBackend(backend.backend); this.emit('ComputerStep', JSON.stringify({ action: 'backend', ...backend })); }).catch((error) => this.emit('Error', 'CU_GRANT', error.message)); return result; }
computerRevoke() { this.input.revoke(); this.computer.revoke(); this.emit('ComputerStep', JSON.stringify({ action: 'revoke' })); }
async startVoice() {
if (this.voiceLoop) return;
const voiceIO = new QvacVoiceAdapter();