Files
Genarrative/server-rs/crates/module-editor-agent/src/domain.rs
T
k88936 2fa05cd605 统一画布代理文本与附件输入约束
要求用户消息包含非空文本,附件仅作为消息上下文。
同步后端领域校验、接口错误和请求测试。
禁用前端纯附件发送并更新交互回归测试。
保留发送失败时的草稿与附件恢复行为。
2026-07-31 11:30:48 +08:00

58 lines
2.4 KiB
Rust

//! 画布Agent对话领域模型。
//!
//! 本 crate 只描述会话元数据、消息与附件的纯领域事实与规则;
//! LLM、SSE、OSS 读写和 SpacetimeDB 写表均留在外层 adapter。
use serde::{Deserialize, Serialize};
#[cfg(feature = "spacetime-types")]
use spacetimedb::SpacetimeType;
pub const EDITOR_AGENT_CONVERSATION_ID_PREFIX: &str = "editor-agent-conv-";
pub const EDITOR_AGENT_MESSAGE_ID_PREFIX: &str = "editor-agent-message-";
/// 会话消息 OSS 对象目录前缀,完整键见 [`editor_agent_messages_object_key`]。
pub const EDITOR_AGENT_MESSAGES_OBJECT_PREFIX: &str = "editor-agent/";
/// 单条消息附件上限(超出由前端拦截、后端兜底拒绝)。
pub const EDITOR_AGENT_MAX_ATTACHMENTS: usize = 9;
/// 会话标题取首条用户消息的前 N 个字符。
pub const EDITOR_AGENT_TITLE_MAX_CHARS: usize = 20;
/// 新会话默认标题。
pub const EDITOR_AGENT_DEFAULT_CONVERSATION_TITLE: &str = "新对话";
/// 会话元数据快照:SpacetimeDB 表只存这些字段,消息正文整体存 OSS。
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EditorAgentConversationSnapshot {
pub conversation_id: String,
pub project_id: String,
pub owner_user_id: String,
pub title: String,
pub messages_object_key: String,
pub deleted: bool,
pub created_at_micros: i64,
pub updated_at_micros: i64,
}
/// 会话消息 OSS 对象键:`editor-agent/{conversationId}.json`,会话粒度整体读写。
pub fn editor_agent_messages_object_key(conversation_id: &str) -> String {
format!("{EDITOR_AGENT_MESSAGES_OBJECT_PREFIX}{conversation_id}.json")
}
/// 从首条用户消息推导会话标题:去掉首尾空白与换行后截取前 N 个字符;
/// 空文本退回默认标题,供尚未发送消息的新会话使用。
pub fn derive_conversation_title(first_message_text: &str) -> String {
let normalized: String = first_message_text
.chars()
.map(|c| if c == '\n' || c == '\r' { ' ' } else { c })
.collect::<String>()
.split_whitespace()
.collect::<Vec<_>>()
.join(" ");
if normalized.is_empty() {
return EDITOR_AGENT_DEFAULT_CONVERSATION_TITLE.to_string();
}
normalized
.chars()
.take(EDITOR_AGENT_TITLE_MAX_CHARS)
.collect()
}