mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-09 16:21:15 +00:00
* feat(tts): add structured fallback diagnostics and attempt analytics * docs(tts): document attempt-detail and provider error diagnostics * TTS: harden fallback loops and share error helpers * TTS: bound provider error-body reads * tts: add double-prefix regression test and clean baseline drift * tests(tts): satisfy error narrowing in double-prefix regression * changelog Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com> --------- Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>
63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
export function trimToUndefined(value: unknown): string | undefined {
|
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
}
|
|
|
|
export function asObject(value: unknown): Record<string, unknown> | undefined {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
? (value as Record<string, unknown>)
|
|
: undefined;
|
|
}
|
|
|
|
export function truncateErrorDetail(detail: string, limit = 220): string {
|
|
return detail.length <= limit ? detail : `${detail.slice(0, limit - 1)}…`;
|
|
}
|
|
|
|
export async function readResponseTextLimited(
|
|
response: Response,
|
|
limitBytes = 16 * 1024,
|
|
): Promise<string> {
|
|
if (limitBytes <= 0) {
|
|
return "";
|
|
}
|
|
const reader = response.body?.getReader();
|
|
if (!reader) {
|
|
return "";
|
|
}
|
|
|
|
const decoder = new TextDecoder();
|
|
let total = 0;
|
|
let text = "";
|
|
let reachedLimit = false;
|
|
|
|
try {
|
|
while (true) {
|
|
const { value, done } = await reader.read();
|
|
if (done) {
|
|
break;
|
|
}
|
|
if (!value || value.byteLength === 0) {
|
|
continue;
|
|
}
|
|
const remaining = limitBytes - total;
|
|
if (remaining <= 0) {
|
|
reachedLimit = true;
|
|
break;
|
|
}
|
|
const chunk = value.byteLength > remaining ? value.subarray(0, remaining) : value;
|
|
total += chunk.byteLength;
|
|
text += decoder.decode(chunk, { stream: true });
|
|
if (total >= limitBytes) {
|
|
reachedLimit = true;
|
|
break;
|
|
}
|
|
}
|
|
text += decoder.decode();
|
|
} finally {
|
|
if (reachedLimit) {
|
|
await reader.cancel().catch(() => {});
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|