Synthesis on a mention based interval V2 #9

open
opened by lenooby09.tech targeting main
Changed files
+46 -16
+46 -16
bsky.py
···
message_counters = defaultdict(int)
start_time = time.time()
+
# Synthesis cycle configuration (normal mode uses cycles, synthesis-only uses time interval)
+
SYNTHESIS_CYCLES = 10 # trigger synthesis after this many successful mentions
+
MENTIONS_SINCE_LAST_SYNTHESIS = 0
+
SYNTHESIS_MODE = "mentions" # normal mode synthesis trigger: "mentions" or "time"
+
# Testing mode flag
TESTING_MODE = False
···
success = process_mention(void_agent, atproto_client, notif_data, queue_filepath=filepath, testing_mode=testing_mode)
if success:
message_counters['mentions'] += 1
+
# Increment synthesis cycle counter and trigger if threshold reached
+
global MENTIONS_SINCE_LAST_SYNTHESIS, SYNTHESIS_CYCLES, last_synthesis_time, SYNTHESIS_MODE
+
if SYNTHESIS_MODE == 'mentions' and SYNTHESIS_CYCLES > 0:
+
MENTIONS_SINCE_LAST_SYNTHESIS += 1
+
logger.debug(f"Mentions since last synthesis: {MENTIONS_SINCE_LAST_SYNTHESIS}/{SYNTHESIS_CYCLES}")
+
if MENTIONS_SINCE_LAST_SYNTHESIS >= SYNTHESIS_CYCLES:
+
logger.info(
+
f"🧠 Synthesis threshold reached: {MENTIONS_SINCE_LAST_SYNTHESIS}/{SYNTHESIS_CYCLES} mentions. Triggering synthesis."
+
)
+
try:
+
send_synthesis_message(CLIENT, void_agent.id, void_agent.name, atproto_client)
+
last_synthesis_time = time.time()
+
except Exception as e:
+
logger.error(f"Error during synthesis trigger: {e}")
+
finally:
+
MENTIONS_SINCE_LAST_SYNTHESIS = 0
elif notif_data['reason'] == "reply":
success = process_mention(void_agent, atproto_client, notif_data, queue_filepath=filepath, testing_mode=testing_mode)
if success:
···
def send_synthesis_message(client: Letta, agent_id: str, agent_name: str = "void", atproto_client=None) -> None:
"""
-
Send a synthesis message to the agent every 10 minutes.
-
This prompts the agent to synthesize its recent experiences.
+
Send a synthesis message to the agent.
+
This is typically triggered periodically based on the configured schedule
+
(time-based or mention-based) and prompts the agent to synthesize recent experiences.
Args:
client: Letta client
···
# --rich option removed as we now use simple text formatting
parser.add_argument('--reasoning', action='store_true', help='Display reasoning in panels and set reasoning log level to INFO')
parser.add_argument('--cleanup-interval', type=int, default=10, help='Run user block cleanup every N cycles (default: 10, 0 to disable)')
-
parser.add_argument('--synthesis-interval', type=int, default=600, help='Send synthesis message every N seconds (default: 600 = 10 minutes, 0 to disable)')
+
parser.add_argument('--synthesis-interval', type=int, default=600, help='Synthesis-only mode: send synthesis every N seconds (default: 600 = 10 minutes); used in normal mode when --synthesis-mode=time')
+
parser.add_argument('--synthesis-cycles', type=int, default=10, help='Normal mode: trigger synthesis after N successful mentions (default: 10, 0 to disable)')
+
parser.add_argument('--synthesis-mode', choices=['mentions', 'time'], default='mentions', help='Normal mode: choose synthesis trigger mechanism: mentions (after N successful mentions) or time (every N seconds). Default: mentions')
parser.add_argument('--synthesis-only', action='store_true', help='Run in synthesis-only mode (only send synthesis messages, no notification processing)')
parser.add_argument('--debug', action='store_true', help='Enable debug logging')
args = parser.parse_args()
···
# Create handler with custom formatter
handler = logging.StreamHandler()
-
if not args.simple_logs:
-
handler.setFormatter(SymbolFormatter(bot_name))
-
else:
-
handler.setFormatter(logging.Formatter(log_format))
+
handler.setFormatter(SymbolFormatter(bot_name))
# Configure root logger
logging.root.setLevel(logging.INFO)
···
atproto_client = None
logger.info("Skipping Bluesky connection (test mode)")
-
# Configure intervals
+
# Configure intervals / counters
CLEANUP_INTERVAL = args.cleanup_interval
-
SYNTHESIS_INTERVAL = args.synthesis_interval
+
SYNTHESIS_INTERVAL = args.synthesis_interval # used in synthesis-only mode and in normal mode if synthesis-mode=time
+
global SYNTHESIS_CYCLES, MENTIONS_SINCE_LAST_SYNTHESIS, SYNTHESIS_MODE
+
SYNTHESIS_CYCLES = args.synthesis_cycles
+
SYNTHESIS_MODE = args.synthesis_mode
# Synthesis-only mode
if SYNTHESIS_ONLY:
···
else:
logger.info("User block cleanup disabled")
-
if SYNTHESIS_INTERVAL > 0:
-
logger.info(f"Synthesis messages enabled every {SYNTHESIS_INTERVAL} seconds ({SYNTHESIS_INTERVAL/60:.1f} minutes)")
-
else:
-
logger.info("Synthesis messages disabled")
+
if SYNTHESIS_MODE == 'mentions':
+
if SYNTHESIS_CYCLES > 0:
+
logger.info(f"Synthesis enabled (mode=mentions): every {SYNTHESIS_CYCLES} successful mentions")
+
else:
+
logger.info("Synthesis disabled in normal mode (mode=mentions, cycles=0)")
+
else: # time-based in normal mode
+
if SYNTHESIS_INTERVAL > 0:
+
logger.info(f"Synthesis enabled (mode=time): every {SYNTHESIS_INTERVAL} seconds ({SYNTHESIS_INTERVAL/60:.1f} minutes)")
+
else:
+
logger.info("Synthesis disabled in normal mode (mode=time, interval=0)")
while True:
try:
cycle_count += 1
process_notifications(void_agent, atproto_client, TESTING_MODE)
-
# Check if synthesis interval has passed
-
if SYNTHESIS_INTERVAL > 0:
+
# If using time-based synthesis in normal mode, check timer
+
if SYNTHESIS_MODE == 'time' and SYNTHESIS_INTERVAL > 0:
current_time = time.time()
global last_synthesis_time
if current_time - last_synthesis_time >= SYNTHESIS_INTERVAL:
logger.info(f"⏰ {SYNTHESIS_INTERVAL/60:.1f} minutes have passed, triggering synthesis")
send_synthesis_message(CLIENT, void_agent.id, void_agent.name, atproto_client)
last_synthesis_time = current_time
-
+
# Run periodic cleanup every N cycles
if CLEANUP_INTERVAL > 0 and cycle_count % CLEANUP_INTERVAL == 0:
logger.debug(f"Running periodic user block cleanup (cycle {cycle_count})")