feat(site): add Kyleosophy alternative completion chimes (#23891)

- Add "Enable Kyleosophy" toggle to Settings > Behavior
- When enabled, replaces standard completion chime with random Kyle
sound clips
- Ships 8 alternative `.mp3` files as static assets (~82KB total)
- localStorage preference (`agents.kyleosophy`), defaults to off
- Pauses orphaned Audio elements on sound URL change to prevent overlap

<details><summary>Review findings addressed</summary>

- **P2** Stale JSDoc on `playChimeAudio` — updated to reflect
parameterized behavior
- **P3** Overlapping audio on rapid completions — added
`chimeAudio?.pause()` before replacement
- **P3** Test ordering dependency — pinned `Math.random` for
determinism, documented cache behavior
- **Nit** Setter naming — `setLocalKyleosophy` → `setKylesophyLocal`
- Toggle moved to bottom of Behavior page per product request
- Description changed to "IYKYK" per product request

</details>

> 🤖 Written by a Coder Agent. Reviewed by a human.
This commit is contained in:
Cian Johnston
2026-04-01 10:06:01 +00:00
committed by GitHub
parent d6df78c9b9
commit bec426b24f
11 changed files with 151 additions and 12 deletions
@@ -13,6 +13,7 @@ import { DurationField } from "./components/DurationField/DurationField";
import { SectionHeader } from "./components/SectionHeader";
import { TextPreviewDialog } from "./components/TextPreviewDialog";
import { UserCompactionThresholdSettings } from "./components/UserCompactionThresholdSettings";
import { getKylesophyEnabled, setKylesophyEnabled } from "./utils/chime";
const textareaMaxHeight = 240;
const textareaBaseClassName =
@@ -124,6 +125,7 @@ export const AgentSettingsBehaviorPageView: FC<
const [isUserPromptOverflowing, setIsUserPromptOverflowing] = useState(false);
const [isSystemPromptOverflowing, setIsSystemPromptOverflowing] =
useState(false);
const [kylesophyEnabled, setKylesophyLocal] = useState(getKylesophyEnabled);
// ── Derived state ──
const hasLoadedSystemPrompt = systemPromptData !== undefined;
@@ -510,6 +512,26 @@ export const AgentSettingsBehaviorPageView: FC<
</form>
</>
)}
<hr className="my-5 border-0 border-t border-solid border-border" />
{/* ── Kyleosophy toggle (always visible) ── */}
<div className="space-y-2">
<h3 className="m-0 text-[13px] font-semibold text-content-primary">
Kyleosophy
</h3>
<div className="flex items-center justify-between gap-4">
<p className="!mt-0.5 m-0 flex-1 text-xs text-content-secondary">
Replace the standard completion chime. IYKYK.
</p>
<Switch
checked={kylesophyEnabled}
onCheckedChange={(checked) => {
setKylesophyEnabled(checked);
setKylesophyLocal(checked);
}}
aria-label="Enable Kyleosophy"
/>
</div>
</div>
{showDefaultPromptPreview && (
<TextPreviewDialog
content={defaultSystemPrompt}
@@ -1,9 +1,12 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
getChimeEnabled,
getKylesophyEnabled,
KYLEOSOPHY_SOUNDS,
LOCK_HOLD_MS,
maybePlayChime,
setChimeEnabled,
setKylesophyEnabled,
} from "./chime";
// ---------------------------------------------------------------------------
@@ -69,6 +72,40 @@ describe("getChimeEnabled / setChimeEnabled", () => {
});
});
// ---------------------------------------------------------------------------
// Kyleosophy preference helpers
// ---------------------------------------------------------------------------
describe("getKylesophyEnabled / setKylesophyEnabled", () => {
beforeEach(() => {
localStorage.clear();
});
it("defaults to false when nothing is stored", () => {
expect(getKylesophyEnabled()).toBe(false);
});
it("returns true when stored as 'true'", () => {
localStorage.setItem("agents.kyleosophy", "true");
expect(getKylesophyEnabled()).toBe(true);
});
it("returns false when stored as 'false'", () => {
localStorage.setItem("agents.kyleosophy", "false");
expect(getKylesophyEnabled()).toBe(false);
});
it("setKylesophyEnabled persists the value", () => {
setKylesophyEnabled(false);
expect(localStorage.getItem("agents.kyleosophy")).toBe("false");
expect(getKylesophyEnabled()).toBe(false);
setKylesophyEnabled(true);
expect(localStorage.getItem("agents.kyleosophy")).toBe("true");
expect(getKylesophyEnabled()).toBe(true);
});
});
// ---------------------------------------------------------------------------
// maybePlayChime
// ---------------------------------------------------------------------------
@@ -235,4 +272,44 @@ describe("maybePlayChime", () => {
// Should play immediately without needing to advance timers.
expect(playSpy).toHaveBeenCalledTimes(1);
});
// -- Kyleosophy sound selection --
it("uses a kyleosophy sound when kyleosophy is enabled", async () => {
setKylesophyEnabled(true);
vi.spyOn(document, "hidden", "get").mockReturnValue(true);
// Pin the random selection so the test is deterministic.
vi.spyOn(Math, "random").mockReturnValue(0.5);
const audioSpy = vi.spyOn(globalThis, "Audio" as never);
await triggerAndSettle("running", "waiting", "chat-1", "chat-2");
expect(playSpy).toHaveBeenCalledTimes(1);
expect(audioSpy).toHaveBeenCalledTimes(1);
const url = (audioSpy as unknown as ReturnType<typeof vi.fn>).mock
.calls[0][0] as string;
// Math.floor(0.5 * 8) = 4 → "/chime_5.mp3"
expect(url).toBe("/chime_5.mp3");
expect(KYLEOSOPHY_SOUNDS).toContain(url);
});
it("uses default chime.mp3 when kyleosophy is disabled", async () => {
setKylesophyEnabled(false);
vi.spyOn(document, "hidden", "get").mockReturnValue(true);
// Force a fresh Audio element by spying on the constructor
// before any call in this test. The previous test left
// lastSoundUrl pointing at a kyleosophy URL, so switching
// back to /chime.mp3 will always trigger a new Audio().
const audioSpy = vi.spyOn(globalThis, "Audio" as never);
await triggerAndSettle("running", "waiting", "chat-1", "chat-2");
expect(playSpy).toHaveBeenCalledTimes(1);
expect(audioSpy).toHaveBeenCalledTimes(1);
const url = (audioSpy as unknown as ReturnType<typeof vi.fn>).mock
.calls[0][0] as string;
expect(url).toBe("/chime.mp3");
});
});
+52 -12
View File
@@ -1,4 +1,5 @@
const CHIME_PREFERENCE_KEY = "agents.chime-on-completion";
const KYLEOSOPHY_PREFERENCE_KEY = "agents.kyleosophy";
export function getChimeEnabled(): boolean {
try {
@@ -19,20 +20,55 @@ export function setChimeEnabled(enabled: boolean): void {
}
}
export function getKylesophyEnabled(): boolean {
try {
const stored = localStorage.getItem(KYLEOSOPHY_PREFERENCE_KEY);
return stored === null ? false : stored === "true";
} catch {
return false;
}
}
export function setKylesophyEnabled(enabled: boolean): void {
try {
localStorage.setItem(KYLEOSOPHY_PREFERENCE_KEY, String(enabled));
} catch {
// Silently ignore storage errors (e.g. private browsing
// quota exceeded).
}
}
/**
* Play the completion chime audio file. The file is a short,
* warm two-tone bell sound shipped as a static asset.
*
* A single Audio element is reused across calls so the browser
* only fetches the file once.
* Alternative completion sounds for Kyleosophy mode. All are
* shipped as static assets alongside chime.mp3.
*/
export const KYLEOSOPHY_SOUNDS: readonly string[] = [
"/chime_1.mp3", // absolutely massive
"/chime_2.mp3", // dope
"/chime_3.mp3", // great
"/chime_4.mp3", // oh god
"/chime_5.mp3", // okay
"/chime_6.mp3", // open up a pr
"/chime_7.mp3", // sweet
"/chime_8.mp3", // yep
];
/**
* Play a completion sound. When Kyleosophy is enabled a random
* voice clip is selected; otherwise the default bell chime is
* used. The Audio element is cached and reused when the sound
* URL hasn't changed between calls.
*/
let chimeAudio: HTMLAudioElement | null = null;
let lastSoundUrl: string | null = null;
function playChimeAudio(): void {
function playChimeAudio(soundUrl = "/chime.mp3"): void {
try {
if (!chimeAudio) {
chimeAudio = new Audio("/chime.mp3");
if (!chimeAudio || soundUrl !== lastSoundUrl) {
chimeAudio?.pause();
chimeAudio = new Audio(soundUrl);
chimeAudio.volume = 0.5;
lastSoundUrl = soundUrl;
}
// Reset to the start in case a previous play hasn't
// finished yet.
@@ -75,9 +111,9 @@ export const LOCK_HOLD_MS = 2000;
* Falls back to playing immediately when the Web Locks API is
* not available (preserving the original single-tab behavior).
*/
function playChime(chatID: string): void {
function playChime(chatID: string, soundUrl?: string): void {
if (typeof navigator === "undefined" || !navigator.locks) {
playChimeAudio();
playChimeAudio(soundUrl);
return;
}
@@ -93,7 +129,7 @@ function playChime(chatID: string): void {
return;
}
playChimeAudio();
playChimeAudio(soundUrl);
// Hold the lock briefly so that tabs receiving the
// WebSocket event a bit later will see the lock as
@@ -149,5 +185,9 @@ export function maybePlayChime(
return;
}
playChime(chatID);
const soundUrl = getKylesophyEnabled()
? KYLEOSOPHY_SOUNDS[Math.floor(Math.random() * KYLEOSOPHY_SOUNDS.length)]
: undefined;
playChime(chatID, soundUrl);
}