feat: add reactive streaming and remove dead panel stream code
- Subscribe to StreamCascadeReactiveUpdates for real-time cascade state diffs - Fall back to timer-based polling if streaming RPC unavailable - Remove StreamCascadePanelReactiveUpdates code (dead end, only has plan_status/user_settings) - Remove debug diff file-saving code - Add stream_reactive_rpc() helper to backend
This commit is contained in:
@@ -443,7 +443,7 @@ async fn handle_responses_stream(
|
||||
}),
|
||||
));
|
||||
|
||||
// ── Phase 1: Poll for thinking content (arrives before response text) ──
|
||||
// ── Stream cascade updates: event-driven instead of timer-based polling ──
|
||||
let start = std::time::Instant::now();
|
||||
let mut last_text = String::new();
|
||||
let mut thinking_emitted = false;
|
||||
@@ -451,6 +451,20 @@ async fn handle_responses_stream(
|
||||
let mut message_started = false;
|
||||
let reasoning_id = format!("rs_{}", uuid::Uuid::new_v4().to_string().replace('-', ""));
|
||||
|
||||
// Try to open a reactive streaming connection for real-time notifications.
|
||||
// Falls back to timer-based polling if the streaming RPC is unavailable.
|
||||
let mut reactive_rx = match state.backend.stream_cascade_updates(&cascade_id).await {
|
||||
Ok(rx) => {
|
||||
debug!("Using reactive streaming for cascade updates");
|
||||
Some(rx)
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("Reactive streaming unavailable, falling back to polling: {e}");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
while start.elapsed().as_secs() < timeout {
|
||||
if let Ok((status, data)) = state.backend.get_steps(&cascade_id).await {
|
||||
if status == 200 {
|
||||
@@ -648,8 +662,33 @@ async fn handle_responses_stream(
|
||||
}
|
||||
}
|
||||
|
||||
let poll_ms: u64 = rand::thread_rng().gen_range(150..250);
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(poll_ms)).await;
|
||||
// Wait for next update: either reactive notification or fallback timer
|
||||
match reactive_rx {
|
||||
Some(ref mut rx) => {
|
||||
// Wait for reactive notification with a safety timeout
|
||||
let timeout = tokio::time::timeout(
|
||||
tokio::time::Duration::from_millis(500),
|
||||
rx.recv(),
|
||||
).await;
|
||||
match timeout {
|
||||
Ok(Some(_diff)) => {
|
||||
// Drain any additional queued notifications (coalesce)
|
||||
while rx.try_recv().is_ok() {}
|
||||
}
|
||||
Ok(None) => {
|
||||
// Stream closed — fall back to polling
|
||||
debug!("Reactive stream closed, falling back to polling");
|
||||
reactive_rx = None;
|
||||
}
|
||||
Err(_) => {} // timeout — fetch anyway as safety net
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Fallback: timer-based polling
|
||||
let poll_ms: u64 = rand::thread_rng().gen_range(150..250);
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(poll_ms)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Timeout — emit incomplete response
|
||||
|
||||
Reference in New Issue
Block a user