继续收敛 Direct 交付终态读取错误

保留交付状态快照读取与锁失败的具体正文

合并原始回合错误与终态读取错误

补充交付复核回归验证记录
This commit is contained in:
kdletters
2026-10-06 01:10:23 +08:00
parent 8fa5cc10ee
commit 1ce8625585
4 changed files with 70 additions and 33 deletions
@@ -1056,9 +1056,13 @@ impl ExecutionAdapter {
}
fn report(&self) -> String {
direct_delivery::terminal_report(&self.session).unwrap_or_else(|| {
"本轮执行已停止,宿主尚未确认交付完成;请核对保留的证据与未完成项。".into()
})
match direct_delivery::terminal_report(&self.session) {
Ok(Some(report)) => report,
Ok(None) => "本轮执行已停止,宿主尚未确认交付完成;请核对保留的证据与未完成项。".into(),
Err(error) => format!(
"本轮执行已停止,读取宿主交付状态失败:{error};请核对保留的证据与未完成项。"
),
}
}
async fn drain(&self) {
@@ -644,8 +644,8 @@ fn assess(root: &Path, ledger: &ExecutionLedger) -> Result<Assessment, String> {
})
}
pub(super) fn terminal_report(session: &Arc<ExecutionSession>) -> Option<String> {
session.snapshot().ok()?.terminal_report
pub(super) fn terminal_report(session: &Arc<ExecutionSession>) -> Result<Option<String>, String> {
session.snapshot().map(|snapshot| snapshot.terminal_report)
}
pub(super) async fn status(root: &Path, session: &Arc<ExecutionSession>) -> Result<Value, String> {
@@ -710,7 +710,13 @@ pub(super) async fn review_reply(
root: &Path,
session: &Arc<ExecutionSession>,
) -> Result<Option<String>, TurnError> {
if let Some(report) = terminal_report(session) {
let existing_report = terminal_report(session).map_err(|error| {
TurnError::turn_failed(
FailureStage::CodeGeneration,
format!("读取交付终态失败:{error}"),
)
})?;
if let Some(report) = existing_report {
return Ok(Some(report));
}
let ledger = session.snapshot()?;
@@ -721,7 +727,13 @@ pub(super) async fn review_reply(
if let Some(report) = finish_sealing(root, session).await? {
return Ok(Some(report));
}
if let Some(report) = terminal_report(session) {
let terminal_report = terminal_report(session).map_err(|error| {
TurnError::turn_failed(
FailureStage::CodeGeneration,
format!("读取交付终态失败:{error}"),
)
})?;
if let Some(report) = terminal_report {
return Ok(Some(report));
}
}
@@ -4528,7 +4528,9 @@ async fn run_direct_game_creator_turn_inner(
direct_turn_trace("run-analytics-accepted");
// 在 guard 仍存活时冻结整体结果,避免 Drop 的中断收尾覆盖真实失败原因。
let result: Result<String, TurnError> = async {
if let Some(report) = super::direct_delivery::terminal_report(&execution_session) {
let terminal_report = super::direct_delivery::terminal_report(&execution_session)
.map_err(|error| TurnError::turn_failed(FailureStage::CodeGeneration, format!("读取交付终态失败:{error}")))?;
if let Some(report) = terminal_report {
return Ok(report);
}
// CLI 没有结构化条目;在进入反馈循环前固定原始消息,避免后续反馈以同一 ID
@@ -4670,20 +4672,28 @@ async fn run_direct_game_creator_turn_inner(
}
// 交付报告的兜底只读一次:guard 与取值各调一次会在两次之间换出不同结果,
// 第二次拿到 `None` 时还会把空串当成回复返回。
Err(error) => match super::direct_delivery::terminal_report(&execution_session)
{
Some(report) => break Ok(report),
None if attempt < DIRECT_CODEX_ERROR_FEEDBACK_MAX_ATTEMPTS
&& error.is_model_repairable() =>
{
let detail =
truncate_agent_runtime_text(&error.diagnostic_detail(), 1800);
emitter.emit("running", Some("error-feedback"));
attempt += 1;
feedback_prompt = direct_codex_error_feedback_prompt(&detail);
Err(error) => {
let original_detail = error.diagnostic_detail();
match super::direct_delivery::terminal_report(&execution_session) {
Ok(Some(report)) => break Ok(report),
Ok(None) if attempt < DIRECT_CODEX_ERROR_FEEDBACK_MAX_ATTEMPTS
&& error.is_model_repairable() =>
{
let detail =
truncate_agent_runtime_text(&original_detail, 1800);
emitter.emit("running", Some("error-feedback"));
attempt += 1;
feedback_prompt = direct_codex_error_feedback_prompt(&detail);
}
Ok(None) => break Err(error),
Err(report_error) => break Err(TurnError::turn_failed(
FailureStage::CodeGeneration,
format!(
"读取交付终态失败:{report_error};原始回合失败:{original_detail}"
),
)),
}
None => break Err(error),
},
}
}
};
drop(observer);
@@ -4732,19 +4742,29 @@ async fn run_direct_game_creator_turn_inner(
}
// 同上:交付报告只读一次,避免两次调用之间换出不同结果(第二次拿到 `None`
// 时还会绕过下面那条"未返回结果"的兜底错误)。
Err(error) => match super::direct_delivery::terminal_report(&execution_session)
{
Some(report) => break Some(report),
None if attempt < DIRECT_CODEX_ERROR_FEEDBACK_MAX_ATTEMPTS
&& error.is_model_repairable() =>
{
let detail =
truncate_agent_runtime_text(&error.diagnostic_detail(), 1800);
attempt += 1;
feedback_prompt = direct_codex_error_feedback_prompt(&detail);
Err(error) => {
let original_detail = error.diagnostic_detail();
match super::direct_delivery::terminal_report(&execution_session) {
Ok(Some(report)) => break Some(report),
Ok(None) if attempt < DIRECT_CODEX_ERROR_FEEDBACK_MAX_ATTEMPTS
&& error.is_model_repairable() =>
{
let detail =
truncate_agent_runtime_text(&original_detail, 1800);
attempt += 1;
feedback_prompt = direct_codex_error_feedback_prompt(&detail);
}
Ok(None) => return Err(error),
Err(report_error) => {
return Err(TurnError::turn_failed(
FailureStage::CodeGeneration,
format!(
"读取交付终态失败:{report_error};原始回合失败:{original_detail}"
),
))
}
}
None => return Err(error),
},
}
}
};
response.ok_or_else(|| {
@@ -88,3 +88,4 @@ DirectProject 回合失败在确认不是客户端内部不可归类故障时,
- Direct 补丁事务的目标指纹读取原先把元数据、打开、正文读取和文件超限都折叠为 `None`,可能误判文件缺失或继续比较;现只对确实 `NotFound` 保留 `missing`,其余失败返回目标相对路径、阶段和底层正文,避免补丁结果被错误归因。
- CC/Direct 工具桥的执行前后成果指纹、回执结算 JoinError/落盘失败,以及外部 MCP journal 的读取/JSON 行解析原先仍会被 `.ok()`、固定回执句或“无记录”吞掉;现分别保留指纹阶段、回执任务/落盘原因、journal 行号和底层正文,只有真实 `NotFound` 才视为空记录。
- 外部 MCP `resources/read` 仍把已能返回具体原因的 Codex journal 读取错误 `unwrap_or_default()` 成空资源;现把读取失败按 MCP 错误响应返回,Direct 执行会话当前项目 canonicalize 也保留底层 I/O 正文。
- Direct 交付终态读取原先把 `session.snapshot()` 锁/状态错误折叠成 `None`,上层继续显示“尚未确认交付完成”;现沿 `code-generation` 失败出口保留终态读取正文,并在已有回合失败时同时保留原始失败与终态读取失败。