···
message_counters = defaultdict(int)
100
+
# Synthesis cycle configuration (normal mode uses cycles, synthesis-only uses time interval)
101
+
SYNTHESIS_CYCLES = 10 # trigger synthesis after this many successful mentions
102
+
MENTIONS_SINCE_LAST_SYNTHESIS = 0
103
+
SYNTHESIS_MODE = "mentions" # normal mode synthesis trigger: "mentions" or "time"
···
success = process_mention(void_agent, atproto_client, notif_data, queue_filepath=filepath, testing_mode=testing_mode)
message_counters['mentions'] += 1
1228
+
# Increment synthesis cycle counter and trigger if threshold reached
1229
+
global MENTIONS_SINCE_LAST_SYNTHESIS, SYNTHESIS_CYCLES, last_synthesis_time, SYNTHESIS_MODE
1230
+
if SYNTHESIS_MODE == 'mentions' and SYNTHESIS_CYCLES > 0:
1231
+
MENTIONS_SINCE_LAST_SYNTHESIS += 1
1232
+
logger.debug(f"Mentions since last synthesis: {MENTIONS_SINCE_LAST_SYNTHESIS}/{SYNTHESIS_CYCLES}")
1233
+
if MENTIONS_SINCE_LAST_SYNTHESIS >= SYNTHESIS_CYCLES:
1235
+
f"🧠 Synthesis threshold reached: {MENTIONS_SINCE_LAST_SYNTHESIS}/{SYNTHESIS_CYCLES} mentions. Triggering synthesis."
1238
+
send_synthesis_message(CLIENT, void_agent.id, void_agent.name, atproto_client)
1239
+
last_synthesis_time = time.time()
1240
+
except Exception as e:
1241
+
logger.error(f"Error during synthesis trigger: {e}")
1243
+
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)
···
def send_synthesis_message(client: Letta, agent_id: str, agent_name: str = "void", atproto_client=None) -> None:
1481
-
Send a synthesis message to the agent every 10 minutes.
1482
-
This prompts the agent to synthesize its recent experiences.
1502
+
Send a synthesis message to the agent.
1503
+
This is typically triggered periodically based on the configured schedule
1504
+
(time-based or mention-based) and prompts the agent to synthesize recent experiences.
···
# --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)')
1849
-
parser.add_argument('--synthesis-interval', type=int, default=600, help='Send synthesis message every N seconds (default: 600 = 10 minutes, 0 to disable)')
1871
+
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')
1872
+
parser.add_argument('--synthesis-cycles', type=int, default=10, help='Normal mode: trigger synthesis after N successful mentions (default: 10, 0 to disable)')
1873
+
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()
1924
-
if not args.simple_logs:
1925
-
handler.setFormatter(SymbolFormatter(bot_name))
1927
-
handler.setFormatter(logging.Formatter(log_format))
1948
+
handler.setFormatter(SymbolFormatter(bot_name))
logging.root.setLevel(logging.INFO)
···
logger.info("Skipping Bluesky connection (test mode)")
2036
-
# Configure intervals
2057
+
# Configure intervals / counters
CLEANUP_INTERVAL = args.cleanup_interval
2038
-
SYNTHESIS_INTERVAL = args.synthesis_interval
2059
+
SYNTHESIS_INTERVAL = args.synthesis_interval # used in synthesis-only mode and in normal mode if synthesis-mode=time
2060
+
global SYNTHESIS_CYCLES, MENTIONS_SINCE_LAST_SYNTHESIS, SYNTHESIS_MODE
2061
+
SYNTHESIS_CYCLES = args.synthesis_cycles
2062
+
SYNTHESIS_MODE = args.synthesis_mode
···
logger.info("User block cleanup disabled")
2076
-
if SYNTHESIS_INTERVAL > 0:
2077
-
logger.info(f"Synthesis messages enabled every {SYNTHESIS_INTERVAL} seconds ({SYNTHESIS_INTERVAL/60:.1f} minutes)")
2079
-
logger.info("Synthesis messages disabled")
2100
+
if SYNTHESIS_MODE == 'mentions':
2101
+
if SYNTHESIS_CYCLES > 0:
2102
+
logger.info(f"Synthesis enabled (mode=mentions): every {SYNTHESIS_CYCLES} successful mentions")
2104
+
logger.info("Synthesis disabled in normal mode (mode=mentions, cycles=0)")
2105
+
else: # time-based in normal mode
2106
+
if SYNTHESIS_INTERVAL > 0:
2107
+
logger.info(f"Synthesis enabled (mode=time): every {SYNTHESIS_INTERVAL} seconds ({SYNTHESIS_INTERVAL/60:.1f} minutes)")
2109
+
logger.info("Synthesis disabled in normal mode (mode=time, interval=0)")
process_notifications(void_agent, atproto_client, TESTING_MODE)
2086
-
# Check if synthesis interval has passed
2087
-
if SYNTHESIS_INTERVAL > 0:
2116
+
# If using time-based synthesis in normal mode, check timer
2117
+
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})")