fix(talk): expose one transcript queue policy

This commit is contained in:
Vincent Koc
2026-08-01 13:21:05 +08:00
parent 137b65b4a9
commit b786f4a804
3 changed files with 27 additions and 15 deletions
+4 -1
View File
@@ -41,10 +41,13 @@ import {
import {
createVoiceTranscriptOperationRegistry,
normalizeVoiceTranscriptText,
VOICE_TRANSCRIPT_QUEUE_POLICY,
} from "./voice-transcript.js";
const voiceSessionByRunId = new Map<string, ClientVoiceRunBinding>();
const voiceSessionOperations = createVoiceTranscriptOperationRegistry();
const voiceSessionOperations = createVoiceTranscriptOperationRegistry(
VOICE_TRANSCRIPT_QUEUE_POLICY,
);
const deferredDigestConfigs = new Map<string, OpenClawConfig>();
let unsubscribeToolEffects: (() => void) | undefined;
let unsubscribeRunCompletion: (() => void) | undefined;
+3 -3
View File
@@ -1,7 +1,7 @@
import { describe, expect, it, vi } from "vitest";
import {
createVoiceTranscriptOperationRegistry,
VOICE_TRANSCRIPT_QUEUE_MAX_PENDING,
VOICE_TRANSCRIPT_QUEUE_POLICY,
} from "./voice-transcript.js";
function deferred(): { promise: Promise<void>; resolve: () => void } {
@@ -14,12 +14,12 @@ function deferred(): { promise: Promise<void>; resolve: () => void } {
describe("VoiceTranscriptOperationRegistry", () => {
it("keeps overflow terminal through drain and releases it only on close", async () => {
const registry = createVoiceTranscriptOperationRegistry();
const registry = createVoiceTranscriptOperationRegistry(VOICE_TRANSCRIPT_QUEUE_POLICY);
const first = deferred();
const key = "agent\0voice-overflow";
const accepted = [
registry.run(key, async () => await first.promise),
...Array.from({ length: VOICE_TRANSCRIPT_QUEUE_MAX_PENDING }, () =>
...Array.from({ length: VOICE_TRANSCRIPT_QUEUE_POLICY.maxPendingCount }, () =>
registry.run(key, async () => undefined),
),
];
+20 -11
View File
@@ -2,22 +2,25 @@ import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
import { BoundedSerialQueue } from "../shared/bounded-serial-queue.js";
const VOICE_TRANSCRIPT_MAX_CHARS = 8_000;
export const VOICE_TRANSCRIPT_QUEUE_MAX_PENDING = 40;
const VOICE_TRANSCRIPT_QUEUE_MAX_PENDING = 40;
const VOICE_TRANSCRIPT_QUEUE_MAX_PENDING_CHARS =
VOICE_TRANSCRIPT_QUEUE_MAX_PENDING * VOICE_TRANSCRIPT_MAX_CHARS;
export const VOICE_TRANSCRIPT_QUEUE_OVERFLOW_MESSAGE =
const VOICE_TRANSCRIPT_QUEUE_OVERFLOW_MESSAGE =
"Voice transcript persistence could not keep up; the realtime session was stopped.";
export function normalizeVoiceTranscriptText(text: string): string {
return truncateUtf16Safe(text.trim(), VOICE_TRANSCRIPT_MAX_CHARS);
}
export function createVoiceTranscriptQueue(): BoundedSerialQueue {
return new BoundedSerialQueue({
maxPendingCount: VOICE_TRANSCRIPT_QUEUE_MAX_PENDING,
maxPendingWeight: VOICE_TRANSCRIPT_QUEUE_MAX_PENDING_CHARS,
});
}
export const VOICE_TRANSCRIPT_QUEUE_POLICY = {
maxPendingCount: VOICE_TRANSCRIPT_QUEUE_MAX_PENDING,
overflowMessage: VOICE_TRANSCRIPT_QUEUE_OVERFLOW_MESSAGE,
createQueue: () =>
new BoundedSerialQueue({
maxPendingCount: VOICE_TRANSCRIPT_QUEUE_MAX_PENDING,
maxPendingWeight: VOICE_TRANSCRIPT_QUEUE_MAX_PENDING_CHARS,
}),
} as const;
type VoiceTranscriptOperationOwner = {
queue: BoundedSerialQueue;
@@ -27,12 +30,16 @@ type VoiceTranscriptOperationOwner = {
class VoiceTranscriptOperationRegistry {
private readonly owners = new Map<string, VoiceTranscriptOperationOwner>();
constructor(
private readonly queuePolicy: Pick<typeof VOICE_TRANSCRIPT_QUEUE_POLICY, "createQueue">,
) {}
private getOrCreate(key: string): VoiceTranscriptOperationOwner {
const existing = this.owners.get(key);
if (existing) {
return existing;
}
const created = { queue: createVoiceTranscriptQueue() };
const created = { queue: this.queuePolicy.createQueue() };
this.owners.set(key, created);
return created;
}
@@ -115,6 +122,8 @@ class VoiceTranscriptOperationRegistry {
}
}
export function createVoiceTranscriptOperationRegistry(): VoiceTranscriptOperationRegistry {
return new VoiceTranscriptOperationRegistry();
export function createVoiceTranscriptOperationRegistry(
queuePolicy: Pick<typeof VOICE_TRANSCRIPT_QUEUE_POLICY, "createQueue">,
): VoiceTranscriptOperationRegistry {
return new VoiceTranscriptOperationRegistry(queuePolicy);
}