@@ -12,6 +12,7 @@ import {
1212errToStr ,
1313} from "./api-helper"
1414import { Storage } from "./storage"
15+ import { getMemoryLogger , MemoryLogger } from "./memoryLogger"
1516
1617export enum WorkspaceQuery {
1718Mine = "owner:me" ,
@@ -227,41 +228,80 @@ export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeIte
227228// agent and registers a watcher that can be disposed to stop the watch and
228229// emits an event when the metadata changes.
229230function monitorMetadata ( agentId :WorkspaceAgent [ "id" ] , restClient :Api ) :AgentWatcher {
231+ const logger = getMemoryLogger ( )
232+ logger . trackResourceCreated ( "AgentMetadataWatcher" , agentId )
233+
230234// TODO: Is there a better way to grab the url and token?
231235const url = restClient . getAxiosInstance ( ) . defaults . baseURL
232236const metadataUrl = new URL ( `${ url } /api/v2/workspaceagents/${ agentId } /watch-metadata` )
237+
238+ logger . info ( `Starting metadata watcher for agent:${ agentId } at${ metadataUrl } ` )
239+
233240const eventSource = new EventSource ( metadataUrl . toString ( ) , {
234241fetch :createStreamingFetchAdapter ( restClient . getAxiosInstance ( ) ) ,
235242} )
236243
237244let disposed = false
245+ let eventCount = 0
238246const onChange = new vscode . EventEmitter < null > ( )
239247const watcher :AgentWatcher = {
240248onChange :onChange . event ,
241249dispose :( ) => {
242250if ( ! disposed ) {
251+ logger . info ( `Disposing metadata watcher for agent:${ agentId } after${ eventCount } events` )
243252eventSource . close ( )
253+ onChange . dispose ( )
244254disposed = true
255+ logger . trackResourceDisposed ( "AgentMetadataWatcher" , agentId )
245256}
246257} ,
247258}
248259
260+ eventSource . addEventListener ( "open" , ( ) => {
261+ logger . info ( `Metadata EventSource connection opened for agent:${ agentId } ` )
262+ } )
263+
249264eventSource . addEventListener ( "data" , ( event ) => {
265+ eventCount ++
266+
267+ // Log periodic updates
268+ if ( eventCount % 50 === 0 ) {
269+ logger . info ( `Received${ eventCount } metadata events for agent:${ agentId } ` )
270+ logger . logMemoryUsage ( "AGENT_METADATA" )
271+ }
272+
250273try {
251274const dataEvent = JSON . parse ( event . data )
252275const metadata = AgentMetadataEventSchemaArray . parse ( dataEvent )
253276
254277// Overwrite metadata if it changed.
255278if ( JSON . stringify ( watcher . metadata ) !== JSON . stringify ( metadata ) ) {
279+ if ( eventCount === 1 ) {
280+ logger . debug ( `Initial metadata received for agent:${ agentId } ` )
281+ }
282+
256283watcher . metadata = metadata
257284onChange . fire ( null )
258285}
259286} catch ( error ) {
287+ logger . error ( `Error processing metadata for agent:${ agentId } ` , error )
260288watcher . error = error
261289onChange . fire ( null )
262290}
263291} )
264292
293+ eventSource . addEventListener ( "error" , ( error ) => {
294+ logger . error ( `Metadata EventSource error for agent:${ agentId } ` , error )
295+
296+ // If connection closes permanently, clean up resources
297+ if ( ( error as any ) . readyState === EventSource . CLOSED ) {
298+ logger . info ( `Metadata EventSource connection closed for agent:${ agentId } ` )
299+ if ( ! disposed ) {
300+ watcher . dispose ( )
301+ }
302+ }
303+ } )
304+
265305return watcher
266306}
267307