Skip to content

Commit c2e9091

Browse files
committed
fix: simplify talk options panel
1 parent 12debcb commit c2e9091

4 files changed

Lines changed: 253 additions & 95 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
2727
### Fixes
2828

2929
- Feishu/wiki: reject numeric wiki space IDs before creating Lark clients and keep numeric-looking IDs documented as quoted opaque strings, preventing JavaScript precision loss in knowledge base calls. Fixes #45301. (#82769) Thanks @hyspacex.
30+
- Control UI: simplify Talk settings to Voice, Model, and Sensitivity defaults, with provider, transport, exact VAD, and timing controls behind Advanced.
3031
- Channels/stream previews: contain rejected background draft-stream flushes so preview send failures do not surface as fatal unhandled rejections. Fixes #82712. (#82713) Thanks @coygeek.
3132
- Providers/OpenAI Codex: include base `gpt-5.5` and `gpt-5.4` reasoning metadata in the bundled Codex catalog so `/think xhigh` remains available for those models. Fixes #82744.
3233
- Providers/MiniMax: declare CN endpoint auth aliases in the plugin manifest so `minimax-cn` and `minimax-portal-cn` reuse the correct base auth profiles instead of falling back to unrelated models after 401s. Fixes #63823. Thanks @kamusis.

ui/src/styles/chat/layout.css

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -702,14 +702,29 @@
702702
}
703703

704704
.agent-chat__talk-options {
705-
display: grid;
706-
grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
707-
gap: 8px;
705+
display: flex;
706+
align-items: flex-start;
707+
gap: 10px;
708708
padding: 10px;
709709
border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
710710
background: color-mix(in srgb, var(--bg-elevated) 72%, transparent);
711711
}
712712

713+
.agent-chat__talk-options-primary {
714+
display: grid;
715+
grid-template-columns: minmax(132px, 0.8fr) minmax(160px, 1fr) minmax(132px, 0.8fr);
716+
gap: 8px;
717+
flex: 1 1 auto;
718+
min-width: 0;
719+
}
720+
721+
.agent-chat__talk-options-grid {
722+
display: grid;
723+
grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
724+
gap: 8px;
725+
margin-top: 8px;
726+
}
727+
713728
.agent-chat__talk-options label {
714729
display: flex;
715730
flex-direction: column;
@@ -733,6 +748,50 @@
733748
padding: 0 8px;
734749
}
735750

751+
.agent-chat__talk-options-advanced {
752+
flex: 0 1 420px;
753+
min-width: 220px;
754+
color: var(--muted);
755+
}
756+
757+
.agent-chat__talk-options-advanced summary {
758+
display: inline-flex;
759+
align-items: center;
760+
min-height: 30px;
761+
padding: 0 8px;
762+
border-radius: var(--radius-sm);
763+
color: var(--muted);
764+
cursor: pointer;
765+
font-size: 0.75rem;
766+
font-weight: 500;
767+
list-style: none;
768+
user-select: none;
769+
}
770+
771+
.agent-chat__talk-options-advanced summary::-webkit-details-marker {
772+
display: none;
773+
}
774+
775+
.agent-chat__talk-options-advanced summary::after {
776+
content: "";
777+
width: 7px;
778+
height: 7px;
779+
margin-left: 8px;
780+
border-right: 1.5px solid currentColor;
781+
border-bottom: 1.5px solid currentColor;
782+
transform: rotate(45deg) translateY(-1px);
783+
transition: transform var(--duration-fast) ease;
784+
}
785+
786+
.agent-chat__talk-options-advanced[open] summary {
787+
color: var(--text);
788+
background: var(--bg-hover);
789+
}
790+
791+
.agent-chat__talk-options-advanced[open] summary::after {
792+
transform: rotate(225deg) translate(-1px, -1px);
793+
}
794+
736795
.agent-chat__input-divider {
737796
width: 1px;
738797
height: 16px;
@@ -827,6 +886,21 @@
827886
}
828887

