@@ -4,10 +4,10 @@ import {CodexEventHandler} from "./CodexEventHandler";
44import { CodexApprovalHandler } from "./CodexApprovalHandler" ;
55import { CodexElicitationHandler } from "./CodexElicitationHandler" ;
66import { type CodexAuthRequest , getCodexAuthMethods } from "./CodexAuthMethod" ;
7- import { CodexAcpClient , type SessionMetadata , type SessionMetadataWithThread } from "./CodexAcpClient" ;
7+ import { CodexAcpClient , type ModelSelection , type SessionMetadata , type SessionMetadataWithThread } from "./CodexAcpClient" ;
88import type { McpStartupResult } from "./CodexAppServerClient" ;
99import { ACPSessionConnection , type UpdateSessionEvent } from "./ACPSessionConnection" ;
10- import type { InputModality , ReasoningEffort } from "./app-server" ;
10+ import type { InputModality , ReasoningEffort , ServiceTier } from "./app-server" ;
1111import type {
1212 Account ,
1313 CollabAgentToolCallStatus ,
@@ -18,7 +18,6 @@ import type {
1818 UserInput
1919} from "./app-server/v2" ;
2020import type { RateLimitsMap } from "./RateLimitsMap" ;
21- import { ModelId } from "./ModelId" ;
2221import { AgentMode } from "./AgentMode" ;
2322import type { TokenCount } from "./TokenCount" ;
2423import { toPromptUsage } from "./TokenCount" ;
@@ -36,6 +35,8 @@ import {
3635export interface SessionState {
3736 sessionId : string ,
3837 currentModelId : string ,
38+ currentReasoningEffort : ReasoningEffort ,
39+ currentServiceTier : ServiceTier | null ,
3940 supportedReasoningEfforts : Array < ReasoningEffortOption > ,
4041 supportedInputModalities : Array < InputModality > ,
4142 agentMode : AgentMode ,
@@ -160,12 +161,14 @@ export class CodexAcpServer implements acp.Agent {
160161 }
161162
162163 const account = await this . getActiveAccount ( ) ;
163- const { sessionId, currentModelId, models} = sessionMetadata ;
164+ const { sessionId, currentModelId, currentReasoningEffort , currentServiceTier , models} = sessionMetadata ;
164165 const sessionMcpServers = this . resolveSessionMcpServers ( requestedMcpServers , "sessionId" in request ) ;
165166 const currentModel = this . findCurrentModel ( models , currentModelId ) ;
166167 const sessionState : SessionState = {
167168 sessionId : sessionId ,
168169 currentModelId : currentModelId ,
170+ currentReasoningEffort : currentReasoningEffort ,
171+ currentServiceTier : currentServiceTier ,
169172 supportedReasoningEfforts : currentModel ?. supportedReasoningEfforts ?? [ ] ,
170173 supportedInputModalities : currentModel ?. inputModalities ?? [ "text" , "image" ] ,
171174 agentMode : AgentMode . getInitialAgentMode ( ) ,
@@ -189,7 +192,7 @@ export class CodexAcpServer implements acp.Agent {
189192 }
190193
191194 this . publishAvailableCommandsAsync ( sessionId ) ;
192- const sessionModelState : SessionModelState = this . createModelState ( models , currentModelId ) ;
195+ const sessionModelState : SessionModelState = this . createModelState ( models , sessionState ) ;
193196 const sessionModeState : SessionModeState = sessionState . agentMode . toSessionModeState ( ) ;
194197
195198 return [ sessionId , sessionModelState , sessionModeState ] ;
@@ -310,34 +313,32 @@ export class CodexAcpServer implements acp.Agent {
310313 const sessionState = this . sessions . get ( params . sessionId ) ;
311314 if ( ! sessionState ) throw new Error ( `Session ${ params . sessionId } not found` ) ;
312315
313- const requestedModelId = ModelId . fromString ( params . modelId ) ;
314- const requestedModelName = requestedModelId . model ;
315- const requestedEffort = requestedModelId . effort ;
316-
317316 const models = await this . codexAcpClient . fetchAvailableModels ( ) ;
318- const model = models . find ( m => m . id === requestedModelName ) ;
317+ const model = models . find ( m => m . id === params . modelId ) ;
319318 if ( ! model ) throw new Error ( `Unknown model ${ params . modelId } ` ) ;
320- if ( requestedModelId . serviceTier === "fast" && ! model . additionalSpeedTiers . includes ( "fast" ) ) {
321- throw new Error ( `Unsupported service tier fast for model ${ requestedModelName } ` ) ;
322- }
323319
324- const requestedEffortValue = requestedEffort as ReasoningEffort | undefined ;
325- let reasoningEffort : ReasoningEffort ;
326- if ( requestedEffortValue ) {
320+ const requestedEffort = readStringMeta ( params . _meta , "reasoningEffort" ) as ReasoningEffort | null ;
321+ let reasoningEffort = model . defaultReasoningEffort ;
322+ if ( requestedEffort !== null ) {
327323 const matchedEffort = model . supportedReasoningEfforts . find (
328- ( option ) => option . reasoningEffort === requestedEffortValue
324+ ( option ) => option . reasoningEffort === requestedEffort
329325 ) ?. reasoningEffort ;
330326
331327 if ( ! matchedEffort ) {
332- throw new Error ( `Unsupported reasoning effort ${ requestedEffortValue } for model ${ requestedModelName } ` ) ;
328+ throw new Error ( `Unsupported reasoning effort ${ requestedEffort } for model ${ model . id } ` ) ;
333329 }
334330
335331 reasoningEffort = matchedEffort ;
336- } else {
337- reasoningEffort = model . defaultReasoningEffort ;
338332 }
339333
340- sessionState . currentModelId = ModelId . fromComponents ( model , reasoningEffort , requestedModelId . serviceTier ) . toString ( ) ;
334+ const requestedServiceTier = readStringMeta ( params . _meta , "serviceTier" ) as ServiceTier | null ;
335+ if ( requestedServiceTier !== null && ! model . additionalSpeedTiers . includes ( requestedServiceTier ) ) {
336+ throw new Error ( `Unsupported service tier ${ requestedServiceTier } for model ${ model . id } ` ) ;
337+ }
338+
339+ sessionState . currentModelId = model . id ;
340+ sessionState . currentReasoningEffort = reasoningEffort ;
341+ sessionState . currentServiceTier = requestedServiceTier ;
341342 sessionState . supportedReasoningEfforts = model . supportedReasoningEfforts ;
342343 sessionState . supportedInputModalities = model . inputModalities ;
343344
@@ -349,35 +350,28 @@ export class CodexAcpServer implements acp.Agent {
349350 }
350351
351352 private findCurrentModel ( models : Model [ ] , currentModelId : string ) : Model | undefined {
352- const modelId = ModelId . fromString ( currentModelId ) ;
353- return models . find ( m => m . id === modelId . model ) ;
353+ return models . find ( m => m . id === currentModelId ) ;
354354 }
355355
356- private createModelState ( availableModels : Model [ ] , selectedModelId : string ) : SessionModelState {
356+ private createModelState ( availableModels : Model [ ] , selection : ModelSelection ) : SessionModelState {
357357 const allowedModels = availableModels
358- . flatMap ( ( model ) =>
359- model . supportedReasoningEfforts . flatMap ( ( effort ) => {
360- const standardModel = {
361- modelId : ModelId . fromComponents ( model , effort . reasoningEffort ) . toString ( ) ,
362- name : `${ model . displayName } (${ effort . reasoningEffort } )` ,
363- description : `${ model . description } ${ effort . description } ` ,
364- } ;
365- if ( ! model . additionalSpeedTiers . includes ( "fast" ) ) {
366- return [ standardModel ] ;
367- }
368- return [
369- standardModel ,
370- {
371- modelId : ModelId . fromComponents ( model , effort . reasoningEffort , "fast" ) . toString ( ) ,
372- name : `${ model . displayName } (${ effort . reasoningEffort } , fast)` ,
373- description : `${ model . description } ${ effort . description } Fast service tier.` ,
374- } ,
375- ] ;
376- } )
377- ) ;
358+ . map ( ( model ) => ( {
359+ modelId : model . id ,
360+ name : model . displayName ,
361+ description : model . description ,
362+ _meta : {
363+ supportedReasoningEfforts : model . supportedReasoningEfforts ,
364+ defaultReasoningEffort : model . defaultReasoningEffort ,
365+ serviceTiers : model . additionalSpeedTiers ,
366+ } ,
367+ } ) ) ;
378368 return {
379369 availableModels : allowedModels ,
380- currentModelId : selectedModelId ,
370+ currentModelId : selection . currentModelId ,
371+ _meta : {
372+ currentReasoningEffort : selection . currentReasoningEffort ,
373+ currentServiceTier : selection . currentServiceTier ,
374+ } ,
381375 }
382376 }
383377
@@ -401,12 +395,14 @@ export class CodexAcpServer implements acp.Agent {
401395 ) ;
402396
403397 const account = await this . getActiveAccount ( ) ;
404- const { sessionId, currentModelId, models, thread} = sessionMetadata ;
398+ const { sessionId, currentModelId, currentReasoningEffort , currentServiceTier , models, thread} = sessionMetadata ;
405399 const sessionMcpServers = this . resolveSessionMcpServers ( requestedMcpServers , true ) ;
406400 const currentModel = this . findCurrentModel ( models , currentModelId ) ;
407401 const sessionState : SessionState = {
408402 sessionId : sessionId ,
409403 currentModelId : currentModelId ,
404+ currentReasoningEffort : currentReasoningEffort ,
405+ currentServiceTier : currentServiceTier ,
410406 supportedReasoningEfforts : currentModel ?. supportedReasoningEfforts ?? [ ] ,
411407 supportedInputModalities : currentModel ?. inputModalities ?? [ "text" , "image" ] ,
412408 agentMode : AgentMode . getInitialAgentMode ( ) ,
@@ -430,7 +426,7 @@ export class CodexAcpServer implements acp.Agent {
430426 }
431427
432428 await this . availableCommands . publish ( sessionId ) ;
433- const sessionModelState : SessionModelState = this . createModelState ( models , currentModelId ) ;
429+ const sessionModelState : SessionModelState = this . createModelState ( models , sessionState ) ;
434430 const sessionModeState : SessionModeState = sessionState . agentMode . toSessionModeState ( ) ;
435431
436432 return {
@@ -767,7 +763,6 @@ export class CodexAcpServer implements acp.Agent {
767763 } ;
768764 }
769765
770- const modelId = ModelId . fromString ( sessionState . currentModelId ) ;
771766 const modelLacksReasoning = sessionState . supportedReasoningEfforts . length > 0
772767 && sessionState . supportedReasoningEfforts . every ( e => e . reasoningEffort === "none" ) ;
773768
@@ -784,7 +779,7 @@ export class CodexAcpServer implements acp.Agent {
784779 }
785780 const agentMode = sessionState . agentMode ;
786781 const turnCompleted = await this . runWithProcessCheck (
787- ( ) => this . codexAcpClient . sendPrompt ( params , agentMode , modelId , disableSummary , sessionState . cwd ) ) ;
782+ ( ) => this . codexAcpClient . sendPrompt ( params , agentMode , sessionState , disableSummary , sessionState . cwd ) ) ;
788783
789784 // Check if turn was interrupted (cancelled)
790785 if ( turnCompleted . turn . status === "interrupted" ) {
@@ -828,7 +823,7 @@ export class CodexAcpServer implements acp.Agent {
828823 private buildQuotaMeta ( sessionState : SessionState ) : { quota : QuotaMeta } {
829824 const lastTokenUsage = sessionState . lastTokenUsage ;
830825
831- const modelName = ModelId . fromString ( sessionState . currentModelId ) . model ;
826+ const modelName = sessionState . currentModelId ;
832827
833828 // FIXME: currently all tokens are reported for the current model
834829 const modelUsage = ( lastTokenUsage != null )
@@ -901,3 +896,14 @@ export class CodexAcpServer implements acp.Agent {
901896function getRequestedMcpServerNames ( mcpServers : Array < acp . McpServer > ) : Array < string > {
902897 return Array . from ( new Set ( mcpServers . map ( server => server . name ) ) ) ;
903898}
899+
900+ function readStringMeta ( meta : { [ key : string ] : unknown } | null | undefined , key : string ) : string | null {
901+ const value = meta ?. [ key ] ;
902+ if ( value === undefined || value === null ) {
903+ return null ;
904+ }
905+ if ( typeof value !== "string" ) {
906+ throw RequestError . invalidParams ( `Expected _meta.${ key } to be a string` ) ;
907+ }
908+ return value ;
909+ }
0 commit comments