Files
openclaw/packages/memory-host-sdk/src/host/batch-error-utils.ts
ZOOWH fb702e5cae fix(memory): harden embedding batch workflows (#103472)
* fix(memory): harden embedding batch workflows

Co-authored-by: 徐闻涵0668001344 <xu.wenhan1@xydigit.com>
Co-authored-by: ben.li <li.yang6@xydigit.com>

* test(memory): align batch redaction expectation

* test(memory): tighten batch dependency types

* refactor(google): clarify batch state control flow

* test(google): make batch stage fallback lint-safe

* build(plugin-sdk): refresh memory batch surface budget

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: ben.li <li.yang6@xydigit.com>
2026-07-11 16:43:58 -07:00

69 lines
2.7 KiB
TypeScript

// Memory Host SDK helper module supports batch error utils behavior.
import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
import type { EmbeddingBatchOutputLine } from "./batch-output.js";
import { formatErrorMessage } from "./error-utils.js";
// Extracts provider batch error text from output and unavailable error files.
const BATCH_ERROR_DETAIL_MAX_CHARS = 500;
const BATCH_ERROR_DETAIL_TRUNCATED_SUFFIX = "... [truncated]";
const EMBEDDING_BATCH_UNAVAILABLE_CODE = "embedding_batch_unavailable";
/** Signals that a provider cannot run the configured embedding batch operation. */
export class EmbeddingBatchUnavailableError extends Error {
readonly code = EMBEDDING_BATCH_UNAVAILABLE_CODE;
constructor(message: string, options?: ErrorOptions) {
super(message, options);
this.name = "EmbeddingBatchUnavailableError";
}
}
export function isEmbeddingBatchUnavailableError(error: unknown): boolean {
if (!error || typeof error !== "object") {
return false;
}
try {
return (error as { code?: unknown }).code === EMBEDDING_BATCH_UNAVAILABLE_CODE;
} catch {
return false;
}
}
/** Pull a nested response error message without assuming a fixed provider body shape. */
function getResponseErrorMessage(line: EmbeddingBatchOutputLine | undefined): string | undefined {
const body = line?.response?.body;
if (typeof body === "string") {
return body || line?.response?.message || undefined;
}
if (!body || typeof body !== "object") {
return line?.response?.message || undefined;
}
return body.error?.message || line?.response?.message || undefined;
}
/** Return the first useful error message from batch output lines. */
export function extractBatchErrorMessage(lines: EmbeddingBatchOutputLine[]): string | undefined {
const first = lines.find((line) => line.error?.message || getResponseErrorMessage(line));
return first?.error?.message || getResponseErrorMessage(first);
}
/** Redact and bound provider-controlled batch diagnostics before logging them. */
export function formatBatchErrorDetail(detail: string | undefined): string | undefined {
if (!detail) {
return undefined;
}
const formatted = formatErrorMessage(detail);
if (formatted.length <= BATCH_ERROR_DETAIL_MAX_CHARS) {
return formatted;
}
const prefixLength = BATCH_ERROR_DETAIL_MAX_CHARS - BATCH_ERROR_DETAIL_TRUNCATED_SUFFIX.length;
return `${truncateUtf16Safe(formatted, prefixLength)}${BATCH_ERROR_DETAIL_TRUNCATED_SUFFIX}`;
}
/** Format a failed error-file read without hiding the underlying read problem. */
export function formatUnavailableBatchError(err: unknown): string | undefined {
const message = formatBatchErrorDetail(formatErrorMessage(err));
return message ? `error file unavailable: ${message}` : undefined;
}