829888
@media (max-width: 860px) {
889+
.agent-chat__talk-options {
890+
flex-direction: column;
891+
}
892+
893+
.agent-chat__talk-options-primary,
894+
.agent-chat__talk-options-grid {
895+
width: 100%;
896+
grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
897+
}
898+
899+
.agent-chat__talk-options-advanced {
900+
flex-basis: auto;
901+
width: 100%;
902+
}
903+
830904
.agent-chat__input-btn,
831905
.agent-chat__toolbar .btn--ghost,
832906
.chat-send-btn {

ui/src/ui/views/chat.test.ts

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,25 +561,31 @@ describe("chat voice controls", () => {
561561
});
562562

563563
const model = container.querySelector<HTMLInputElement>(
564-
'.agent-chat__talk-options input[placeholder="gpt-realtime-2"]',
564+
'.agent-chat__talk-options-primary input[placeholder="Auto"]',
565565
);
566566
const voice = container.querySelector<HTMLSelectElement>(
567-
".agent-chat__talk-options label:nth-of-type(4) select",
567+
".agent-chat__talk-options-primary label:nth-of-type(1) select",
568+
);
569+
const sensitivity = container.querySelector<HTMLSelectElement>(
570+
".agent-chat__talk-options-primary label:nth-of-type(3) select",
568571
);
569572
const voiceOptions = Array.from(
570573
container.querySelectorAll<HTMLOptionElement>(
571-
".agent-chat__talk-options label:nth-of-type(4) option",
574+
".agent-chat__talk-options-primary label:nth-of-type(1) option",
572575
),
573576
).map((option) => option.value);
574577
const reasoningOptions = Array.from(
575578
container.querySelectorAll<HTMLOptionElement>(
576-
".agent-chat__talk-options label:nth-of-type(5) option",
579+
".agent-chat__talk-options-advanced label:nth-of-type(3) option",
577580
),
578581
).map((option) => option.value);
579582

580583
if (voice === null) {
581584
throw new Error("expected Talk voice select");
582585
}
586+
if (sensitivity === null) {
587+
throw new Error("expected Talk sensitivity select");
588+
}
583589
expect(voiceOptions).toEqual([
584590
"",
585591
"alloy",
@@ -593,14 +599,58 @@ describe("chat voice controls", () => {
593599
"marin",
594600
"cedar",
595601
]);
602+
expect(sensitivity.value).toBe("__custom");
603+
expect(Array.from(sensitivity.options).map((option) => option.value)).toEqual([
604+
"",
605+
"0.65",
606+
"0.5",
607+
"0.35",
608+
"__custom",
609+
]);
596610
expect(reasoningOptions).toEqual(["", "minimal", "low", "medium", "high"]);
611+
expect(container.textContent).toContain("Sensitivity");
612+
expect(container.textContent).toContain("Advanced");
613+
expect(container.textContent).toContain("Pause before send");
614+
expect(container.textContent).not.toContain("Silence ms");
615+
expect(container.textContent).not.toContain("Prefix ms");
597616
if (model === null) {
598617
throw new Error("expected Talk model input");
599618
}
600619
model.value = "gpt-realtime-mini";
601620
model.dispatchEvent(new Event("input", { bubbles: true }));
621+
sensitivity.value = "0.35";
622+
sensitivity.dispatchEvent(new Event("change", { bubbles: true }));
623+
sensitivity.value = "";
624+
sensitivity.dispatchEvent(new Event("change", { bubbles: true }));
602625

603626
expect(onRealtimeTalkOptionsChange).toHaveBeenCalledWith({ model: "gpt-realtime-mini" });
627+
expect(onRealtimeTalkOptionsChange).toHaveBeenCalledWith({ vadThreshold: "0.35" });
628+
expect(onRealtimeTalkOptionsChange).toHaveBeenCalledWith({ vadThreshold: "" });
629+
630+
const defaultContainer = renderChatView({
631+
realtimeTalkOptionsOpen: true,
632+
realtimeTalkOptions: {
633+
provider: "",
634+
model: "",
635+
voice: "",
636+
transport: "",
637+
vadThreshold: "",
638+
silenceDurationMs: "",
639+
prefixPaddingMs: "",
640+
reasoningEffort: "",
641+
},
642+
onRealtimeTalkOptionsChange,
643+
});
644+
const defaultSensitivity = defaultContainer.querySelector<HTMLSelectElement>(
645+
".agent-chat__talk-options-primary label:nth-of-type(3) select",
646+
);
647+
expect(defaultSensitivity?.value).toBe("");
648+
expect(Array.from(defaultSensitivity?.options ?? []).map((option) => option.value)).toEqual([
649+
"",
650+
"0.65",
651+
"0.5",
652+
"0.35",
653+
]);
604654
});
605655

606656
it("renders composer and Talk labels from the active locale", async () => {

0 commit comments

Comments
 (0)