@@ -35,6 +35,7 @@ import {
3535} from "./threadDraftViewHelpers" ;
3636import { friendlyError } from "@/shared/messages" ;
3737import { PresentationModeTabs } from "./PresentationModeTabs" ;
38+ import { ProjectSwitchMenu } from "./ProjectSwitchMenu" ;
3839import { ThreadDraftComposerArea , type DraftStartInput } from "./ThreadDraftComposerArea" ;
3940import type { ComposerControl } from "./ThreadComposer" ;
4041import { AgentDiscoveryScreen } from "./AgentDiscoveryScreen" ;
@@ -803,6 +804,42 @@ export function ThreadDraftView(props: {
803804 props . paneAlign === "right" ? "ml-auto" : props . paneAlign === "left" ? "mr-auto" : "mx-auto" ;
804805 const paddingClass = "px-2" ;
805806
807+ const handlePresentationChange = ( next : ThreadPresentationMode ) => {
808+ // If the active provider can't serve this surface, swap to another
809+ // installed provider that can — the provider-switch effect will then
810+ // reload the per-provider config snapshot.
811+ if ( ! supportedPresentationModes . includes ( next ) ) {
812+ const fallback = installedAgents . find ( ( agent ) => {
813+ const modes = agent . capabilities . presentationModes ?? [ agent . capabilities . presentationMode ] ;
814+ return modes . includes ( next ) ;
815+ } ) ;
816+ if ( ! fallback ) return ;
817+ setPresentationMode ( next ) ;
818+ setAgentKind ( fallback . kind ) ;
819+ return ;
820+ }
821+ setPresentationMode ( next ) ;
822+ // Drop config values that the new presentation surface doesn't
823+ // support (e.g. Codex plan mode is ACP-only).
824+ const normalizer = effectiveAgentKind ? getConfigNormalizer ( effectiveAgentKind ) : undefined ;
825+ if ( ! normalizer ) return ;
826+ const patch = normalizer ( {
827+ capabilities : capabilitiesForPresentation ( selectedAgent . capabilities , next ) ,
828+ config : {
829+ model,
830+ effort,
831+ ...( contextSize ? { contextSize } : { } ) ,
832+ ...( fast ? { fast } : { } ) ,
833+ ...( thinking ? { thinking } : { } ) ,
834+ mode,
835+ approvalPolicy,
836+ sandboxMode,
837+ } ,
838+ presentationMode : next ,
839+ } ) ;
840+ if ( Object . keys ( patch ) . length > 0 ) onConfigPatch ( patch ) ;
841+ } ;
842+
806843 return (
807844 < div
808845 ref = { props . droppableRef }
@@ -821,64 +858,26 @@ export function ThreadDraftView(props: {
821858 />
822859 ) }
823860 < div
824- className = { `${ props . compact ? alignClass : "mx-auto" } relative flex h-full min-h-0 w-full max-w-[1040px] flex-col ${ paddingClass } px-3 pb-2 ${ props . compact ? "" : "pt-2" } ` }
861+ className = { `${ props . compact ? alignClass : "mx-auto justify-center " } relative flex h-full min-h-0 w-full max-w-[1040px] flex-col ${ paddingClass } px-3 pb-2 ${ props . compact ? "" : "pt-2" } ` }
825862 >
826863 < ThreadDraftDropIndicators dropIndicator = { props . dropIndicator } />
827- < ThreadDraftHero
828- compact = { props . compact }
829- projectId = { project . id }
830- { ...( scopeLabel ? { scopeLabel } : { } ) }
831- { ...( props . paneId ? { paneId : props . paneId } : { } ) }
832- />
833-
834- < PresentationModeTabs
835- presentationMode = { presentationMode }
836- supportsTerminal = { supportsTerminalMode }
837- supportsGui = { supportsGuiMode }
838- className = { `${ props . compact ? alignClass : "mx-auto" } mb-1 w-full max-w-[920px]` }
839- onChange = { ( next ) => {
840- // If the active provider can't serve this surface, swap to
841- // another installed provider that can — the provider-switch
842- // effect will then reload the per-provider config snapshot.
843- if ( ! supportedPresentationModes . includes ( next ) ) {
844- const fallback = installedAgents . find ( ( agent ) => {
845- const modes = agent . capabilities . presentationModes ?? [
846- agent . capabilities . presentationMode ,
847- ] ;
848- return modes . includes ( next ) ;
849- } ) ;
850- if ( ! fallback ) return ;
851- setPresentationMode ( next ) ;
852- setAgentKind ( fallback . kind ) ;
853- return ;
854- }
855- setPresentationMode ( next ) ;
856- // Drop config values that the new presentation surface
857- // doesn't support (e.g. Codex plan mode is ACP-only).
858- const normalizer = effectiveAgentKind
859- ? getConfigNormalizer ( effectiveAgentKind )
860- : undefined ;
861- if ( ! normalizer ) return ;
862- const patch = normalizer ( {
863- capabilities : capabilitiesForPresentation ( selectedAgent . capabilities , next ) ,
864- config : {
865- model,
866- effort,
867- ...( contextSize ? { contextSize } : { } ) ,
868- ...( fast ? { fast } : { } ) ,
869- ...( thinking ? { thinking } : { } ) ,
870- mode,
871- approvalPolicy,
872- sandboxMode,
873- } ,
874- presentationMode : next ,
875- } ) ;
876- if ( Object . keys ( patch ) . length > 0 ) onConfigPatch ( patch ) ;
877- } }
878- />
864+ { props . compact ? < ThreadDraftHero compact = { props . compact } /> : null }
879865
880866 { /* Composer at bottom */ }
881- < div className = { `${ props . compact ? alignClass : "mx-auto" } w-full max-w-[920px]` } >
867+ < div className = { `${ props . compact ? alignClass : "mx-auto" } w-full max-w-[720px]` } >
868+ < div className = "mb-1 flex items-center justify-between gap-2" >
869+ < ProjectSwitchMenu
870+ currentProjectId = { project . id }
871+ variant = "compact"
872+ { ...( props . paneId ? { paneId : props . paneId } : { } ) }
873+ />
874+ < PresentationModeTabs
875+ presentationMode = { presentationMode }
876+ supportsTerminal = { supportsTerminalMode }
877+ supportsGui = { supportsGuiMode }
878+ onChange = { handlePresentationChange }
879+ />
880+ </ div >
882881 < ThreadDraftComposerArea
883882 project = { project }
884883 { ...( props . paneId ? { paneId : props . paneId } : { } ) }
0 commit comments