This commit is contained in:
+1
-1
@@ -47,7 +47,7 @@ export class JarvisDaemon extends EventEmitter {
|
|||||||
async sleep() { this.voice.sleep(); this.setState('SLEEPING'); await suspendQvac().catch((error) => this.emit('Error', 'QVAC_SUSPEND', error.message)); }
|
async sleep() { this.voice.sleep(); this.setState('SLEEPING'); await suspendQvac().catch((error) => this.emit('Error', 'QVAC_SUSPEND', error.message)); }
|
||||||
say(text) { this.lastReply = String(text); this.emit('Reply', this.lastReply); }
|
say(text) { this.lastReply = String(text); this.emit('Reply', this.lastReply); }
|
||||||
async ask(text) {
|
async ask(text) {
|
||||||
this.voice.utterance(); this.setState('THINKING');
|
this.voice.typedUtterance(); this.setState('THINKING');
|
||||||
try {
|
try {
|
||||||
const startedAt = Date.now(); const reply = await this.scheduler.run(() => this.harness.ask(text), { lane: 'voice' }); this.telemetry.record('llm', startedAt, { success: true });
|
const startedAt = Date.now(); const reply = await this.scheduler.run(() => this.harness.ask(text), { lane: 'voice' }); this.telemetry.record('llm', startedAt, { success: true });
|
||||||
this.voice.speak(); this.setState('SPEAKING'); this.lastReply = String(reply || ''); this.emit('Reply', this.lastReply); this.voiceLoop?.speak(this.lastReply).catch((error) => this.emit('Error', 'TTS', error.message)); return reply;
|
this.voice.speak(); this.setState('SPEAKING'); this.lastReply = String(reply || ''); this.emit('Reply', this.lastReply); this.voiceLoop?.speak(this.lastReply).catch((error) => this.emit('Error', 'TTS', error.message)); return reply;
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ export class VoiceStateMachine {
|
|||||||
|
|
||||||
wake() { return this.transition('LISTENING', 'wake'); }
|
wake() { return this.transition('LISTENING', 'wake'); }
|
||||||
utterance() { return this.transition('THINKING', 'utterance'); }
|
utterance() { return this.transition('THINKING', 'utterance'); }
|
||||||
|
typedUtterance() {
|
||||||
|
if (this.state === 'ARMED' || this.state === 'SLEEPING') this.wake();
|
||||||
|
return this.utterance();
|
||||||
|
}
|
||||||
speak() { return this.transition('SPEAKING', 'reply'); }
|
speak() { return this.transition('SPEAKING', 'reply'); }
|
||||||
finishSpeaking() { return this.transition('LISTENING', 'playback-finished'); }
|
finishSpeaking() { return this.transition('LISTENING', 'playback-finished'); }
|
||||||
cancel() { return this.transition('ARMED', 'cancel'); }
|
cancel() { return this.transition('ARMED', 'cancel'); }
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ test('voice state machine handles wake, reply, cancel, and idle sleep', () => {
|
|||||||
assert.equal(voice.state, 'SLEEPING');
|
assert.equal(voice.state, 'SLEEPING');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('typed questions wake an armed voice session before thinking', () => {
|
||||||
|
const voice = new VoiceStateMachine();
|
||||||
|
voice.typedUtterance();
|
||||||
|
assert.equal(voice.state, 'THINKING');
|
||||||
|
});
|
||||||
|
|
||||||
test('QVAC scheduler prioritizes voice and keeps one active job', async () => {
|
test('QVAC scheduler prioritizes voice and keeps one active job', async () => {
|
||||||
const scheduler = new QvacScheduler();
|
const scheduler = new QvacScheduler();
|
||||||
const order = [];
|
const order = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user