@@ -5,6 +5,7 @@ import { CompleteAgent } from '@utils/agent_database';
55import { isJupyterConnected } from '@utils/handlers/JupyterConfig' ;
66import { listModels } from '@utils/ollamaServer' ;
77import { getOllamaServerAddress } from '@utils/main_loop' ;
8+ import { AGENT_ITERATION_START_EVENT , AGENT_WAITING_START_EVENT , AGENT_ITERATION_SKIPPED_EVENT } from '@utils/TimerEventManager' ;
89import { Logger , LogEntry } from '@utils/logging' ;
910import { StreamManager , StreamState } from '@utils/streamManager' ;
1011
@@ -64,6 +65,7 @@ const AgentCard: React.FC<AgentCardProps> = ({
6465 const [ lastResponse , setLastResponse ] = useState < string > ( '...' ) ;
6566 const [ responseKey , setResponseKey ] = useState ( 0 ) ;
6667 const [ loopProgress , setLoopProgress ] = useState ( 0 ) ;
68+ const [ lastProgressUpdate , setLastProgressUpdate ] = useState ( 0 ) ;
6769 const [ currentModel , setCurrentModel ] = useState ( agent . model_name ) ;
6870 const initialModelRef = useRef ( agent . model_name ) ;
6971
@@ -103,7 +105,12 @@ const AgentCard: React.FC<AgentCardProps> = ({
103105 return ;
104106 }
105107 if ( isRunning ) {
106- if ( liveStatus === 'STARTING' || liveStatus === 'IDLE' ) setLiveStatus ( 'CAPTURING' ) ;
108+ if ( liveStatus === 'STARTING' || liveStatus === 'IDLE' ) {
109+ setLiveStatus ( 'CAPTURING' ) ;
110+ // Reset progress when agent starts
111+ setLoopProgress ( 0 ) ;
112+ setLastProgressUpdate ( 0 ) ;
113+ }
107114 const handleNewLog = ( log : LogEntry ) => {
108115 if ( log . source !== agent . id ) return ;
109116 if ( log . details ?. logType === 'model-prompt' ) setLiveStatus ( 'THINKING' ) ;
@@ -121,22 +128,54 @@ const AgentCard: React.FC<AgentCardProps> = ({
121128 } , [ isRunning , showStartingState , agent . id , liveStatus , hasQuotaError ] ) ;
122129
123130 useEffect ( ( ) => {
124- let timer : NodeJS . Timeout | null = null ;
125- if ( isRunning && liveStatus === 'WAITING' && ! hasQuotaError ) {
126- timer = setInterval ( ( ) => {
127- setLoopProgress ( prev => {
128- const newProgress = prev + ( 100 / ( agent . loop_interval_seconds * 10 ) ) ;
129- if ( newProgress >= 100 ) {
130- clearInterval ( timer ! ) ;
131- setLiveStatus ( 'CAPTURING' ) ;
132- return 0 ;
133- }
134- return newProgress ;
135- } ) ;
136- } , 100 ) ;
131+ let progressTimer : NodeJS . Timeout | null = null ;
132+ let nextIterationTime = 0 ;
133+ let intervalMs = 0 ;
134+
135+ const handleWaitingStart = ( event : CustomEvent ) => {
136+ if ( event . detail . agentId !== agent . id ) return ;
137+ nextIterationTime = event . detail . nextIterationTime ;
138+ intervalMs = event . detail . intervalMs ;
139+
140+ // Start progress timer
141+ progressTimer = setInterval ( ( ) => {
142+ const now = Date . now ( ) ;
143+ const elapsed = now - ( nextIterationTime - intervalMs ) ;
144+ const progress = Math . min ( 100 , Math . max ( 0 , ( elapsed / intervalMs ) * 100 ) ) ;
145+ setLoopProgress ( progress ) ;
146+ setLastProgressUpdate ( now ) ;
147+ } , 50 ) ; // Update more frequently for smoothness
148+ } ;
149+
150+ const handleIterationStart = ( event : CustomEvent ) => {
151+ if ( event . detail . agentId !== agent . id ) return ;
152+ if ( progressTimer ) {
153+ clearInterval ( progressTimer ) ;
154+ progressTimer = null ;
155+ }
156+ setLoopProgress ( 0 ) ;
157+ } ;
158+
159+ const handleIterationSkipped = ( event : CustomEvent ) => {
160+ if ( event . detail . agentId !== agent . id ) return ;
161+ nextIterationTime = event . detail . nextIterationTime ;
162+ intervalMs = event . detail . intervalMs ;
163+ // Continue showing progress for next possible iteration
164+ } ;
165+
166+ if ( isRunning && ! hasQuotaError ) {
167+ window . addEventListener ( AGENT_WAITING_START_EVENT as any , handleWaitingStart ) ;
168+ window . addEventListener ( AGENT_ITERATION_START_EVENT as any , handleIterationStart ) ;
169+ window . addEventListener ( AGENT_ITERATION_SKIPPED_EVENT as any , handleIterationSkipped ) ;
137170 }
138- return ( ) => { if ( timer ) clearInterval ( timer ) ; } ;
139- } , [ isRunning , liveStatus , agent . loop_interval_seconds , hasQuotaError ] ) ;
171+
172+ return ( ) => {
173+ if ( progressTimer ) clearInterval ( progressTimer ) ;
174+ window . removeEventListener ( AGENT_WAITING_START_EVENT as any , handleWaitingStart ) ;
175+ window . removeEventListener ( AGENT_ITERATION_START_EVENT as any , handleIterationStart ) ;
176+ window . removeEventListener ( AGENT_ITERATION_SKIPPED_EVENT as any , handleIterationSkipped ) ;
177+ } ;
178+ } , [ isRunning , hasQuotaError , agent . id ] ) ;
140179
141180 const handleToggle = async ( ) => {
142181 if ( isRunning ) {
@@ -181,7 +220,8 @@ const AgentCard: React.FC<AgentCardProps> = ({
181220
182221 return (
183222 < div className = "relative bg-white rounded-xl shadow-sm border border-gray-200 transition-all duration-300 flex flex-col" >
184- { isRunning && liveStatus === 'WAITING' && (
223+ { isRunning && ( liveStatus === 'WAITING' || liveStatus === 'THINKING' ) &&
224+ ( Date . now ( ) - lastProgressUpdate < 5000 ) && ( // Hide if progress hasn't updated in 5 seconds
185225 < div className = "absolute top-0 left-0 right-0 h-1 z-10" >
186226 < div className = "h-full bg-green-500" style = { { width : `${ loopProgress } %` , transition : 'width 0.1s linear' } } />
187227 </ div >
0 commit comments