feat(mobile): correlate voice tasks and recover results on reconnect
This commit is contained in:
1 parent
9f9f3226a1
commit
b66daed07a
17 files changed
+308
-48
No files matched your search
@@ -0,0 +1,49 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { VoiceDispatchGate } from '../src/behavior.mjs'
|
||||
import { VoiceSession } from '../src/voice.mjs'
|
||||
|
||||
test('IDE result cannot resurrect pending audio consent', async () => {
|
||||
const voice = new VoiceSession({ onText() {} }); voice.ready = true; voice.send = () => {}
|
||||
voice.audioTranscript = 'Bunu yap'; voice.dispatchGate.input('Bunu yap')
|
||||
voice.result({ taskId: 'done', status: 'complete', text: 'Bunu yap' })
|
||||
assert.equal(voice.audioTranscript, '')
|
||||
assert.throws(() => voice.dispatchGate.claim('Bunu yap', 'execute'))
|
||||
})
|
||||
|
||||
for (const phrase of ['Tamam, bunu yap.', 'Bu görevi gönder', 'Lütfen araştır', 'Şimdi başlat', 'Evet uygula']) {
|
||||
test(`direct current instruction: ${phrase}`, () => {
|
||||
const gate = new VoiceDispatchGate(); gate.input(phrase)
|
||||
assert.equal(gate.claim(phrase, 'research'), 1)
|
||||
assert.throws(() => gate.claim(phrase, 'research'))
|
||||
})
|
||||
}
|
||||
for (const phrase of ['Bunu yapma', 'Bunu yap mı', 'Bunu yapabilir miyiz?', '“Bunu yap” dedi', 'Yapsak nasıl olur', 'Hayır, bekle', 'Tamam']) {
|
||||
test(`discussion is not dispatch permission: ${phrase}`, () => {
|
||||
const gate = new VoiceDispatchGate(); gate.input(phrase)
|
||||
assert.throws(() => gate.claim(phrase, 'execute'))
|
||||
})
|
||||
}
|
||||
test('old consent, unfinished speech, research escalation and stopped session fail closed', () => {
|
||||
const gate = new VoiceDispatchGate(); gate.input('Bunu yap'); gate.input('Hayır bekle')
|
||||
assert.throws(() => gate.claim('Bunu yap', 'execute'))
|
||||
gate.input('Araştır'); assert.throws(() => gate.claim('Araştır', 'execute'))
|
||||
gate.input('Bunu ', false); assert.throws(() => gate.claim('Araştır', 'research'))
|
||||
gate.input('yap', true); assert.equal(gate.claim('Bunu yap', 'execute'), 4)
|
||||
gate.invalidate(); assert.throws(() => gate.claim('Bunu yap', 'execute'))
|
||||
})
|
||||
test('voice dispatch uses actual user text once; no model-generated permission or success', async () => {
|
||||
const sends = [], responses = []
|
||||
const voice = new VoiceSession({ onText() {}, onDraft() {}, onSubmit: async (...args) => { sends.push(args); return { accepted: true, completed: false } } })
|
||||
voice.send = frame => responses.push(frame)
|
||||
const args = { intent: 'research', objective: 'İncele', scope: 'Android', context: 'Yeşil seçildi', constraints: 'Değiştirme', output: 'Rapor', completion: 'Kanıt', userInstruction: 'Araştır' }
|
||||
const frame = { data: JSON.stringify({ toolCall: { functionCalls: [{ id: '1', name: 'submit_task', args }] } }) }
|
||||
await voice.receive(frame); assert.equal(sends.length, 0)
|
||||
await voice.receive({ data: JSON.stringify({ toolCall: { functionCalls: [{ id: 'draft', name: 'prepare_task', args }] } }) })
|
||||
responses.length = 0
|
||||
await voice.receive({ data: JSON.stringify({ serverContent: { inputTranscription: { text: 'Araştır' } } }) })
|
||||
await voice.receive(frame); await voice.receive(frame)
|
||||
assert.equal(sends.length, 1)
|
||||
assert.deepEqual(responses[0].toolResponse.functionResponses[0].response, { accepted: true, completed: false })
|
||||
assert.ok(responses[1].toolResponse.functionResponses[0].response.error)
|
||||
})
|
||||
Reference in new issue
Block a user