fix(video): redact executor diagnostics

This commit is contained in:
diegosouzapw
2026-08-27 03:07:06 -03:00
parent 6d209a9128
commit ab60b95e31
4 changed files with 31 additions and 15 deletions

View File

@@ -202,6 +202,10 @@ export type ExecuteInput = {
* this to apply client-format-aware policies such as `</think>` close-marker
* suppression. */
clientResponseFormat?: string | null;
/** True when upstream diagnostics may echo a video transcript. Executors must
* preserve operational responses/errors while omitting those echoes from
* retained logs. */
videoTranscriptSensitive?: boolean;
/** Callback to persist tokens that are proactively refreshed during execution.
* Accepts a partial credentials patch (e.g. `{ accessToken, refreshToken }` or
* `{ testStatus: "expired", isActive: false }`); the caller merges into the

View File

@@ -1,4 +1,5 @@
import { randomUUID } from "node:crypto";
import { redactVideoTranscriptSensitiveText } from "../../src/lib/guardrails/videoTranscriptLogRedaction.ts";
import type { KeyHealth } from "../services/apiKeyRotator.ts";
import { DefaultExecutor } from "./default.ts";
@@ -45,6 +46,11 @@ function asRecord(value: unknown): JsonRecord | null {
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : null;
}
function retainGlmDiagnostic(error: unknown, input: ExecuteInput): string {
const message = error instanceof Error ? error.message : String(error);
return redactVideoTranscriptSensitiveText(message, input.videoTranscriptSensitive === true);
}
function getEffectiveKey(credentials: ProviderCredentials): string {
const extraKeys = (credentials.providerSpecificData?.extraApiKeys as string[] | undefined) ?? [];
if (credentials.apiKey && credentials.connectionId && extraKeys.length > 0) {
@@ -465,6 +471,7 @@ export class GlmExecutor extends DefaultExecutor {
timeoutMs: STREAM_READINESS_TIMEOUT_MS,
provider: this.provider,
model: input.model,
redactUpstreamDiagnosticForLog: input.videoTranscriptSensitive === true,
log: input.log,
});
response = readiness.response;
@@ -559,7 +566,7 @@ export class GlmExecutor extends DefaultExecutor {
if (!isRetryableGlmFallbackError(error)) throw error;
input.log?.debug?.(
"GLM_FALLBACK",
`${primaryTransport} error (${error instanceof Error ? error.message : String(error)}); trying ${fallbackTransport}`
`${primaryTransport} error (${retainGlmDiagnostic(error, input)}); trying ${fallbackTransport}`
);
}
@@ -572,7 +579,7 @@ export class GlmExecutor extends DefaultExecutor {
if (!primaryResult) throw error;
input.log?.debug?.(
"GLM_FALLBACK",
`${fallbackTransport} fallback failed (${error instanceof Error ? error.message : String(error)}); returning primary response`
`${fallbackTransport} fallback failed (${retainGlmDiagnostic(error, input)}); returning primary response`
);
}

View File

@@ -3173,6 +3173,7 @@ export async function handleChatCore({
userAgent
),
clientResponseFormat,
videoTranscriptSensitive,
onCredentialsRefreshed,
skipUpstreamRetry,
contextEditing: { enabled: contextEditingEnabled },
@@ -3489,6 +3490,7 @@ export async function handleChatCore({
userAgent
),
clientResponseFormat,
videoTranscriptSensitive,
onCredentialsRefreshed,
skipUpstreamRetry,
contextEditing: { enabled: contextEditingEnabled },
@@ -4036,6 +4038,7 @@ export async function handleChatCore({
upstreamExtraHeaders: buildUpstreamHeadersForExecute(retryModelId),
clientHeaders: buildExecutorClientHeaders(clientRawRequest?.headers, userAgent),
clientResponseFormat,
videoTranscriptSensitive,
onCredentialsRefreshed,
skipUpstreamRetry: isCombo,
contextEditing: { enabled: contextEditingEnabled },

View File

@@ -17,8 +17,10 @@
*/
import { getExecutor } from "../../executors/index.ts";
import type { ExecuteInput } from "../../executors/base.ts";
import { isCliproxyapiDeepModeEnabled } from "../../executors/cliproxyapi.ts";
import { isDarioDeepModeEnabled } from "../../executors/dario.ts";
import { redactVideoTranscriptSensitiveText } from "../../../src/lib/guardrails/videoTranscriptLogRedaction.ts";
import { getCachedSettings } from "@/lib/db/readCache";
import { getUpstreamProxyConfigCached } from "./comboContextCache.ts";
import type { FallbackBackend } from "@/lib/db/upstreamProxy";
@@ -48,6 +50,11 @@ function parseFallbackCodes(raw: unknown): number[] | null {
return parsed.length > 0 ? parsed : null;
}
function retainExecutorDiagnostic(error: unknown, input: ExecuteInput): string {
const message = error instanceof Error ? error.message : String(error);
return redactVideoTranscriptSensitiveText(message, input.videoTranscriptSensitive === true);
}
/**
* Reads the CLIProxyAPI-related settings shared by both the direct
* `mode: "cliproxyapi"` passthrough leg and the `mode: "fallback"` retry leg:
@@ -155,25 +162,20 @@ export async function resolveExecutorWithProxy(
const isRetryableStatus = (s: number) => fallbackCodes.includes(s) || s === 0;
const wrapper = Object.create(nativeExec);
wrapper.execute = async (input: {
model: string;
body: unknown;
stream: boolean;
credentials: unknown;
signal?: AbortSignal | null;
log?: unknown;
upstreamExtraHeaders?: Record<string, string> | null;
}) => {
wrapper.execute = async (input: ExecuteInput) => {
let result;
try {
result = await nativeExec.execute(input);
} catch (err) {
const errMsg = err instanceof Error ? err.message : String(err);
log?.info?.("UPSTREAM_PROXY", `${prov} native error (${errMsg}), retrying via ${backendLabel}`);
const errMsg = retainExecutorDiagnostic(err, input);
log?.info?.(
"UPSTREAM_PROXY",
`${prov} native error (${errMsg}), retrying via ${backendLabel}`
);
try {
return await proxyExec.execute(input);
} catch (proxyErr) {
const proxyMsg = proxyErr instanceof Error ? proxyErr.message : String(proxyErr);
const proxyMsg = retainExecutorDiagnostic(proxyErr, input);
log?.error?.("UPSTREAM_PROXY", `${prov} ${backendLabel} fallback also failed: ${proxyMsg}`);
throw proxyErr;
}
@@ -189,7 +191,7 @@ export async function resolveExecutorWithProxy(
try {
return await proxyExec.execute(input);
} catch (proxyErr) {
const proxyMsg = proxyErr instanceof Error ? proxyErr.message : String(proxyErr);
const proxyMsg = retainExecutorDiagnostic(proxyErr, input);
log?.error?.("UPSTREAM_PROXY", `${prov} ${backendLabel} fallback also failed: ${proxyMsg}`);
throw proxyErr;
}