




















@@ -374,10 +374,60 @@ function stringifyRedactedEvent(value: unknown): string {
374374return redacted.length > 2000 ? `${redacted.slice(0, 2000)}…<truncated>` : redacted;
375375}
376376377-function readRecordString(record: Record<string, unknown> | undefined, key: string): string {
377+type ResponsesFailedNoDetailsObservation = {
378+event: "openai_responses_response_failed_without_details";
379+provider: string;
380+api: Api;
381+transportModel: string;
382+providerRuntimeFailureKind: "no_error_details";
383+responseId: string;
384+responseStatus: string;
385+responseModel: string;
386+responseObject: string;
387+metadataKeys: string[];
388+requestIdHashes: string[];
389+failureFieldsPreview: string;
390+responsePreview: string;
391+};
392+393+type ResponsesFailedEventSummary = {
394+message: string;
395+responseId?: string;
396+observation?: ResponsesFailedNoDetailsObservation;
397+};
398+399+const RESPONSE_FAILED_FAILURE_FIELD_KEYS = [
400+"error",
401+"incomplete_details",
402+"status_details",
403+"failure_reason",
404+"last_error",
405+"provider_error",
406+"error_details",
407+] as const;
408+409+function readResponseFailedString(
410+record: Record<string, unknown> | undefined,
411+key: string,
412+): string {
378413return stringifyUnknown(record?.[key]);
379414}
380415416+function buildResponsesFailedEventSummary(
417+message: string,
418+responseId: string | undefined,
419+observation?: ResponsesFailedNoDetailsObservation,
420+): ResponsesFailedEventSummary {
421+const summary: ResponsesFailedEventSummary = { message };
422+if (responseId) {
423+summary.responseId = responseId;
424+}
425+if (observation) {
426+summary.observation = observation;
427+}
428+return summary;
429+}
430+381431function isResponseFailedIdentifierKey(key: string): boolean {
382432const normalized = key.replace(/[-_\s]/g, "").toLowerCase();
383433return (
@@ -456,7 +506,7 @@ function collectResponseFailedIdentifierHashes(
456506return out;
457507}
458508459-function redactResponseFailedIdentifierFields(
509+function redactResponseFailedDiagnosticValue(
460510value: unknown,
461511opts: {
462512key?: string;
@@ -481,7 +531,7 @@ function redactResponseFailedIdentifierFields(
481531seen.add(value);
482532if (Array.isArray(value)) {
483533return value.slice(0, 16).map((item) =>
484-redactResponseFailedIdentifierFields(item, {
534+redactResponseFailedDiagnosticValue(item, {
485535 key,
486536depth: depth + 1,
487537 seen,
@@ -490,7 +540,7 @@ function redactResponseFailedIdentifierFields(
490540}
491541const out: Record<string, unknown> = {};
492542for (const [childKey, child] of Object.entries(value as Record<string, unknown>)) {
493-out[childKey] = redactResponseFailedIdentifierFields(child, {
543+out[childKey] = redactResponseFailedDiagnosticValue(child, {
494544key: childKey,
495545depth: depth + 1,
496546 seen,
@@ -499,20 +549,14 @@ function redactResponseFailedIdentifierFields(
499549return out;
500550}
501551502-function buildResponsesFailedFailureFields(response: Record<string, unknown> | undefined) {
552+function buildResponsesFailedFailureFields(
553+response: Record<string, unknown> | undefined,
554+): Record<string, unknown> {
503555if (!response) {
504556return {};
505557}
506558const fields: Record<string, unknown> = {};
507-for (const key of [
508-"error",
509-"incomplete_details",
510-"status_details",
511-"failure_reason",
512-"last_error",
513-"provider_error",
514-"error_details",
515-]) {
559+for (const key of RESPONSE_FAILED_FAILURE_FIELD_KEYS) {
516560if (response[key] !== undefined && response[key] !== null) {
517561fields[key] = response[key];
518562}
@@ -523,20 +567,23 @@ function buildResponsesFailedFailureFields(response: Record<string, unknown> | u
523567function buildResponsesFailedNoDetailsObservation(
524568event: Record<string, unknown>,
525569model: Model<Api>,
526-) {
527-const response = isRecord(event.response) ? event.response : undefined;
528-const failureFields = redactResponseFailedIdentifierFields(
570+response: Record<string, unknown> | undefined = isRecord(event.response)
571+ ? event.response
572+ : undefined,
573+): ResponsesFailedNoDetailsObservation {
574+const failureFields = redactResponseFailedDiagnosticValue(
529575buildResponsesFailedFailureFields(response),
530576) as Record<string, unknown>;
577+const metadataKeys = isRecord(response?.metadata)
578+ ? Object.keys(response.metadata).toSorted()
579+ : [];
531580const responsePreview = {
532-id: readRecordString(response, "id"),
533-status: readRecordString(response, "status"),
534-model: readRecordString(response, "model"),
535-object: readRecordString(response, "object"),
581+id: readResponseFailedString(response, "id"),
582+status: readResponseFailedString(response, "status"),
583+model: readResponseFailedString(response, "model"),
584+object: readResponseFailedString(response, "object"),
536585 failureFields,
537-metadataKeys: isRecord(response?.metadata)
538- ? Object.keys(response.metadata).toSorted().join(",")
539- : "",
586+ metadataKeys,
540587};
541588return {
542589event: "openai_responses_response_failed_without_details",
@@ -547,33 +594,66 @@ function buildResponsesFailedNoDetailsObservation(
547594responseId: responsePreview.id,
548595responseStatus: responsePreview.status,
549596responseModel: responsePreview.model,
597+responseObject: responsePreview.object,
598+ metadataKeys,
550599requestIdHashes: collectResponseFailedIdentifierHashes(event),
551600failureFieldsPreview: stringifyRedactedEvent(failureFields),
552601responsePreview: stringifyRedactedEvent(responsePreview),
553602};
554603}
555604556605function summarizeResponsesFailedNoDetailsObservation(
557-observation: ReturnType<typeof buildResponsesFailedNoDetailsObservation>,
606+observation: ResponsesFailedNoDetailsObservation,
558607): string {
559608const requestIds = observation.requestIdHashes.join(",");
609+const metadataKeys = observation.metadataKeys.join(",");
560610return (
561611`responseId=${safeDebugValue(observation.responseId || undefined)} ` +
562612`responseStatus=${safeDebugValue(observation.responseStatus || undefined)} ` +
563613`responseModel=${safeDebugValue(observation.responseModel || undefined)} ` +
564-`requestIds=${requestIds || "none"} response=${observation.responsePreview}`
614+`requestIds=${requestIds || "none"} metadataKeys=${metadataKeys || "none"} ` +
615+`failureFields=${observation.failureFieldsPreview}`
565616);
566617}
567618568-function responseFailedErrorMessage(
569-error: { code?: unknown; message?: unknown } | null | undefined,
570-): string | undefined {
571-const code = stringifyUnknown(error?.code).trim();
572-const message = stringifyUnknown(error?.message).trim();
573-if (!code && !message) {
574-return undefined;
619+function normalizeResponsesFailedEvent(
620+event: Record<string, unknown>,
621+model: Model<Api>,
622+): ResponsesFailedEventSummary {
623+const response = isRecord(event.response) ? event.response : undefined;
624+const responseId = readResponseFailedString(response, "id") || undefined;
625+const error = isRecord(response?.error) ? response.error : undefined;
626+if (error) {
627+const code = readResponseFailedString(error, "code").trim();
628+const message = readResponseFailedString(error, "message").trim();
629+if (code || message) {
630+return buildResponsesFailedEventSummary(
631+`${code || "unknown"}: ${message || "no message"}`,
632+responseId,
633+);
634+}
575635}
576-return `${code || "unknown"}: ${message || "no message"}`;
636+const incompleteDetails = isRecord(response?.incomplete_details)
637+ ? response.incomplete_details
638+ : undefined;
639+const incompleteReason = readResponseFailedString(incompleteDetails, "reason");
640+if (incompleteReason) {
641+return buildResponsesFailedEventSummary(`incomplete: ${incompleteReason}`, responseId);
642+}
643+return buildResponsesFailedEventSummary(
644+RESPONSE_FAILED_NO_DETAILS_MESSAGE,
645+responseId,
646+buildResponsesFailedNoDetailsObservation(event, model, response),
647+);
648+}
649+650+function logResponsesFailedNoDetails(observation: ResponsesFailedNoDetailsObservation): void {
651+log.warn(
652+`[responses] response.failed missing error details provider=${observation.provider} ` +
653+`api=${observation.api} model=${observation.transportModel} ` +
654+summarizeResponsesFailedNoDetailsObservation(observation),
655+observation,
656+);
577657}
578658579659function summarizeResponsesPayload(params: unknown): string {
@@ -1165,31 +1245,14 @@ async function processResponsesStream(
11651245`Error Code ${stringifyUnknown(event.code, "unknown")}: ${stringifyUnknown(event.message, "Unknown error")}`,
11661246);
11671247} else if (type === "response.failed") {
1168-const response = event.response as
1169-| {
1170-id?: string;
1171-error?: { code?: unknown; message?: unknown } | null;
1172-incomplete_details?: { reason?: string };
1173-}
1174-| undefined;
1175-if (typeof response?.id === "string") {
1176-output.responseId = response.id;
1248+const failure = normalizeResponsesFailedEvent(event, model);
1249+if (failure.responseId) {
1250+output.responseId = failure.responseId;
11771251}
1178-const detailedErrorMessage = responseFailedErrorMessage(response?.error);
1179-const msg = detailedErrorMessage
1180- ? detailedErrorMessage
1181- : response?.incomplete_details?.reason
1182- ? `incomplete: ${response.incomplete_details.reason}`
1183- : RESPONSE_FAILED_NO_DETAILS_MESSAGE;
1184-if (msg === RESPONSE_FAILED_NO_DETAILS_MESSAGE) {
1185-const observation = buildResponsesFailedNoDetailsObservation(event, model);
1186-log.warn(
1187-`[responses] response.failed missing error details provider=${model.provider} api=${model.api} model=${model.id} ` +
1188-summarizeResponsesFailedNoDetailsObservation(observation),
1189-observation,
1190-);
1252+if (failure.observation) {
1253+logResponsesFailedNoDetails(failure.observation);
11911254}
1192-throw new Error(msg);
1255+throw new Error(failure.message);
11931256}
11941257await cooperativeScheduler.afterEvent();
11951258}
@@ -3013,6 +3076,7 @@ export const __testing = {
30133076 processResponsesStream,
30143077 formatModelTransportDebugBaseUrl,
30153078 buildResponsesFailedNoDetailsObservation,
3079+ normalizeResponsesFailedEvent,
30163080 summarizeResponsesFailedNoDetailsObservation,
30173081 summarizeResponsesPayload,
30183082 summarizeResponsesTools,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。