fix(web): émet chat.attached pour les sessions agents structurées au lieu de UNSUPPORTED — #229

This commit is contained in:
2026-08-20 15:10:41 +02:00
parent 1b8534fbf9
commit 023d483ba2
5 changed files with 203 additions and 35 deletions

View File

@ -1559,11 +1559,19 @@ async fn send_launch_agent_attached(
owned: &Arc<Mutex<Vec<(SessionId, u64)>>>,
output: application::LaunchAgentOutput,
) -> Result<(), ErrorDto> {
if output.structured.is_some() {
return Err(ErrorDto {
code: "UNSUPPORTED".to_owned(),
message: "structured agent sessions do not stream over the PTY websocket".to_owned(),
});
if let Some(structured) = output.structured.as_ref() {
tx.send(ServerFrame::chat_attached(
&frame.id,
structured,
output.assigned_conversation_id.as_deref(),
output.engine_session_id.as_deref(),
))
.await
.map_err(|_| ErrorDto {
code: "WS_CLOSED".to_owned(),
message: "websocket output closed".to_owned(),
})?;
return Ok(());
}
let session_id = output.session.id;
let dto = TerminalSessionDto::from(output);
@ -5430,6 +5438,28 @@ impl ServerFrame {
}
}
fn chat_attached(
request_id: &str,
session: &application::StructuredSessionDescriptor,
assigned_conversation_id: Option<&str>,
engine_session_id: Option<&str>,
) -> Self {
Self {
kind: "chat.attached".to_owned(),
reply_to: Some(request_id.to_owned()),
payload: json!({
"sessionId": session.session_id.to_string(),
"session": {
"sessionId": session.session_id.to_string(),
"nodeId": session.node_id.to_string(),
},
"cellKind": "chat",
"assignedConversationId": assigned_conversation_id,
"engineSessionId": engine_session_id,
}),
}
}
fn output(session_id: SessionId, seq: u64, bytes: Vec<u8>) -> Self {
Self {
kind: "terminal.output".to_owned(),
@ -7043,7 +7073,7 @@ mod tests {
}
#[tokio::test]
async fn websocket_launch_agent_structured_is_unsupported() {
async fn websocket_launch_agent_structured_emits_chat_attached() {
let state = state();
let (tx, mut rx) = mpsc::channel(4);
let owned = Arc::new(Mutex::new(Vec::new()));
@ -7073,25 +7103,25 @@ mod tests {
profile: None,
};
if let Err(err) = send_launch_agent_attached(&frame, &state, &tx, &owned, output).await {
tx.send(ServerFrame::error(
Some(frame.id),
payload_session_id(&frame.payload),
err.code,
err.message,
))
send_launch_agent_attached(&frame, &state, &tx, &owned, output)
.await
.unwrap();
}
let error = recv_server_frame(&mut rx).await;
let attached = recv_server_frame(&mut rx).await;
assert_eq!(error.kind, "error");
assert_eq!(error.reply_to.as_deref(), Some("agent-structured"));
assert_eq!(error.payload["code"], "UNSUPPORTED");
assert_eq!(attached.kind, "chat.attached");
assert_eq!(attached.reply_to.as_deref(), Some("agent-structured"));
assert_eq!(attached.payload["sessionId"], session_id.to_string());
assert_eq!(
error.payload["message"],
"structured agent sessions do not stream over the PTY websocket"
attached.payload["session"]["sessionId"],
session_id.to_string()
);
assert_eq!(attached.payload["session"]["nodeId"], node_id.to_string());
assert_eq!(attached.payload["cellKind"], "chat");
assert_eq!(
attached.payload["assignedConversationId"],
"pair-conversation"
);
assert_eq!(attached.payload["engineSessionId"], "engine-session");
assert_eq!(state.ws_pty_bridge.active_sessions(), 0);
}