複数クライアント間でのRunメソッドの同期漏れ
This commit is contained in:
parent
18533b3580
commit
a39bce779c
|
|
@ -279,6 +279,13 @@ impl PodController {
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Broadcast the accepted user message so every
|
||||||
|
// subscriber (including the submitter) can
|
||||||
|
// render the turn header + user line from a
|
||||||
|
// single source of truth.
|
||||||
|
let _ = event_tx.send(Event::UserMessage {
|
||||||
|
text: input.clone(),
|
||||||
|
});
|
||||||
let was_paused = status_before == PodStatus::Paused;
|
let was_paused = status_before == PodStatus::Paused;
|
||||||
shared_state.set_status(PodStatus::Running);
|
shared_state.set_status(PodStatus::Running);
|
||||||
let _ = runtime_dir.write_status(&shared_state).await;
|
let _ = runtime_dir.write_status(&shared_state).await;
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,18 @@ pub enum PodEvent {
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "event", content = "data", rename_all = "snake_case")]
|
#[serde(tag = "event", content = "data", rename_all = "snake_case")]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
|
/// A user input message was accepted by the Pod and is about to
|
||||||
|
/// start a new turn. Broadcast to every subscribed client so
|
||||||
|
/// additional TUI / GUI instances show the same pending user line
|
||||||
|
/// that the submitter already sees — without this event, non-
|
||||||
|
/// submitting clients would see tool calls and assistant text
|
||||||
|
/// appear without any preceding user message.
|
||||||
|
///
|
||||||
|
/// Fires exactly once per accepted `Method::Run`, before
|
||||||
|
/// `TurnStart`. Rejected runs (e.g. `AlreadyRunning`) do not emit.
|
||||||
|
UserMessage {
|
||||||
|
text: String,
|
||||||
|
},
|
||||||
TurnStart {
|
TurnStart {
|
||||||
turn: usize,
|
turn: usize,
|
||||||
},
|
},
|
||||||
|
|
@ -596,4 +608,21 @@ mod tests {
|
||||||
assert_eq!(parsed["event"], "error");
|
assert_eq!(parsed["event"], "error");
|
||||||
assert_eq!(parsed["data"]["code"], "already_running");
|
assert_eq!(parsed["data"]["code"], "already_running");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn event_user_message_roundtrip() {
|
||||||
|
let event = Event::UserMessage {
|
||||||
|
text: "hello 世界".into(),
|
||||||
|
};
|
||||||
|
let json = serde_json::to_string(&event).unwrap();
|
||||||
|
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
|
||||||
|
assert_eq!(parsed["event"], "user_message");
|
||||||
|
assert_eq!(parsed["data"]["text"], "hello 世界");
|
||||||
|
|
||||||
|
let decoded: Event = serde_json::from_str(&json).unwrap();
|
||||||
|
match decoded {
|
||||||
|
Event::UserMessage { text } => assert_eq!(text, "hello 世界"),
|
||||||
|
other => panic!("expected UserMessage, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,11 +72,10 @@ impl App {
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.turn_index += 1;
|
// TurnHeader / UserMessage blocks are pushed in response to
|
||||||
self.blocks.push(Block::TurnHeader {
|
// `Event::UserMessage` (single source of truth, shared by every
|
||||||
turn: self.turn_index,
|
// client subscribed to the Pod). Locally we only clear the
|
||||||
});
|
// input buffer and forward the method.
|
||||||
self.blocks.push(Block::UserMessage { text: text.clone() });
|
|
||||||
self.input.clear();
|
self.input.clear();
|
||||||
Some(Method::Run { input: text })
|
Some(Method::Run { input: text })
|
||||||
}
|
}
|
||||||
|
|
@ -91,6 +90,14 @@ impl App {
|
||||||
|
|
||||||
pub fn handle_pod_event(&mut self, event: Event) {
|
pub fn handle_pod_event(&mut self, event: Event) {
|
||||||
match event {
|
match event {
|
||||||
|
Event::UserMessage { text } => {
|
||||||
|
self.turn_index += 1;
|
||||||
|
self.blocks.push(Block::TurnHeader {
|
||||||
|
turn: self.turn_index,
|
||||||
|
});
|
||||||
|
self.blocks.push(Block::UserMessage { text });
|
||||||
|
self.assistant_streaming = false;
|
||||||
|
}
|
||||||
Event::TurnStart { .. } => {
|
Event::TurnStart { .. } => {
|
||||||
self.running = true;
|
self.running = true;
|
||||||
self.paused = false;
|
self.paused = false;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user