拆分大文件
This commit is contained in:
@@ -611,7 +611,10 @@ where
|
||||
empty_json_array()
|
||||
};
|
||||
let asset_coverage_json = if should_stay_in_draft_stage {
|
||||
serialize_json(&request.session.asset_coverage, &empty_agent_asset_coverage_json())
|
||||
serialize_json(
|
||||
&request.session.asset_coverage,
|
||||
&empty_agent_asset_coverage_json(),
|
||||
)
|
||||
} else {
|
||||
empty_agent_asset_coverage_json()
|
||||
};
|
||||
@@ -732,7 +735,10 @@ pub(crate) fn build_failed_finalize_record_input(
|
||||
stage: session.stage.clone(),
|
||||
progress_percent: session.progress_percent,
|
||||
focus_card_id: session.focus_card_id.clone(),
|
||||
anchor_content_json: serialize_json(&session.anchor_content, &empty_agent_anchor_content_json()),
|
||||
anchor_content_json: serialize_json(
|
||||
&session.anchor_content,
|
||||
&empty_agent_anchor_content_json(),
|
||||
),
|
||||
creator_intent_json: serialize_optional_json_object(&session.creator_intent),
|
||||
creator_intent_readiness_json: serialize_json(
|
||||
&session.creator_intent_readiness,
|
||||
@@ -753,7 +759,10 @@ pub(crate) fn build_failed_finalize_record_input(
|
||||
&JsonValue::Array(session.quality_findings.clone()),
|
||||
&empty_json_array(),
|
||||
),
|
||||
asset_coverage_json: serialize_json(&session.asset_coverage, &empty_agent_asset_coverage_json()),
|
||||
asset_coverage_json: serialize_json(
|
||||
&session.asset_coverage,
|
||||
&empty_agent_asset_coverage_json(),
|
||||
),
|
||||
error_message: Some(error_message),
|
||||
updated_at_micros,
|
||||
}
|
||||
@@ -771,13 +780,18 @@ async fn stream_single_turn<F>(
|
||||
where
|
||||
F: FnMut(&str),
|
||||
{
|
||||
let llm_client = llm_client.ok_or_else(|| {
|
||||
CustomWorldTurnError::new("当前模型不可用,请稍后重试。")
|
||||
})?;
|
||||
let llm_client =
|
||||
llm_client.ok_or_else(|| CustomWorldTurnError::new("当前模型不可用,请稍后重试。"))?;
|
||||
let chat_history = build_chat_history(messages);
|
||||
let dynamic_state =
|
||||
resolve_dynamic_state(llm_client, current_turn, progress_percent, quick_fill_requested, current_anchor_content, &chat_history)
|
||||
.await;
|
||||
let dynamic_state = resolve_dynamic_state(
|
||||
llm_client,
|
||||
current_turn,
|
||||
progress_percent,
|
||||
quick_fill_requested,
|
||||
current_anchor_content,
|
||||
&chat_history,
|
||||
)
|
||||
.await;
|
||||
let prompt = build_eight_anchor_single_turn_prompt(
|
||||
current_turn,
|
||||
progress_percent,
|
||||
@@ -806,27 +820,21 @@ where
|
||||
)
|
||||
.await;
|
||||
|
||||
let response = response.map_err(|_| {
|
||||
CustomWorldTurnError::new("这一轮设定生成失败,请稍后重试。")
|
||||
})?;
|
||||
let response =
|
||||
response.map_err(|_| CustomWorldTurnError::new("这一轮设定生成失败,请稍后重试。"))?;
|
||||
|
||||
let parsed = parse_json_response_text(response.content.as_str()).map_err(|_| {
|
||||
CustomWorldTurnError::new("模型返回结果解析失败,请稍后重试。")
|
||||
})?;
|
||||
let parsed = parse_json_response_text(response.content.as_str())
|
||||
.map_err(|_| CustomWorldTurnError::new("模型返回结果解析失败,请稍后重试。"))?;
|
||||
|
||||
let next_anchor_content = normalize_eight_anchor_content(
|
||||
parsed
|
||||
.get("nextAnchorContent")
|
||||
.unwrap_or(&JsonValue::Null),
|
||||
);
|
||||
let next_anchor_content =
|
||||
normalize_eight_anchor_content(parsed.get("nextAnchorContent").unwrap_or(&JsonValue::Null));
|
||||
let progress_percent = if quick_fill_requested {
|
||||
100
|
||||
} else {
|
||||
clamp_progress_percent(parsed.get("progressPercent"))
|
||||
};
|
||||
let reply_text = to_text(parsed.get("replyText")).ok_or_else(|| {
|
||||
CustomWorldTurnError::new("模型返回结果缺少有效回复,请稍后重试。")
|
||||
})?;
|
||||
let reply_text = to_text(parsed.get("replyText"))
|
||||
.ok_or_else(|| CustomWorldTurnError::new("模型返回结果缺少有效回复,请稍后重试。"))?;
|
||||
if reply_text != latest_reply_text {
|
||||
on_reply_update(reply_text.as_str());
|
||||
}
|
||||
@@ -907,13 +915,19 @@ fn build_prompt_dynamic_state(
|
||||
let Some(inference) = inference else {
|
||||
return fallback;
|
||||
};
|
||||
let user_input_signal = inference.user_input_signal.unwrap_or(fallback.user_input_signal);
|
||||
let user_input_signal = inference
|
||||
.user_input_signal
|
||||
.unwrap_or(fallback.user_input_signal);
|
||||
let drift_risk = inference.drift_risk.unwrap_or(fallback.drift_risk);
|
||||
let conversation_mode = inference.conversation_mode.unwrap_or(fallback.conversation_mode);
|
||||
let conversation_mode = inference
|
||||
.conversation_mode
|
||||
.unwrap_or(fallback.conversation_mode);
|
||||
let judgement_summary = inference
|
||||
.judgement_summary
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.unwrap_or_else(|| summarize_dynamic_state(user_input_signal, drift_risk, conversation_mode));
|
||||
.unwrap_or_else(|| {
|
||||
summarize_dynamic_state(user_input_signal, drift_risk, conversation_mode)
|
||||
});
|
||||
|
||||
PromptDynamicState {
|
||||
current_turn,
|
||||
@@ -966,7 +980,11 @@ fn build_prompt_dynamic_state_inference_prompt(
|
||||
chat_history: &[JsonValue],
|
||||
) -> (String, String) {
|
||||
(
|
||||
[STATE_INFERENCE_SYSTEM_PROMPT, STATE_INFERENCE_OUTPUT_CONTRACT].join("\n\n"),
|
||||
[
|
||||
STATE_INFERENCE_SYSTEM_PROMPT,
|
||||
STATE_INFERENCE_OUTPUT_CONTRACT,
|
||||
]
|
||||
.join("\n\n"),
|
||||
[
|
||||
format!("当前轮次:{current_turn}"),
|
||||
format!("当前完成度:{progress_percent}"),
|
||||
@@ -1010,7 +1028,8 @@ fn build_chat_history(messages: &[CustomWorldAgentMessageRecord]) -> Vec<JsonVal
|
||||
messages
|
||||
.iter()
|
||||
.filter(|message| {
|
||||
(message.role == "user" || message.role == "assistant") && !message.text.trim().is_empty()
|
||||
(message.role == "user" || message.role == "assistant")
|
||||
&& !message.text.trim().is_empty()
|
||||
})
|
||||
.map(|message| {
|
||||
json!({
|
||||
@@ -1059,8 +1078,7 @@ fn build_creator_intent_from_eight_anchor_content(
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(
|
||||
(!value.hidden_crisis.trim().is_empty())
|
||||
.then_some(value.hidden_crisis.clone()),
|
||||
(!value.hidden_crisis.trim().is_empty()).then_some(value.hidden_crisis.clone()),
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
@@ -1205,7 +1223,10 @@ fn evaluate_creator_intent_readiness(intent: &CreatorIntentRecord) -> CreatorInt
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_creator_intent_stage(has_user_input: bool, readiness: &CreatorIntentReadiness) -> &'static str {
|
||||
fn resolve_creator_intent_stage(
|
||||
has_user_input: bool,
|
||||
readiness: &CreatorIntentReadiness,
|
||||
) -> &'static str {
|
||||
if readiness.is_ready {
|
||||
"foundation_review"
|
||||
} else if has_user_input {
|
||||
@@ -1509,11 +1530,16 @@ fn detect_user_input_signal(chat_history: &[JsonValue]) -> PromptUserInputSignal
|
||||
if latest_user_text.is_empty() {
|
||||
return PromptUserInputSignal::Sparse;
|
||||
}
|
||||
if contains_any(&latest_user_text, &["不是", "改成", "改为", "换成", "重来", "推翻", "修正"])
|
||||
{
|
||||
if contains_any(
|
||||
&latest_user_text,
|
||||
&["不是", "改成", "改为", "换成", "重来", "推翻", "修正"],
|
||||
) {
|
||||
return PromptUserInputSignal::Correction;
|
||||
}
|
||||
if contains_any(&latest_user_text, &["你帮我想", "你来定", "你决定", "你补完"]) {
|
||||
if contains_any(
|
||||
&latest_user_text,
|
||||
&["你帮我想", "你来定", "你决定", "你补完"],
|
||||
) {
|
||||
return PromptUserInputSignal::Delegate;
|
||||
}
|
||||
let segments = split_sentences(&latest_user_text);
|
||||
@@ -1535,8 +1561,14 @@ fn detect_drift_risk(
|
||||
let recent_user_messages = chat_history
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
(entry.get("role").and_then(JsonValue::as_str) == Some("user"))
|
||||
.then(|| entry.get("content").and_then(JsonValue::as_str).unwrap_or("").trim().to_string())
|
||||
(entry.get("role").and_then(JsonValue::as_str) == Some("user")).then(|| {
|
||||
entry
|
||||
.get("content")
|
||||
.and_then(JsonValue::as_str)
|
||||
.unwrap_or("")
|
||||
.trim()
|
||||
.to_string()
|
||||
})
|
||||
})
|
||||
.filter(|value| !value.is_empty())
|
||||
.rev()
|
||||
@@ -1545,11 +1577,19 @@ fn detect_drift_risk(
|
||||
|
||||
let correction_count = recent_user_messages
|
||||
.iter()
|
||||
.filter(|entry| contains_any(entry, &["不是", "改成", "改为", "换成", "推翻", "重来", "修正"]))
|
||||
.filter(|entry| {
|
||||
contains_any(
|
||||
entry,
|
||||
&["不是", "改成", "改为", "换成", "推翻", "重来", "修正"],
|
||||
)
|
||||
})
|
||||
.count();
|
||||
if correction_count >= 2
|
||||
|| (progress_percent >= 65
|
||||
&& contains_any(&latest_user_text, &["不是", "改成", "改为", "换成", "重来", "推翻"]))
|
||||
&& contains_any(
|
||||
&latest_user_text,
|
||||
&["不是", "改成", "改为", "换成", "重来", "推翻"],
|
||||
))
|
||||
{
|
||||
return PromptDriftRisk::High;
|
||||
}
|
||||
@@ -1652,7 +1692,8 @@ fn render_dynamic_state_context(dynamic_state: &PromptDynamicState) -> String {
|
||||
fn render_current_anchor_context(anchor_content: &EightAnchorContent) -> String {
|
||||
format!(
|
||||
"当前完整设定结构如下。\n你必须把它视为上一版有效世界底子。\n\n如果用户没有否定其中某部分内容,且该部分仍然成立,可以继续保留。\n如果用户明确修正了某部分内容,新的完整设定结构必须体现修正后的版本。\n\n当前完整设定结构:\n{}",
|
||||
serde_json::to_string_pretty(anchor_content).unwrap_or_else(|_| empty_agent_anchor_content_json())
|
||||
serde_json::to_string_pretty(anchor_content)
|
||||
.unwrap_or_else(|_| empty_agent_anchor_content_json())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1757,7 +1798,8 @@ fn parse_conversation_mode(value: Option<&JsonValue>) -> Option<PromptConversati
|
||||
|
||||
fn mode_rules(mode: PromptConversationMode) -> &'static str {
|
||||
match mode {
|
||||
PromptConversationMode::Bootstrap => r#"当前模式:bootstrap
|
||||
PromptConversationMode::Bootstrap => {
|
||||
r#"当前模式:bootstrap
|
||||
|
||||
目标:
|
||||
1. 先把世界的基本方向抓住
|
||||
@@ -1777,8 +1819,10 @@ fn mode_rules(mode: PromptConversationMode) -> &'static str {
|
||||
1. 让用户觉得“现在很容易继续往下说”
|
||||
2. 不要制造被考试、被拷问、被策划问卷追着跑的感觉
|
||||
3. replyText 最好短、稳、可接话
|
||||
4. 如果用户信息很少,也不要显得冷淡或机械"#,
|
||||
PromptConversationMode::Expand => r#"当前模式:expand
|
||||
4. 如果用户信息很少,也不要显得冷淡或机械"#
|
||||
}
|
||||
PromptConversationMode::Expand => {
|
||||
r#"当前模式:expand
|
||||
|
||||
目标:
|
||||
1. 在保持现有方向的前提下,把设定结构逐步补全
|
||||
@@ -1797,8 +1841,10 @@ fn mode_rules(mode: PromptConversationMode) -> &'static str {
|
||||
1. 让用户感到“我刚说的内容都被接住了”
|
||||
2. 回复里可以带一点顺势整理感,但不要太像会议纪要
|
||||
3. 不要无视用户刚提供的高价值细节
|
||||
4. 不要让用户觉得系统在自顾自重写世界"#,
|
||||
PromptConversationMode::Compress => r#"当前模式:compress
|
||||
4. 不要让用户觉得系统在自顾自重写世界"#
|
||||
}
|
||||
PromptConversationMode::Compress => {
|
||||
r#"当前模式:compress
|
||||
|
||||
目标:
|
||||
1. 开始收束当前设定
|
||||
@@ -1818,8 +1864,10 @@ fn mode_rules(mode: PromptConversationMode) -> &'static str {
|
||||
1. 让用户感觉世界正在变得更稳,而不是越来越散
|
||||
2. 让推进感更明确,但不要显得催促
|
||||
3. 回复语气应更笃定一些,减少反复横跳
|
||||
4. 不要把用户刚补进来的细节又冲淡掉"#,
|
||||
PromptConversationMode::RepairDirection => r#"当前模式:repair_direction
|
||||
4. 不要把用户刚补进来的细节又冲淡掉"#
|
||||
}
|
||||
PromptConversationMode::RepairDirection => {
|
||||
r#"当前模式:repair_direction
|
||||
|
||||
目标:
|
||||
1. 处理用户对既有设定的修正
|
||||
@@ -1838,8 +1886,10 @@ fn mode_rules(mode: PromptConversationMode) -> &'static str {
|
||||
1. 让用户感到“我刚刚的纠偏真的生效了”
|
||||
2. 不要和用户辩论旧方案为什么也行
|
||||
3. 不要表现出对修正的不情愿
|
||||
4. 回复要体现重心已经切到新方向,而不是停留在旧世界观惯性里"#,
|
||||
PromptConversationMode::ForceComplete => r#"当前模式:force_complete
|
||||
4. 回复要体现重心已经切到新方向,而不是停留在旧世界观惯性里"#
|
||||
}
|
||||
PromptConversationMode::ForceComplete => {
|
||||
r#"当前模式:force_complete
|
||||
|
||||
目标:
|
||||
1. 基于当前方向直接补齐剩余设定
|
||||
@@ -1860,8 +1910,10 @@ fn mode_rules(mode: PromptConversationMode) -> &'static str {
|
||||
1. 让用户感到“系统已经帮我把能补的补好了”
|
||||
2. 不要在这一步突然冒出很多陌生设定把用户吓出戏
|
||||
3. 回复要有完成感,但不要太官话
|
||||
4. 清楚告诉用户下一步可以做什么"#,
|
||||
PromptConversationMode::Closing => r#"当前模式:closing
|
||||
4. 清楚告诉用户下一步可以做什么"#
|
||||
}
|
||||
PromptConversationMode::Closing => {
|
||||
r#"当前模式:closing
|
||||
|
||||
目标:
|
||||
1. 尽量形成一版可用的设定底子
|
||||
@@ -1880,26 +1932,37 @@ fn mode_rules(mode: PromptConversationMode) -> &'static str {
|
||||
1. 让用户感觉作品已经快成了,而不是还在无穷试探
|
||||
2. 回复可以更像确认和轻推,不要继续像前期那样频繁试探
|
||||
3. 保持留白感,不要把所有东西都一次说死
|
||||
4. 让用户自然过渡到下一阶段,而不是突然被切断对话"#,
|
||||
4. 让用户自然过渡到下一阶段,而不是突然被切断对话"#
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn user_signal_rules(signal: PromptUserInputSignal) -> &'static str {
|
||||
match signal {
|
||||
PromptUserInputSignal::Rich => r#"本轮用户输入信息密度高。
|
||||
PromptUserInputSignal::Rich => {
|
||||
r#"本轮用户输入信息密度高。
|
||||
请尽量从这一轮里提取多个锚点,不要只更新单一方向。
|
||||
如果一条输入同时影响世界方向、冲突和关系,请在新的完整设定结构中一起体现。"#,
|
||||
PromptUserInputSignal::Normal => r#"本轮用户输入为正常补充。
|
||||
请优先顺着当前方向稳定更新,不要主动扩写太多新设定。"#,
|
||||
PromptUserInputSignal::Sparse => r#"本轮用户输入较少或较虚。
|
||||
如果一条输入同时影响世界方向、冲突和关系,请在新的完整设定结构中一起体现。"#
|
||||
}
|
||||
PromptUserInputSignal::Normal => {
|
||||
r#"本轮用户输入为正常补充。
|
||||
请优先顺着当前方向稳定更新,不要主动扩写太多新设定。"#
|
||||
}
|
||||
PromptUserInputSignal::Sparse => {
|
||||
r#"本轮用户输入较少或较虚。
|
||||
请保留上一版中仍然成立的内容,不要为了凑完整度而强行发明过多新设定。
|
||||
replyText 要让用户容易继续往下说。"#,
|
||||
PromptUserInputSignal::Correction => r#"本轮用户在修正或推翻旧设定。
|
||||
replyText 要让用户容易继续往下说。"#
|
||||
}
|
||||
PromptUserInputSignal::Correction => {
|
||||
r#"本轮用户在修正或推翻旧设定。
|
||||
请优先吸收修正,不要机械复读旧版本。
|
||||
新的完整设定结构必须以修正后的方向为准。"#,
|
||||
PromptUserInputSignal::Delegate => r#"本轮用户把部分决定权交给你。
|
||||
新的完整设定结构必须以修正后的方向为准。"#
|
||||
}
|
||||
PromptUserInputSignal::Delegate => {
|
||||
r#"本轮用户把部分决定权交给你。
|
||||
你可以在 replyText 中给出有限度的建议,但不要突然补满整套设定。
|
||||
新的完整设定结构仍应尽量建立在已有世界方向上,而不是完全重做。"#,
|
||||
新的完整设定结构仍应尽量建立在已有世界方向上,而不是完全重做。"#
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1985,7 +2048,11 @@ fn clamp_text(value: &str, max_length: usize) -> String {
|
||||
if normalized.chars().count() <= max_length {
|
||||
return normalized;
|
||||
}
|
||||
normalized.chars().take(max_length.saturating_sub(1)).collect::<String>() + "…"
|
||||
normalized
|
||||
.chars()
|
||||
.take(max_length.saturating_sub(1))
|
||||
.collect::<String>()
|
||||
+ "…"
|
||||
}
|
||||
|
||||
fn clamp_progress_percent(value: Option<&JsonValue>) -> u32 {
|
||||
@@ -1996,7 +2063,8 @@ fn clamp_progress_percent(value: Option<&JsonValue>) -> u32 {
|
||||
}
|
||||
|
||||
fn to_text(value: Option<&JsonValue>) -> Option<String> {
|
||||
value.and_then(JsonValue::as_str)
|
||||
value
|
||||
.and_then(JsonValue::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(str::to_string)
|
||||
|
||||
Reference in New Issue
Block a user