feat(chat): persistance bornee du brouillon custom chat par projet/layout (#182)

This commit is contained in:
2026-08-11 16:24:20 +02:00
parent 25ad44a3d9
commit 94b4ce7e5f
23 changed files with 1552 additions and 70 deletions

View File

@ -7,9 +7,10 @@
//! `cellKind` and PTY paths keep `"pty"`.
use app_tauri_lib::dto::{
CellKind, ChatAttachmentDto, ChatAttachmentInputDto, ImportChatAttachmentsRequestDto,
ImportChatAttachmentsResponseDto, ReattachChatDto, ReplyChunk, ReplyProgressDto,
ReplyProgressKindDto, ReplyProgressSourceDto, ReplyProgressStageDto, TerminalSessionDto,
CellKind, ChatAttachmentDto, ChatAttachmentInputDto, ChatDraftScopeRequestDto,
ImportChatAttachmentsRequestDto, ImportChatAttachmentsResponseDto, ReadChatDraftResponseDto,
ReattachChatDto, ReplyChunk, ReplyProgressDto, ReplyProgressKindDto, ReplyProgressSourceDto,
ReplyProgressStageDto, SaveChatDraftRequestDto, TerminalSessionDto,
};
use application::{LaunchAgentOutput, StructuredSessionDescriptor};
use domain::project::ProjectPath;
@ -154,6 +155,50 @@ fn reply_chunk_rejects_snake_case_tag() {
// Chat attachments — structured input + durable metadata, camelCase
// ---------------------------------------------------------------------------
#[test]
fn chat_draft_scope_request_deserialises_camel_case() {
let dto: ChatDraftScopeRequestDto = serde_json::from_value(json!({
"projectId": Uuid::from_u128(1).to_string(),
"layoutId": Uuid::from_u128(2).to_string(),
"nodeId": Uuid::from_u128(3).to_string()
}))
.unwrap();
assert_eq!(dto.project_id, Uuid::from_u128(1).to_string());
assert_eq!(dto.layout_id, Uuid::from_u128(2).to_string());
assert_eq!(dto.node_id, Uuid::from_u128(3).to_string());
}
#[test]
fn save_chat_draft_request_deserialises_text_only_camel_case() {
let dto: SaveChatDraftRequestDto = serde_json::from_value(json!({
"projectId": Uuid::from_u128(1).to_string(),
"layoutId": Uuid::from_u128(2).to_string(),
"nodeId": Uuid::from_u128(3).to_string(),
"text": "draft text"
}))
.unwrap();
assert_eq!(dto.text, "draft text");
}
#[test]
fn read_chat_draft_response_serialises_camel_case() {
let dto = ReadChatDraftResponseDto {
text: Some("draft text".to_owned()),
updated_at_ms: Some(42),
};
let v = serde_json::to_value(dto).unwrap();
assert_eq!(v["text"], "draft text");
assert_eq!(v["updatedAtMs"], 42);
assert!(v.get("updated_at_ms").is_none(), "no snake_case leak");
assert!(
v.get("attachments").is_none(),
"drafts never persist attachments"
);
}
#[test]
fn chat_attachment_input_dto_deserialises_camel_case() {
let dto: ChatAttachmentInputDto = serde_json::from_value(json!({