@@ -24,6 +24,7 @@ import { refreshTokenIfNeeded } from '@/app/api/auth/oauth/utils'
2424import { projectResolvedSecretModelContent } from '@/executor/utils/resolved-secret-content-projection'
2525import type { ResolvedSecretTraceRegistry } from '@/executor/utils/resolved-secret-trace-registry'
2626import { executeProviderRequest } from '@/providers'
27+ import { isAbortError } from '@/providers/streaming-tool-loop-shared'
2728import { getProviderFromModel } from '@/providers/utils'
2829
2930const logger = createLogger ( 'HallucinationValidator' )
@@ -298,6 +299,11 @@ Evaluate the consistency and provide your score and reasoning in JSON format.`
298299 cost,
299300 }
300301 } catch ( error : any ) {
302+ /**
303+ * A cancelled run is not a scoring failure. Rewrapping it would erase the
304+ * `AbortError` name the outer handler classifies on, so it propagates as-is.
305+ */
306+ if ( isAbortError ( error ) ) throw error
301307 logger . error ( `[${ requestId } ] Error scoring with LLM` , {
302308 error : error . message ,
303309 } )
@@ -402,6 +408,12 @@ export async function validateHallucination(
402408 : `Low confidence: score ${ score } /10 is below threshold ${ threshold } ` ,
403409 }
404410 } catch ( error : any ) {
411+ /**
412+ * Cancellation is surfaced as cancellation, not as a guardrail verdict. Returning
413+ * `passed: false` here would fail content on a run the caller abandoned, which is
414+ * indistinguishable to a consumer from the model actually hallucinating.
415+ */
416+ if ( isAbortError ( error ) ) throw error
405417 logger . error ( `[${ requestId } ] Hallucination validation error` , {
406418 error : error . message ,
407419 } )
0 commit comments