@@ -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 ,
@@ -67,7 +62,10 @@ import { createAgentToolset, type AgentToolset, type OperatorResult } from "../a
6762import { createAgentWithLiveToolDispatch } from "../agent/live-tool-dispatch.js" ;
6863import { liveTelemetry } from "../telemetry/singleton.js" ;
6964import { createTurnObserver } from "../telemetry/ai-observability.js" ;
70- import { terminalProviderFailureMessage } from "../inference-error-message.js" ;
65+ import {
66+ isResolvedProviderFailureError ,
67+ terminalProviderFailureMessage ,
68+ } from "../inference-error-message.js" ;
7169import { collectToolPlugins , resolveToolPlugins } from "../plugins/tool-plugins.js" ;
7270import {
7371 expandExistingPluginMembers ,
@@ -136,9 +134,13 @@ export async function refreshSelectedProviderCredential<T>(refresh: () => Promis
136134export function execUserFailureMessage (
137135 config : Config ,
138136 err : unknown ,
139- inferenceStarted : boolean ,
137+ providerFailureObserved : boolean ,
140138) : string {
141- if ( inferenceStarted || ( err instanceof Error && err . name === SELECTED_PROVIDER_FAILURE ) ) {
139+ if (
140+ providerFailureObserved ||
141+ isResolvedProviderFailureError ( err ) ||
142+ ( err instanceof Error && err . name === SELECTED_PROVIDER_FAILURE )
143+ ) {
142144 return terminalProviderFailureMessage (
143145 config . providerName ,
144146 config . settings ?. providers [ config . providerName ] ?. name ,
@@ -324,7 +326,7 @@ export async function runExec(config: Config): Promise<ExecResult> {
324326 let finalized = false ;
325327 let turnsUsed = 0 ;
326328 let runSink : RunSink | null = null ;
327- let inferenceStarted = false ;
329+ let providerFailureObserved = false ;
328330
329331 const persist = async (
330332 status : "running" | "done" | "failed" | "cancelled" ,
@@ -614,56 +616,14 @@ export async function runExec(config: Config): Promise<ExecResult> {
614616
615617 const initialCodexProfile = codexProfileFromProviderName ( config . providerName ) ;
616618 const initialXaiProfile = xaiProfileFromProviderName ( config . providerName ) ;
617- const initialCodexAccountId = config . providers . find (
618- ( p ) => p . name === config . providerName ,
619- ) ?. codexAccountId ;
620-
621- const buildOpenAICompatibleInitialSource = ( ) : InferenceSource =>
622- buildOpenAISource ( {
623- id : config . providerName ,
624- baseURL : config . baseURL ,
625- apiKey : config . apiKey ,
626- model : config . model ,
627- ...( config . reasoningEffort !== undefined
628- ? { reasoningEffort : config . reasoningEffort }
629- : { } ) ,
630- } ) ;
631-
632- const buildSessionSources = ( ) : { sources : InferenceSource [ ] ; defaultSource : string } =>
633- buildSessionSourcesFromConfig ( config , sessionId ) ;
634-
635- const initialBundle = buildSessionSources ( ) ;
619+ const initialBundle = buildSessionSourcesFromConfig ( config , sessionId ) ;
636620 const liveSources = initialBundle . sources ;
637621 const liveDefaultSource = initialBundle . defaultSource ;
638-
639- const buildInitialSourceFallback = ( ) : InferenceSource =>
640- initialCodexProfile !== undefined
641- ? buildCodexSource ( {
642- id : config . providerName ,
643- apiKey : config . apiKey ,
644- model : config . model ,
645- sessionId,
646- ...( initialCodexAccountId !== undefined ? { accountId : initialCodexAccountId } : { } ) ,
647- ...( config . reasoningEffort !== undefined
648- ? { reasoningEffort : config . reasoningEffort }
649- : { } ) ,
650- } )
651- : initialXaiProfile !== undefined
652- ? buildXaiSource ( {
653- id : config . providerName ,
654- apiKey : config . apiKey ,
655- model : config . model ,
656- sessionId,
657- ...( config . reasoningEffort !== undefined
658- ? { reasoningEffort : config . reasoningEffort }
659- : { } ) ,
660- } )
661- : buildOpenAICompatibleInitialSource ( ) ;
662-
663- let liveSource : InferenceSource =
664- liveSources . find ( ( s ) => s . id === liveDefaultSource ) ??
665- liveSources [ 0 ] ??
666- buildInitialSourceFallback ( ) ;
622+ const selectedSource = liveSources [ 0 ] ;
623+ if ( selectedSource === undefined ) {
624+ throw new Error ( "Selected inference source was not assembled" ) ;
625+ }
626+ let liveSource : InferenceSource = selectedSource ;
667627
668628 // Refresh pinned Codex instructions before first inference, same as the
669629 // TUI path. Best-effort: a network failure falls back to the disk cache
@@ -794,6 +754,11 @@ export async function runExec(config: Config): Promise<ExecResult> {
794754 // its partial output in partial.jsonl instead of vanishing.
795755 const cycleRecorder = createCycleTextRecorder ( ( ) => workdir ) ;
796756 const sink = ( event : ReactorEmittedEvent ) : void => {
757+ if ( event . type === "inference.start" || event . type === "inference.done" ) {
758+ providerFailureObserved = false ;
759+ } else if ( event . type === "inference.error" ) {
760+ providerFailureObserved = true ;
761+ }
797762 liveSink . sink ( event ) ;
798763 cycleRecorder . handleEvent ( event ) ;
799764 if ( event . type === "inference.text.delta" ) {
@@ -817,7 +782,6 @@ export async function runExec(config: Config): Promise<ExecResult> {
817782 let runError : string | undefined ;
818783 let sinkStatus : ReturnType < typeof liveSink . getStatus > = "cancelled" ;
819784 try {
820- inferenceStarted = true ;
821785 // Final OAuth refresh immediately before send (token may have aged during MCP).
822786 if ( initialCodexProfile !== undefined ) {
823787 const { access } = await getValidCodexToken ( initialCodexProfile ) ;
@@ -958,7 +922,7 @@ export async function runExec(config: Config): Promise<ExecResult> {
958922 } catch ( err ) {
959923 const diagnosticMessage = formatCaughtError ( err ) ;
960924 logger . error ( "exec failed: {error}" , { error : diagnosticMessage } ) ;
961- const userMessage = execUserFailureMessage ( config , err , inferenceStarted ) ;
925+ const userMessage = execUserFailureMessage ( config , err , providerFailureObserved ) ;
962926 stderr . write ( `Error: ${ userMessage } \n` ) ;
963927 await persist ( "failed" , { error : diagnosticMessage } ) ;
964928 return {
0 commit comments