feat: unify creation agent chat fill

This commit is contained in:
2026-04-25 10:50:19 +08:00
parent c06bf84d0a
commit 31f350d499
26 changed files with 540 additions and 153 deletions

View File

@@ -9,11 +9,13 @@ use spacetime_client::{
use crate::creation_agent_anchor_templates::{
get_creation_agent_anchor_template, render_anchor_question_block,
};
use crate::creation_agent_chat::render_quick_fill_extra_rules;
#[derive(Clone, Debug)]
pub(crate) struct BigFishAgentTurnRequest<'a> {
pub llm_client: Option<&'a LlmClient>,
pub session: &'a BigFishSessionRecord,
pub quick_fill_requested: bool,
}
#[derive(Clone, Debug)]
@@ -115,7 +117,7 @@ where
let llm_client = request
.llm_client
.ok_or_else(|| BigFishAgentTurnError::new("当前模型不可用,请稍后重试。"))?;
let prompt = build_big_fish_agent_prompt(request.session);
let prompt = build_big_fish_agent_prompt(request.session, request.quick_fill_requested);
let mut latest_reply_text = String::new();
let response = llm_client
.stream_text(
@@ -146,7 +148,11 @@ where
Ok(BigFishAgentTurnResult {
assistant_reply_text: output.reply_text,
stage: BigFishCreationStage::CollectingAnchors.as_str().to_string(),
progress_percent: output.progress_percent.min(100),
progress_percent: if request.quick_fill_requested {
100
} else {
output.progress_percent.min(100)
},
anchor_pack_json: serde_json::to_string(&output.next_anchor_pack)
.unwrap_or_else(|_| "{}".to_string()),
error_message: None,
@@ -193,15 +199,33 @@ pub(crate) fn build_failed_finalize_record_input(
}
}
fn build_big_fish_agent_prompt(session: &BigFishSessionRecord) -> String {
fn build_big_fish_agent_prompt(
session: &BigFishSessionRecord,
quick_fill_requested: bool,
) -> String {
let anchor_question_block = get_creation_agent_anchor_template("big_fish")
.map(render_anchor_question_block)
.unwrap_or_else(|| "模板目标:收束成可玩的竖屏大鱼吃小鱼玩法草稿。".to_string());
let quick_fill_rules = if quick_fill_requested {
format!(
"\n\n{}",
render_quick_fill_extra_rules(
"当前玩法方向里的成长、生态、风险节奏等缺失关键词",
"不要要求用户再提供等级、鱼群、场景或节奏信息",
"输出完整 nextAnchorPack直接补齐 value 为空或 status 为 missing 的项",
"生成结果页",
)
)
} else {
String::new()
};
format!(
"{anchor_question_block}\n\n当前是第 {turn} 轮,当前进度 {progress}% 。\n\n当前 anchor pack\n{anchor_pack}\n\n最近聊天记录:\n{chat_history}\n\n{contract}",
"{anchor_question_block}{quick_fill_rules}\n\n当前是第 {turn} 轮,当前进度 {progress}% 。\n\n是否要求自动补充剩余关键字:{quick_fill_requested_text}\n\n当前 anchor pack\n{anchor_pack}\n\n最近聊天记录:\n{chat_history}\n\n{contract}",
anchor_question_block = anchor_question_block,
quick_fill_rules = quick_fill_rules,
turn = session.current_turn.saturating_add(1),
progress = session.progress_percent,
quick_fill_requested_text = if quick_fill_requested { "" } else { "" },
anchor_pack = serialize_record_anchor_pack(&session.anchor_pack),
chat_history =
serde_json::to_string_pretty(&build_chat_history(session.messages.as_slice()))
@@ -315,7 +339,7 @@ fn default_big_fish_anchor_label(field_name: &str) -> &'static str {
fn serialize_record_anchor_pack(anchor_pack: &spacetime_client::BigFishAnchorPackRecord) -> String {
serde_json::to_string_pretty(&map_big_fish_record_anchor_pack(anchor_pack))
.unwrap_or_else(|_| "{}".to_string())
.unwrap_or_else(|_| "{}".to_string())
}
fn map_big_fish_record_anchor_pack(
@@ -399,3 +423,70 @@ fn extract_reply_text_from_partial_json(text: &str) -> Option<String> {
Some(result)
}
}
#[cfg(test)]
mod tests {
use super::build_big_fish_agent_prompt;
fn anchor_item(
key: &str,
label: &str,
value: &str,
status: &str,
) -> spacetime_client::BigFishAnchorItemRecord {
spacetime_client::BigFishAnchorItemRecord {
key: key.to_string(),
label: label.to_string(),
value: value.to_string(),
status: status.to_string(),
}
}
fn empty_session_record() -> spacetime_client::BigFishSessionRecord {
spacetime_client::BigFishSessionRecord {
session_id: "big-fish-session-test".to_string(),
current_turn: 2,
progress_percent: 60,
stage: "collecting_anchors".to_string(),
anchor_pack: spacetime_client::BigFishAnchorPackRecord {
gameplay_promise: anchor_item(
"gameplayPromise",
"玩法承诺",
"微光小鱼逆袭深海巨兽",
"confirmed",
),
ecology_visual_theme: anchor_item(
"ecologyVisualTheme",
"生态视觉主题",
"幽蓝珊瑚海沟",
"confirmed",
),
growth_ladder: anchor_item("growthLadder", "成长阶梯", "", "missing"),
risk_tempo: anchor_item("riskTempo", "风险节奏", "", "missing"),
},
draft: None,
asset_slots: Vec::new(),
asset_coverage: spacetime_client::BigFishAssetCoverageRecord {
level_main_image_ready_count: 0,
level_motion_ready_count: 0,
background_ready: false,
required_level_count: 8,
publish_ready: false,
blockers: Vec::new(),
},
messages: Vec::new(),
last_assistant_reply: None,
publish_ready: false,
updated_at: "2026-04-24T10:00:00.000Z".to_string(),
}
}
#[test]
fn quick_fill_prompt_forbids_follow_up_questions() {
let prompt = build_big_fish_agent_prompt(&empty_session_record(), true);
assert!(prompt.contains("用户刚刚主动要求你自动补充剩余关键字"));
assert!(prompt.contains("不要再继续提问"));
assert!(prompt.contains("progressPercent 直接输出为 100"));
}
}