@@ -13,12 +13,7 @@ import { noopAuditStore, permissiveAuthorize } from "@intx/agent/testing";
1313import { getLogger } from "@intx/log" ;
1414import { createOptimizedContextStore } from "../session/optimized-context-store.js" ;
1515import { type } from "arktype" ;
16- import {
17- buildCodexSource ,
18- buildOpenAISource ,
19- buildXaiSource ,
20- type Config ,
21- } from "../config/index.js" ;
16+ import { type Config } from "../config/index.js" ;
2217import {
2318 loadLocalSettings ,
2419 resolveLocalSettingsPath ,
@@ -63,7 +58,10 @@ import { createAgentToolset, type AgentToolset, type OperatorResult } from "../a
6358import { createAgentWithLiveToolDispatch } from "../agent/live-tool-dispatch.js" ;
6459import { liveTelemetry } from "../telemetry/singleton.js" ;
6560import { createTurnObserver } from "../telemetry/ai-observability.js" ;
66- import { terminalProviderFailureMessage } from "../inference-error-message.js" ;
61+ import {
62+ isResolvedProviderFailureError ,
63+ terminalProviderFailureMessage ,
64+ } from "../inference-error-message.js" ;
6765import { collectToolPlugins , resolveToolPlugins } from "../plugins/tool-plugins.js" ;
6866import {
6967 expandExistingPluginMembers ,
@@ -132,9 +130,13 @@ export async function refreshSelectedProviderCredential<T>(refresh: () => Promis
132130export function execUserFailureMessage (
133131 config : Config ,
134132 err : unknown ,
135- inferenceStarted : boolean ,
133+ providerFailureObserved : boolean ,
136134) : string {
137- if ( inferenceStarted || ( err instanceof Error && err . name === SELECTED_PROVIDER_FAILURE ) ) {
135+ if (
136+ providerFailureObserved ||
137+ isResolvedProviderFailureError ( err ) ||
138+ ( err instanceof Error && err . name === SELECTED_PROVIDER_FAILURE )
139+ ) {
138140 return terminalProviderFailureMessage (
139141 config . providerName ,
140142 config . settings ?. providers [ config . providerName ] ?. name ,
@@ -279,7 +281,7 @@ export async function runExec(config: Config): Promise<ExecResult> {
279281 let finalized = false ;
280282 let turnsUsed = 0 ;
281283 let runSink : RunSink | null = null ;
282- let inferenceStarted = false ;
284+ let providerFailureObserved = false ;
283285
284286 const persist = async (
285287 status : "running" | "done" | "failed" | "cancelled" ,
@@ -568,56 +570,14 @@ export async function runExec(config: Config): Promise<ExecResult> {
568570
569571 const initialCodexProfile = codexProfileFromProviderName ( config . providerName ) ;
570572 const initialXaiProfile = xaiProfileFromProviderName ( config . providerName ) ;
571- const initialCodexAccountId = config . providers . find (
572- ( p ) => p . name === config . providerName ,
573- ) ?. codexAccountId ;
574-
575- const buildOpenAICompatibleInitialSource = ( ) : InferenceSource =>
576- buildOpenAISource ( {
577- id : config . providerName ,
578- baseURL : config . baseURL ,
579- apiKey : config . apiKey ,
580- model : config . model ,
581- ...( config . reasoningEffort !== undefined
582- ? { reasoningEffort : config . reasoningEffort }
583- : { } ) ,
584- } ) ;
585-
586- const buildSessionSources = ( ) : { sources : InferenceSource [ ] ; defaultSource : string } =>
587- buildSessionSourcesFromConfig ( config , sessionId ) ;
588-
589- const initialBundle = buildSessionSources ( ) ;
573+ const initialBundle = buildSessionSourcesFromConfig ( config , sessionId ) ;
590574 const liveSources = initialBundle . sources ;
591575 const liveDefaultSource = initialBundle . defaultSource ;
592-
593- const buildInitialSourceFallback = ( ) : InferenceSource =>
594- initialCodexProfile !== undefined
595- ? buildCodexSource ( {
596- id : config . providerName ,
597- apiKey : config . apiKey ,
598- model : config . model ,
599- sessionId,
600- ...( initialCodexAccountId !== undefined ? { accountId : initialCodexAccountId } : { } ) ,
601- ...( config . reasoningEffort !== undefined
602- ? { reasoningEffort : config . reasoningEffort }
603- : { } ) ,
604- } )
605- : initialXaiProfile !== undefined
606- ? buildXaiSource ( {
607- id : config . providerName ,
608- apiKey : config . apiKey ,
609- model : config . model ,
610- sessionId,
611- ...( config . reasoningEffort !== undefined
612- ? { reasoningEffort : config . reasoningEffort }
613- : { } ) ,
614- } )
615- : buildOpenAICompatibleInitialSource ( ) ;
616-
617- let liveSource : InferenceSource =
618- liveSources . find ( ( s ) => s . id === liveDefaultSource ) ??
619- liveSources [ 0 ] ??
620- buildInitialSourceFallback ( ) ;
576+ const selectedSource = liveSources [ 0 ] ;
577+ if ( selectedSource === undefined ) {
578+ throw new Error ( "Selected inference source was not assembled" ) ;
579+ }
580+ let liveSource : InferenceSource = selectedSource ;
621581
622582 // Refresh pinned Codex instructions before first inference, same as the
623583 // TUI path. Best-effort: a network failure falls back to the disk cache
@@ -748,6 +708,11 @@ export async function runExec(config: Config): Promise<ExecResult> {
748708 // its partial output in partial.jsonl instead of vanishing.
749709 const cycleRecorder = createCycleTextRecorder ( ( ) => workdir ) ;
750710 const sink = ( event : ReactorEmittedEvent ) : void => {
711+ if ( event . type === "inference.start" || event . type === "inference.done" ) {
712+ providerFailureObserved = false ;
713+ } else if ( event . type === "inference.error" ) {
714+ providerFailureObserved = true ;
715+ }
751716 liveSink . sink ( event ) ;
752717 cycleRecorder . handleEvent ( event ) ;
753718 if ( event . type === "inference.text.delta" ) {
@@ -771,7 +736,6 @@ export async function runExec(config: Config): Promise<ExecResult> {
771736 let runError : string | undefined ;
772737 let sinkStatus : ReturnType < typeof liveSink . getStatus > = "cancelled" ;
773738 try {
774- inferenceStarted = true ;
775739 // Final OAuth refresh immediately before send (token may have aged during MCP).
776740 if ( initialCodexProfile !== undefined ) {
777741 const { access } = await getValidCodexToken ( initialCodexProfile ) ;
@@ -912,7 +876,7 @@ export async function runExec(config: Config): Promise<ExecResult> {
912876 } catch ( err ) {
913877 const diagnosticMessage = formatCaughtError ( err ) ;
914878 logger . error ( "exec failed: {error}" , { error : diagnosticMessage } ) ;
915- const userMessage = execUserFailureMessage ( config , err , inferenceStarted ) ;
879+ const userMessage = execUserFailureMessage ( config , err , providerFailureObserved ) ;
916880 stderr . write ( `Error: ${ userMessage } \n` ) ;
917881 await persist ( "failed" , { error : diagnosticMessage } ) ;
918882 return {
0 commit comments