fix(native): do not also report a classified model rejection as unclassified

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DottaandClaude Opus 5.5 committed 2026-11-07 16:09:54 -06:00
1 parent f04cbfd134
commit ca973e3b13
2 files changed
+12 -3

No files matched your search

@@ -40,6 +40,10 @@ describe("native provider failure observation", () => {
const result = observed.forTerminal("turn", terminal);
expect(result).toMatchObject({ errorCode: "native_provider_model_rejected", errorMessage: NATIVE_MODEL_REJECTION_MESSAGE });
expect(JSON.stringify(result)).not.toContain("private-model");
// A closed diagnostic only, and the classified turn is not also reported as unclassified.
expect(result?.diagnostic).toEqual(expect.objectContaining({ provider: kind }));
expect(JSON.stringify(result?.diagnostic)).not.toContain("not a valid model");
expect(observed.unclassifiedTurnFailure("turn", terminal)).toBeNull();
expect(observed.forTerminal("other-turn", terminal)).toBeNull();
expect(observed.forTerminal("turn", { ...terminal, runTerminalState: "succeeded" })).toBeNull();
});
@@ -216,6 +216,11 @@ export function createNativeProviderFailureObservation(provider: { kind: string;
let overloadedTurnId: string | null = null;
const failedTurns = new Map<string, NativeTurnFailureDiagnostic>();
const providerFailures = new Map<string, ProviderFailure>();
/** A driver-classified, action-required model rejection; `forTerminal` classifies it, so it is not "unclassified". */
const modelUnavailableTurn = (turnId: string) => {
const failure = providerFailures.get(turnId);
return failure?.category === "model_unavailable" && failure.retryability === "requires_action";
};
return {
observe(event: PrpEvent) {
if (event.sourceKind === "runner" && event.eventType === "turn.failed" && event.turnId
@@ -270,8 +275,8 @@ export function createNativeProviderFailureObservation(provider: { kind: string;
if (turnId !== rejectedTurnId) {
// A driver's closed category marks a rejected model for any provider. Only an
// action-required rejection qualifies; a transient one may succeed on retry.
const failure = providerFailures.get(turnId);
if (failure?.category !== "model_unavailable" || failure.retryability !== "requires_action") return null;
if (!modelUnavailableTurn(turnId)) return null;
const failure = providerFailures.get(turnId)!;
return {
errorCode: "native_provider_model_rejected" as const,
errorMessage: NATIVE_MODEL_REJECTION_MESSAGE,
@@ -287,7 +292,7 @@ export function createNativeProviderFailureObservation(provider: { kind: string;
/** Diagnostics only: the failed turn that `forTerminal` did not classify. */
unclassifiedTurnFailure(turnId: string | null | undefined, terminal: PrpTerminalState) {
if (!turnId || terminal.turnTerminalState !== "failed" || terminal.runTerminalState !== "failed" ||
turnId === overloadedTurnId || turnId === rejectedTurnId) return null;
turnId === overloadedTurnId || turnId === rejectedTurnId || modelUnavailableTurn(turnId)) return null;
const diagnostic = failedTurns.get(turnId);
return diagnostic ? { ...diagnostic } : null;
},