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) })