mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
fix(voice): show the voice panel that typed chat asks for
set_panel_open for voice-settings or voice-preview reported success while chat's open state kept the voice panel hidden, minimized chat included. A successful explicit show now closes chat, which keeps the typed session, its running turn and its messages; reopening chat restores them.
This commit is contained in:
1 parent
b6967a3dd9
commit
4f4af9c4e0
3 files changed
+72
-4
No files matched your search
@@ -767,7 +767,10 @@ starts. Settings opened from chat keep chat's frame and show the shared AI
|
|||||||
provider and the quick-commands option, with Back to chat; voice Settings show
|
provider and the quick-commands option, with Back to chat; voice Settings show
|
||||||
Back to voice. Escape steps back from either Settings view, closes Voice
|
Back to voice. Escape steps back from either Settings view, closes Voice
|
||||||
Preview, and does nothing in chat. Closing chat ends a typed session, and the
|
Preview, and does nothing in chat. Closing chat ends a typed session, and the
|
||||||
voice panel's close turns voice off.
|
voice panel's close turns voice off. Asking the assistant from chat to open
|
||||||
|
Voice Settings or Voice Preview puts chat away, minimized or not, and shows the
|
||||||
|
voice panel; the typed conversation and its running reply carry on, and the
|
||||||
|
chat button brings them back.
|
||||||
|
|
||||||
Contacts nearest-aircraft follow-ups retain the snapshot's distance basis even
|
Contacts nearest-aircraft follow-ups retain the snapshot's distance basis even
|
||||||
after the camera moves. An explicit new scope replaces that basis. Provider
|
after the camera moves. An explicit new scope replaces that basis. Provider
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ test('the voice inactivity timeout never ends a typed chat session', async (t) =
|
|||||||
|
|
||||||
async function directActions(
|
async function directActions(
|
||||||
t,
|
t,
|
||||||
{ storage = null, delayExit = false, exposePanel = true } = {},
|
{ storage = null, delayExit = false, exposePanel = true, typed = false } = {},
|
||||||
) {
|
) {
|
||||||
let f, releaseExit;
|
let f, releaseExit;
|
||||||
const state = { active: true, exits: 0, visual: [] };
|
const state = { active: true, exits: 0, visual: [] };
|
||||||
@@ -544,7 +544,12 @@ async function directActions(
|
|||||||
exposePanel ? f?.commands.captureVoicePanelOperation() : undefined,
|
exposePanel ? f?.commands.captureVoicePanelOperation() : undefined,
|
||||||
});
|
});
|
||||||
f = mounted(t, { native: true, runner, storage });
|
f = mounted(t, { native: true, runner, storage });
|
||||||
await f.commands.session.start();
|
// A typed chat session starts from chat's first send instead.
|
||||||
|
if (typed) {
|
||||||
|
const adapter = f.instances[0];
|
||||||
|
adapter.getStartOptions = () => ({ textOnly: true });
|
||||||
|
adapter.sendText = () => true;
|
||||||
|
} else await f.commands.session.start();
|
||||||
return {
|
return {
|
||||||
...f,
|
...f,
|
||||||
runner,
|
runner,
|
||||||
@@ -618,6 +623,53 @@ test('named voice settings exits Cockpit directly; Preview stays disabled and vi
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (const minimized of [false, true])
|
||||||
|
test(`an explicit voice panel request from ${minimized ? 'minimized ' : ''}typed chat shows the panel and keeps the chat`, async (t) => {
|
||||||
|
const f = await directActions(t, { typed: true });
|
||||||
|
const adapter = f.instances[0];
|
||||||
|
f.ui.emit('chat-button');
|
||||||
|
f.ui.emit('chat-input', 'Fly to Tokyo');
|
||||||
|
f.ui.emit('chat-submit');
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
assert.equal(f.ui.state.chat.busy, true, 'the typed turn is running');
|
||||||
|
if (minimized) f.ui.emit('chat-minimize');
|
||||||
|
assert.equal(f.ui.state.root.chatOpen, true);
|
||||||
|
for (const [panelId, view] of [
|
||||||
|
['voice-settings', 'settings'],
|
||||||
|
['voice-preview', 'preview'],
|
||||||
|
]) {
|
||||||
|
const result = await f.run('set_panel_open', { panelId, open: true });
|
||||||
|
assert.equal(result.ok, true);
|
||||||
|
// `[data-chat-open='true'] .gev-voice-panel` is display:none.
|
||||||
|
assert.equal(f.ui.state.root.chatOpen, false, panelId);
|
||||||
|
assert.equal(f.ui.state.chat.open, false);
|
||||||
|
assert.equal(f.ui.state.voicePanel.hidden, false);
|
||||||
|
assert.equal(f.ui.state.voicePanel.view, view);
|
||||||
|
}
|
||||||
|
assert.equal(adapter.stops, 0, 'the typed session continues');
|
||||||
|
assert.equal(f.commands.session.isActive(), true);
|
||||||
|
assert.equal(f.ui.state.chat.busy, true, 'the turn is not cancelled');
|
||||||
|
adapter.hooks.emit({
|
||||||
|
type: 'transcript',
|
||||||
|
role: 'assistant',
|
||||||
|
text: 'Flying to Tokyo.',
|
||||||
|
final: true,
|
||||||
|
itemId: 'reply',
|
||||||
|
});
|
||||||
|
adapter.hooks.emit({ type: 'completion', status: 'completed' });
|
||||||
|
assert.equal(f.ui.state.chat.busy, false);
|
||||||
|
f.ui.emit('chat-button');
|
||||||
|
assert.equal(f.ui.state.root.chatOpen, true);
|
||||||
|
assert.equal(f.ui.state.voicePanel.hidden, true);
|
||||||
|
assert.deepEqual(
|
||||||
|
f.ui.chatMessages.map(({ role }) => role),
|
||||||
|
['user', 'assistant'],
|
||||||
|
'reopened chat shows the whole conversation',
|
||||||
|
);
|
||||||
|
assert.equal(f.ui.chatMessages[0].text, 'Fly to Tokyo');
|
||||||
|
assert.equal(adapter.stops, 0);
|
||||||
|
});
|
||||||
|
|
||||||
test('canonical exit reveals requested voice UI; newer manual choice or Stop defeats pending reveal', async (t) => {
|
test('canonical exit reveals requested voice UI; newer manual choice or Stop defeats pending reveal', async (t) => {
|
||||||
const f = await directActions(t, { delayExit: true });
|
const f = await directActions(t, { delayExit: true });
|
||||||
const pending = f.run('control_cockpit', {
|
const pending = f.run('control_cockpit', {
|
||||||
|
|||||||
@@ -157,7 +157,20 @@ export function createVoiceCommands({
|
|||||||
controls.voiceCard = card;
|
controls.voiceCard = card;
|
||||||
if (panelMount) {
|
if (panelMount) {
|
||||||
controls.voicePanel = panelMount.panel;
|
controls.voicePanel = panelMount.panel;
|
||||||
controls.captureVoicePanelOperation = panelMount.captureOperation;
|
// An explicit, successful show hands the frame from chat to the voice
|
||||||
|
// panel, which chat's open state hides. Closing chat keeps its typed
|
||||||
|
// session, running turn and messages; reopening chat restores them.
|
||||||
|
controls.captureVoicePanelOperation = () => {
|
||||||
|
const operation = panelMount.captureOperation();
|
||||||
|
return {
|
||||||
|
...operation,
|
||||||
|
show(view, open = true) {
|
||||||
|
const result = operation.show(view, open);
|
||||||
|
if (open && result.ok) chat?.close();
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
controls.getVoicePanelState = panelMount.snapshot;
|
controls.getVoicePanelState = panelMount.snapshot;
|
||||||
controls.getVoicePreferences = panelHost.snapshot;
|
controls.getVoicePreferences = panelHost.snapshot;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user