Skip to content

Commit 8c60fb4

Browse files
author
SAGE
committed
perf(voiceclaw-realtime, server-maintenance): audit-driven hot-path wins
Acted on the SAGE-side optimization audit (~/Documents/sage/self-improvement-audit/report.md, openclaw section). #1 β€” xai-realtime.ts:719 β€” replace per-overflow O(n) `.shift()` with batched 25% splice. Hot voice path; under sustained overflow the old shift-per-push was N*overflow_count. Batch trim drops 25% in one splice so amortized per-push cost is O(1) (audio overflow always meant data loss anyway; trimming a quarter at once is cleaner than dropping one frame at a time). #7 β€” server-maintenance.ts:93 β€” `[...map.entries()].toSorted(...)` allocates two distinct copies (spread + toSorted internal). Switched to single Array.from(...) + in-place .sort(). Drops one allocation per maintenance tick. #8 β€” xai-realtime.ts:698 + isValidXaiVoice β€” `.find()` / `.includes()` over the const XAI_VOICES tuple was O(N) per voice resolution. Pre-built `_XAI_VOICE_SET = new Set(XAI_VOICES)`; lookups are now O(1). Skipped #2 (audit suggested merging 4 server-maintenance Map iterations into one β€” they touch DIFFERENT collections; merging would be artificial code, not real perf). Multi-day refactors of attempt.ts / loader.ts / chat.ts deferred per audit recommendation.
1 parent 6854786 commit 8c60fb4

2 files changed

Lines changed: 21 additions & 6 deletions

File tree

β€Žsrc/gateway/server-maintenance.tsβ€Ž

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,13 @@ export function startGatewayMaintenanceTimers(params: {
9090
}
9191
}
9292
if (params.dedupe.size > DEDUPE_MAX) {
93-
const entries = [...params.dedupe.entries()].toSorted((a, b) => a[1].ts - b[1].ts);
94-
for (let i = 0; i < params.dedupe.size - DEDUPE_MAX; i++) {
93+
// pt 235n (audit #7) β€” was [...map.entries()].toSorted(...).
94+
// Both spread + toSorted allocate distinct copies. Single
95+
// Array.from + in-place sort drops one allocation per tick.
96+
const entries = Array.from(params.dedupe.entries());
97+
entries.sort((a, b) => a[1].ts - b[1].ts);
98+
const target = params.dedupe.size - DEDUPE_MAX;
99+
for (let i = 0; i < target; i++) {
95100
params.dedupe.delete(entries[i][0]);
96101
}
97102
}

β€Žsrc/gateway/voiceclaw-realtime/xai-realtime.tsβ€Ž

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ const DEFAULT_OUTPUT_AUDIO_FORMAT = "pcm16";
2727
// https://docs.x.ai/developers/model-capabilities/audio/voice-agent
2828
export const XAI_VOICES = ["eve", "ara", "rex", "sal", "leo"] as const;
2929
export type XaiVoice = (typeof XAI_VOICES)[number];
30+
31+
// pt 235n (audit #8) β€” Set lookup avoids the per-voice-resolution
32+
// linear .find() / .includes() walk over the const tuple.
33+
const _XAI_VOICE_SET: ReadonlySet<string> = new Set(XAI_VOICES);
3034
export const DEFAULT_XAI_VOICE: XaiVoice = "ara";
3135

3236
type XaiMessage = Record<string, unknown>;
@@ -695,12 +699,13 @@ export function resolveXaiVoice(voice?: string): XaiVoice {
695699
return DEFAULT_XAI_VOICE;
696700
}
697701
const normalized = voice.toLowerCase();
698-
const match = XAI_VOICES.find((candidate) => candidate === normalized);
699-
return match ?? DEFAULT_XAI_VOICE;
702+
// pt 235n β€” O(1) Set lookup
703+
return _XAI_VOICE_SET.has(normalized) ? (normalized as XaiVoice) : DEFAULT_XAI_VOICE;
700704
}
701705

702706
export function isValidXaiVoice(voice: string): boolean {
703-
return (XAI_VOICES as readonly string[]).includes(voice.toLowerCase());
707+
// pt 235n β€” O(1) Set lookup
708+
return _XAI_VOICE_SET.has(voice.toLowerCase());
704709
}
705710

706711
function queueBounded(
@@ -716,7 +721,12 @@ function queueBounded(
716721
}
717722
if (kind === "audio") {
718723
if (queues.audio.length >= MAX_PENDING_AUDIO) {
719-
queues.audio.shift();
724+
// pt 235n (audit #1) β€” was .shift() per overflow which is
725+
// O(n) array shift. Hot voice path; under sustained
726+
// overflow that's N*shift_count. Batch-trim 25% in a
727+
// single splice so the amortized per-push cost is O(1).
728+
const drop = Math.max(1, Math.floor(MAX_PENDING_AUDIO / 4));
729+
queues.audio.splice(0, drop);
720730
}
721731
queues.audio.push(payload);
722732
return;

0 commit comments

Comments
Β (0)