a digital person for bluesky

Add timeout protection and silence ping messages in streaming

- Add 10-minute timeout to prevent infinite hangs in streaming loops
- Silence 'ping' keepalive messages (log at debug level only)
- Apply to both notification processing and synthesis streams
- Prevents logs from being spammed with ping messages
- Stream will break after 600 seconds if agent doesn't send 'done'

This fixes the issue where streaming would hang indefinitely
when agents get stuck or don't complete properly.

๐Ÿพ Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

+22 -2
+22 -2
bsky.py
··· 419 419 max_steps=100 420 420 ) 421 421 422 - # Collect the streaming response 422 + # Collect the streaming response with timeout protection 423 423 all_messages = [] 424 + stream_start_time = time.time() 425 + max_stream_duration = 600 # 10 minutes max 426 + 424 427 for chunk in message_stream: 428 + # Check for timeout 429 + if time.time() - stream_start_time > max_stream_duration: 430 + logger.warning(f"Stream exceeded {max_stream_duration}s timeout, breaking") 431 + break 425 432 # Log condensed chunk info 426 433 if hasattr(chunk, 'message_type'): 427 434 if chunk.message_type == 'reasoning_message': ··· 606 613 logger.error(f"Agent error (dict): {chunk.model_dump()}") 607 614 elif hasattr(chunk, '__dict__'): 608 615 logger.error(f"Agent error (vars): {vars(chunk)}") 616 + elif chunk.message_type == 'ping': 617 + # Silently ignore ping keepalive messages 618 + logger.debug(f"Received keepalive ping from Letta API") 609 619 else: 610 620 # Filter out verbose message types 611 621 if chunk.message_type not in ['usage_statistics', 'stop_reason']: ··· 1582 1592 synthesis_posts = [] 1583 1593 ack_note = None 1584 1594 1585 - # Process the streaming response 1595 + # Process the streaming response with timeout protection 1596 + stream_start_time = time.time() 1597 + max_stream_duration = 600 # 10 minutes max 1598 + 1586 1599 for chunk in message_stream: 1600 + # Check for timeout 1601 + if time.time() - stream_start_time > max_stream_duration: 1602 + logger.warning(f"Synthesis stream exceeded {max_stream_duration}s timeout, breaking") 1603 + break 1587 1604 if hasattr(chunk, 'message_type'): 1588 1605 if chunk.message_type == 'reasoning_message': 1589 1606 if SHOW_REASONING: ··· 1669 1686 print(" โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€") 1670 1687 for line in chunk.content.split('\n'): 1671 1688 print(f" {line}") 1689 + elif chunk.message_type == 'ping': 1690 + # Silently ignore ping keepalive messages 1691 + logger.debug(f"Received keepalive ping from Letta API during synthesis") 1672 1692 elif chunk.message_type == 'error_message': 1673 1693 # Dump full error object 1674 1694 logger.error(f"Synthesis error_message: {chunk}")