@@ -8,6 +8,7 @@ import type {
88 ReactorAction ,
99 ToolDefinition ,
1010 ConversationTurn ,
11+ RetryPolicy ,
1112} from "@intx/types/runtime" ;
1213import { type SessionMetadata , type TaskBoundary } from "../session/compactor.js" ;
1314import type { WorkflowCoordinator } from "../workflows/coordinator.js" ;
@@ -33,8 +34,6 @@ import { isOperatorOriginated } from "./message-provenance.js";
3334import { classifyBriefSalvage , isHardBlockSalvage } from "../subagent/brief-dispatch.js" ;
3435import { PRIMARY_SALVAGE_NUDGE } from "./look-tour.js" ;
3536
36- const RETRY_POLICY = createCorbitsRetryPolicy ( ) ;
37-
3837// Fired when turnsSinceUserMessage reaches TURNS_SINCE_USER_MESSAGE_BACKSTOP.
3938// A nudge, not a pause — the operator explicitly wants long autonomous runs
4039// to keep going, so silence alone (with no detected cycle) is not
@@ -356,12 +355,22 @@ export interface ChatDirectorOptions {
356355 onTasksChange : ( tasks : Task [ ] ) => void ;
357356 requestContinuation ?: ( ( ) => void ) | undefined ;
358357 provider ?: { providerName : string ; model ?: string } | undefined ;
358+ /**
359+ * Live catalog provider id for retry stamping. Resolved on each retry
360+ * decision so mid-session `/model` switches remapping without rebuilding
361+ * the agent. When set, preferred over static `provider.providerName`.
362+ */
363+ getProviderId ?: ( ( ) => string | undefined ) | undefined ;
364+ /** Explicit retry policy; when set, skips the default Corbits policy. */
365+ retryPolicy ?: RetryPolicy | undefined ;
359366}
360367
361368// The constructor takes the resolved ModelFamilyPolicy rather than the raw
362369// `provider` input the factory function accepts and resolves on its behalf.
363370type ChatDirectorImplOptions = Omit < ChatDirectorOptions , "provider" > & {
364371 modelFamilyPolicy ?: ModelFamilyPolicy | undefined ;
372+ /** Provider-stamped retry policy (xAI short 429 remapping needs providerId). */
373+ retryPolicy ?: RetryPolicy | undefined ;
365374} ;
366375
367376class ChatDirectorImpl extends DefaultDirector {
@@ -390,6 +399,7 @@ class ChatDirectorImpl extends DefaultDirector {
390399 private startedAt = Date . now ( ) ;
391400 private readonly compaction : CompactionGovernor ;
392401 private readonly modelFamilyPolicy : ModelFamilyPolicy ;
402+ private readonly retryPolicy : RetryPolicy ;
393403 // Consecutive assistant turns that contain tool calls and no text. Reset on
394404 // any turn with text and on every fresh user message — a weak model that
395405 // spins in place on one thread of tool calls still converges to the
@@ -476,6 +486,7 @@ class ChatDirectorImpl extends DefaultDirector {
476486 ) ;
477487 this . modelFamilyPolicy =
478488 options . modelFamilyPolicy ?? resolveModelFamilyPolicy ( { providerName : "" } ) ;
489+ this . retryPolicy = options . retryPolicy ?? createCorbitsRetryPolicy ( ) ;
479490 }
480491
481492 setWorkflowCoordinator ( coordinator : WorkflowCoordinator | undefined ) : void {
@@ -618,7 +629,7 @@ class ChatDirectorImpl extends DefaultDirector {
618629 const options = {
619630 ...action . options ,
620631 tools,
621- retryPolicy : action . options ?. retryPolicy ?? RETRY_POLICY ,
632+ retryPolicy : action . options ?. retryPolicy ?? this . retryPolicy ,
622633 } ;
623634 if ( this . inactivityTimeoutMs !== undefined )
624635 options . inactivityTimeoutMs = this . inactivityTimeoutMs ;
@@ -1064,12 +1075,24 @@ export function createChatDirector(
10641075 toolDefinitions : ToolDefinition [ ] ,
10651076 options : ChatDirectorOptions ,
10661077) : ChatDirector {
1067- const { provider, ...rest } = options ;
1078+ const { provider, getProviderId , retryPolicy , ...rest } = options ;
10681079 return new ChatDirectorImpl ( systemPrompt , toolDefinitions , {
10691080 ...rest ,
10701081 // `provider` is raw {providerName, model} input; the constructor wants
10711082 // the resolved ModelFamilyPolicy, not the input it was resolved from.
10721083 modelFamilyPolicy : provider !== undefined ? resolveModelFamilyPolicy ( provider ) : undefined ,
1084+ // Stamp provider id onto retry errors so known-xAI short 429s remap.
1085+ // Prefer an explicit policy, then a live getter (mid-session `/model`),
1086+ // then the bootstrap providerName.
1087+ retryPolicy :
1088+ retryPolicy ??
1089+ createCorbitsRetryPolicy (
1090+ getProviderId !== undefined
1091+ ? { providerId : getProviderId }
1092+ : provider !== undefined
1093+ ? { providerId : provider . providerName }
1094+ : undefined ,
1095+ ) ,
10731096 } ) ;
10741097}
10751098
0 commit comments