@@ -6,20 +6,15 @@ import {
66} from "@xyflow/react" ;
77
88import { FlowCanvas } from "@/components/FlowCanvas" ;
9- import { DimEnvEditor } from "@/components/DimEnvEditor" ;
109import { layoutFlow } from "@/lib/elk" ;
1110import { GalleryTab } from "@/components/GalleryTab" ;
1211import { GalleryScaleDownSlider } from "@/components/GalleryScaleDownSlider" ;
1312import { FeatureInjectionBar ,
1413 type AppliedInjection } from "@/components/FeatureInjectionBar" ;
1514import { SweepPanel } from "@/components/SweepPanel" ;
1615import { TokenizerMatrixTab } from "@/components/TokenizerMatrixTab" ;
17- import { TransplantBar } from "@/components/TransplantBar" ;
18- import { InsertIntoEdgeBar } from "@/components/InsertIntoEdgeBar" ;
19- import { ParallelComposeBar } from "@/components/ParallelComposeBar" ;
20- import { TrainOptionsPanel , type TrainOptions } from "@/components/TrainOptionsPanel" ;
16+ import { type TrainOptions } from "@/components/TrainOptionsPanel" ;
2117import { GenerationPanel } from "@/components/GenerationPanel" ;
22- import { RunHistoryPicker } from "@/components/RunHistoryPicker" ;
2318import { TrainLiveControls } from "@/components/TrainLiveControls" ;
2419import { useGalleryCache } from "@/hooks/useGalleryCache" ;
2520import { Palette } from "@/components/Palette" ;
@@ -326,6 +321,22 @@ export function App(): JSX.Element {
326321
327322 const [ wizardPreset , setWizardPreset ] = useState < string | null > ( null ) ;
328323
324+ // Tab state lifting for right Sidebar
325+ const [ activeSidebarTab , setActiveSidebarTab ] = useState < import ( "@/components/Sidebar" ) . SidebarTab > ( "loss" ) ;
326+ // Floating live train controls slide-up visibility state
327+ const [ showLivePanel , setShowLivePanel ] = useState ( false ) ;
328+
329+ useEffect ( ( ) => {
330+ if ( trainInFlight ) {
331+ setShowLivePanel ( true ) ;
332+ } else {
333+ const t = setTimeout ( ( ) => {
334+ setShowLivePanel ( false ) ;
335+ } , 3000 ) ;
336+ return ( ) => clearTimeout ( t ) ;
337+ }
338+ } , [ trainInFlight ] ) ;
339+
329340 // Dynamic platform detection and filtering.
330341 const [ platformInfo , setPlatformInfo ] = useState < {
331342 active_device : string ;
@@ -1640,117 +1651,14 @@ export function App(): JSX.Element {
16401651 applied = { featureInjections }
16411652 onApply = { handleFeatureInjectionApply }
16421653 onRemove = { handleFeatureInjectionRemove }
1643- />
1644- < DimEnvEditor value = { dimEnv } onApply = { setDimEnv } />
1645- < TrainOptionsPanel
1646- value = { trainOptions }
1647- onChange = { setTrainOptions }
1648- />
1649- < RunHistoryPicker
1650- history = { trainRunHistory }
1651- selected = { selectedWarmStartRunId }
1652- onSelect = { setSelectedWarmStartRunId }
1653- />
1654- < TrainLiveControls
1655- rpc = { rpc }
1656- trainInFlight = { trainInFlight }
1657- activeRunId = { trainRunId }
1658- onScheduleCheckpoint = { ( path ) =>
1659- setPendingCheckpointTrigger ( path ) }
1660- activeLayoutState = { {
1661- projectName,
1662- nodes,
1663- edges,
1664- spec,
1665- dimEnv,
1666- trainOptions,
1667- } }
1668- onLoadLayout = { ( layout : any ) => {
1669- if ( layout . projectName ) setProjectName ( layout . projectName ) ;
1670- if ( layout . nodes ) setNodes ( layout . nodes ) ;
1671- if ( layout . edges ) setEdges ( layout . edges ) ;
1672- if ( layout . spec ) dispatch ( { type : "spec.replace" , spec : layout . spec } ) ;
1673- if ( layout . dimEnv ) setDimEnv ( layout . dimEnv ) ;
1674- if ( layout . trainOptions ) setTrainOptions ( layout . trainOptions ) ;
1675- } }
1676- />
1677- < ParallelComposeBar
1678- onCompose = { ( composeNodes , composeEdges ) => {
1679- setNodes ( composeNodes . map ( ( cn ) => ( {
1680- id : cn . id ,
1681- type : "brick" ,
1682- position : cn . position ,
1683- data : { kind : cn . kind ,
1684- params : cn . params ?? { } } as never ,
1685- } ) ) ) ;
1686- setEdges ( composeEdges . map ( ( ce ) => ( {
1687- id : `${ ce . source } ->${ ce . target } ` ,
1688- source : ce . source ,
1689- target : ce . target ,
1690- data : { severity : "info" } ,
1691- } ) ) ) ;
1692- // Rebind head_outputs to the join's downstream
1693- // norm so verify_build_spec finds the loss head.
1694- const last = composeNodes [ composeNodes . length - 1 ] ;
1695- if ( last ) {
1696- dispatch ( { type : "loss.set" , loss : {
1697- ...spec . loss ,
1698- head_outputs : [ last . id ] ,
1699- } } ) ;
1654+ onChipClick = { ( name ) => {
1655+ if ( name . toLowerCase ( ) . includes ( "mtp" ) || name . toLowerCase ( ) . includes ( "rewriter" ) ) {
1656+ setActiveSidebarTab ( "rewriters" ) ;
1657+ } else {
1658+ setActiveSidebarTab ( "trainops" ) ;
17001659 }
17011660 } }
17021661 />
1703- < InsertIntoEdgeBar
1704- edges = { edges . map ( ( e ) => ( {
1705- source : e . source , target : e . target ,
1706- } ) ) }
1707- onInsert = { ( kind , edge ) => {
1708- const baseName =
1709- `${ kind } _insert_${ nodes . length } ` ;
1710- // Layout: midpoint between src & dst nodes.
1711- const src = nodes . find ( ( n ) => n . id === edge . source ) ;
1712- const dst = nodes . find ( ( n ) => n . id === edge . target ) ;
1713- const mid = src && dst
1714- ? { x : ( src . position . x + dst . position . x ) / 2 ,
1715- y : ( src . position . y + dst . position . y ) / 2 + 50 }
1716- : { x : 200 , y : 280 } ;
1717- setNodes ( ( prev ) => [
1718- ...prev ,
1719- { id : baseName ,
1720- type : "brick" ,
1721- position : mid ,
1722- data : { kind } as never } ,
1723- ] ) ;
1724- setEdges ( ( prev ) => [
1725- ...prev . filter ( ( e ) =>
1726- ! ( e . source === edge . source
1727- && e . target === edge . target ) ) ,
1728- { id : `${ edge . source } ->${ baseName } ` ,
1729- source : edge . source , target : baseName ,
1730- data : { severity : "info" } } ,
1731- { id : `${ baseName } ->${ edge . target } ` ,
1732- source : baseName , target : edge . target ,
1733- data : { severity : "info" } } ,
1734- ] ) ;
1735- } }
1736- />
1737- < TransplantBar
1738- rpc = { rpc }
1739- presets = { PRESETS }
1740- onTransplant = { ( kind , params ) => {
1741- const baseName = `${ kind } _xplant_${ nodes . length } ` ;
1742- setNodes ( ( prev ) => [
1743- ...prev ,
1744- {
1745- id : baseName ,
1746- type : "brick" ,
1747- position : { x : 60 + ( prev . length * 40 ) % 600 ,
1748- y : 280 } ,
1749- data : { kind, params } as never ,
1750- } ,
1751- ] ) ;
1752- } }
1753- />
17541662 { spec . gotchas . some (
17551663 ( g ) => g . id === "v7_f56b_dim_env_mismatch" ) && (
17561664 < div
@@ -1931,6 +1839,50 @@ export function App(): JSX.Element {
19311839 ] ) ;
19321840 } }
19331841 />
1842+ { showLivePanel && (
1843+ < div
1844+ data-testid = "live-train-controls-floating"
1845+ style = { {
1846+ position : "absolute" ,
1847+ bottom : 24 ,
1848+ left : "50%" ,
1849+ transform : "translateX(-50%)" ,
1850+ zIndex : 100 ,
1851+ background : "rgba(15, 23, 42, 0.92)" ,
1852+ backdropFilter : "blur(16px)" ,
1853+ border : "1px solid rgba(255, 255, 255, 0.15)" ,
1854+ borderRadius : 8 ,
1855+ boxShadow : "0 10px 30px rgba(0, 0, 0, 0.6)" ,
1856+ padding : "8px 16px" ,
1857+ width : "fit-content" ,
1858+ transition : "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)" ,
1859+ } }
1860+ >
1861+ < TrainLiveControls
1862+ rpc = { rpc }
1863+ trainInFlight = { trainInFlight }
1864+ activeRunId = { trainRunId }
1865+ onScheduleCheckpoint = { ( path ) =>
1866+ setPendingCheckpointTrigger ( path ) }
1867+ activeLayoutState = { {
1868+ projectName,
1869+ nodes,
1870+ edges,
1871+ spec,
1872+ dimEnv,
1873+ trainOptions,
1874+ } }
1875+ onLoadLayout = { ( layout : any ) => {
1876+ if ( layout . projectName ) setProjectName ( layout . projectName ) ;
1877+ if ( layout . nodes ) setNodes ( layout . nodes ) ;
1878+ if ( layout . edges ) setEdges ( layout . edges ) ;
1879+ if ( layout . spec ) dispatch ( { type : "spec.replace" , spec : layout . spec } ) ;
1880+ if ( layout . dimEnv ) setDimEnv ( layout . dimEnv ) ;
1881+ if ( layout . trainOptions ) setTrainOptions ( layout . trainOptions ) ;
1882+ } }
1883+ />
1884+ </ div >
1885+ ) }
19341886 </ div >
19351887 { selectedBrickId && ( ( ) => {
19361888 const selected = nodes . find ( ( n ) => n . id === selectedBrickId ) ;
@@ -2145,6 +2097,88 @@ export function App(): JSX.Element {
21452097 max_steps : 4 ,
21462098 } ) ;
21472099 } }
2100+ // Lifted active tab state
2101+ activeTab = { activeSidebarTab }
2102+ onTabChange = { setActiveSidebarTab }
2103+ // dim_env
2104+ dimEnv = { dimEnv }
2105+ onDimEnvApply = { setDimEnv }
2106+ // Train options
2107+ trainOptions = { trainOptions }
2108+ onTrainOptionsChange = { setTrainOptions }
2109+ trainRunHistory = { trainRunHistory }
2110+ selectedWarmStartRunId = { selectedWarmStartRunId }
2111+ onWarmStartSelect = { setSelectedWarmStartRunId }
2112+ // Canvas splicing callbacks
2113+ onParallelCompose = { ( composeNodes , composeEdges ) => {
2114+ setNodes ( composeNodes . map ( ( cn ) => ( {
2115+ id : cn . id ,
2116+ type : "brick" ,
2117+ position : cn . position ,
2118+ data : {
2119+ kind : cn . kind ,
2120+ params : cn . params ?? { } ,
2121+ } as never ,
2122+ } ) ) ) ;
2123+ setEdges ( composeEdges . map ( ( ce ) => ( {
2124+ id : `${ ce . source } ->${ ce . target } ` ,
2125+ source : ce . source ,
2126+ target : ce . target ,
2127+ data : { severity : "info" } as never ,
2128+ } ) ) ) ;
2129+ const last = composeNodes [ composeNodes . length - 1 ] ;
2130+ if ( last ) {
2131+ dispatch ( { type : "loss.set" , loss : {
2132+ ...spec . loss ,
2133+ head_outputs : [ last . id ] ,
2134+ } } ) ;
2135+ }
2136+ } }
2137+ onInsertIntoEdge = { ( kind , selectedEdge ) => {
2138+ const baseName = `${ kind } _splice_${ nodes . length } ` ;
2139+ // Midpoint layout:
2140+ const srcNode = nodes . find ( ( n ) => n . id === selectedEdge . source ) ;
2141+ const dstNode = nodes . find ( ( n ) => n . id === selectedEdge . target ) ;
2142+ const mid = srcNode && dstNode
2143+ ? { x : ( srcNode . position . x + dstNode . position . x ) / 2 ,
2144+ y : ( srcNode . position . y + dstNode . position . y ) / 2 + 50 }
2145+ : { x : 500 , y : 250 } ;
2146+ setNodes ( ( prev ) => [
2147+ ...prev ,
2148+ {
2149+ id : baseName ,
2150+ type : "brick" ,
2151+ position : mid ,
2152+ data : { kind } as never ,
2153+ } ,
2154+ ] ) ;
2155+ setEdges ( ( prev ) => [
2156+ ...prev . filter ( ( e ) => e . id !== `${ selectedEdge . source } ->${ selectedEdge . target } ` ) ,
2157+ {
2158+ id : `${ selectedEdge . source } ->${ baseName } ` ,
2159+ source : selectedEdge . source , target : baseName ,
2160+ data : { severity : "info" } as never ,
2161+ } ,
2162+ {
2163+ id : `${ baseName } ->${ selectedEdge . target } ` ,
2164+ source : baseName , target : selectedEdge . target ,
2165+ data : { severity : "info" } as never ,
2166+ } ,
2167+ ] ) ;
2168+ } }
2169+ onTransplant = { ( kind , params ) => {
2170+ const baseName = `${ kind } _xplant_${ nodes . length } ` ;
2171+ setNodes ( ( prev ) => [
2172+ ...prev ,
2173+ {
2174+ id : baseName ,
2175+ type : "brick" ,
2176+ position : { x : 60 + ( prev . length * 40 ) % 600 ,
2177+ y : 280 } ,
2178+ data : { kind, params } as never ,
2179+ } ,
2180+ ] ) ;
2181+ } }
21482182 />
21492183 </ >
21502184 ) }
0 commit comments