回包失败留痕改为记录真实原因
- response_write_failed 改名为 response_delivery_failed,新增 ResponseDeliveryFailure 枚举 - 两个调用点分别传 Write(stdin 写入 / flush 失败)与 TurnBindMismatch(bind_turn 返回 false) - 日志键改为 agent.direct_codex.approval.response_delivery_failed 并带 cause 字段,回合绑定失败不再被误报成写入失败 - 同步更新 shared-memory 决策记录里的日志键口径
This commit is contained in:
@@ -291,6 +291,26 @@ fn accepted(id: u64, method: &str) -> Value {
|
||||
}
|
||||
}
|
||||
|
||||
/// app-server 交互回包未能送达的原因。
|
||||
///
|
||||
/// 两种失败共用同一条收束路径,但来源不同:写失败是 Codex 根本没收到 decision,回合绑定不一致
|
||||
/// 是回包已经产出、宿主无法确认执行作用域。留痕必须写真实原因,不能按函数名反推。
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(super) enum ResponseDeliveryFailure {
|
||||
/// stdin 写入 / flush 失败。
|
||||
Write,
|
||||
/// `bind_turn` 返回 false:回合绑定不一致。
|
||||
TurnBindMismatch,
|
||||
}
|
||||
impl ResponseDeliveryFailure {
|
||||
fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Write => "response-write-failed",
|
||||
Self::TurnBindMismatch => "turn-bind-mismatch",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecutionAdapter {
|
||||
pub(super) async fn for_turn(
|
||||
root: &Path,
|
||||
@@ -789,15 +809,16 @@ impl ExecutionAdapter {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub(super) fn response_write_failed(self: &Arc<Self>) {
|
||||
// 回包写不出去时 Codex 侧等不到 decision,表现为「审批没有回应」;与主动 decline 分开留痕。
|
||||
pub(super) fn response_delivery_failed(self: &Arc<Self>, cause: ResponseDeliveryFailure) {
|
||||
// 回包没送达 Codex 时线上表现为「审批没有回应」;与主动 decline 分开留痕。
|
||||
// 同一回合内同一原因只留一行:这一步可能被重复触发。
|
||||
self.log_once(
|
||||
"host-interaction\u{1}response-write-failed".to_string(),
|
||||
format!("host-interaction\u{1}response-delivery:{}", cause.as_str()),
|
||||
|_| {
|
||||
format!(
|
||||
"agent.direct_codex.approval.response_write_failed thread_id={}",
|
||||
self.thread_id
|
||||
"agent.direct_codex.approval.response_delivery_failed thread_id={} cause={}",
|
||||
self.thread_id,
|
||||
cause.as_str()
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ mod execution;
|
||||
mod model_catalog;
|
||||
pub(crate) use direct_project_identity::thread_id_for_project;
|
||||
use direct_project_identity::*;
|
||||
use execution::ExecutionAdapter;
|
||||
use execution::{ExecutionAdapter, ResponseDeliveryFailure};
|
||||
|
||||
const GAME_CREATOR_CODEX_APP_SERVER_PROVIDER_ID: &str = "genarrative_agc";
|
||||
const GAME_CREATOR_CODEX_APP_SERVER_API_KEY_ENV: &str = "GENARRATIVE_AGC_CODEX_API_KEY";
|
||||
@@ -4884,7 +4884,7 @@ async fn read_game_creator_codex_app_server_stdout(
|
||||
};
|
||||
if !sent {
|
||||
if let Some(adapter) = adapter {
|
||||
adapter.response_write_failed();
|
||||
adapter.response_delivery_failed(ResponseDeliveryFailure::Write);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -4916,7 +4916,9 @@ async fn read_game_creator_codex_app_server_stdout(
|
||||
let adapter = inner.execution.lock().ok().and_then(|slot| slot.clone());
|
||||
if let Some(adapter) = adapter {
|
||||
if !adapter.bind_turn(turn_id) {
|
||||
adapter.response_write_failed();
|
||||
adapter.response_delivery_failed(
|
||||
ResponseDeliveryFailure::TurnBindMismatch,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 2026-10-01 DirectProject 审批拒绝原因留痕
|
||||
|
||||
- 决策:宿主拒绝 app-server 的审批 / 交互请求时,原因必须落 AppData `RUST` 日志。稳定键 `agent.direct_codex.approval.denied`,字段为 `thread_id` / `method` / `reason` / `distinct_reasons`;未绑定宿主执行器时另记 `agent.direct_codex.interaction.no_adapter`(`method` / `outcome`,`outcome` 区分 `decline` / `empty-permissions` / `unsupported-method`),回包未送达另记 `agent.direct_codex.approval.response_write_failed`。
|
||||
- 决策:宿主拒绝 app-server 的审批 / 交互请求时,原因必须落 AppData `RUST` 日志。稳定键 `agent.direct_codex.approval.denied`,字段为 `thread_id` / `method` / `reason` / `distinct_reasons`;未绑定宿主执行器时另记 `agent.direct_codex.interaction.no_adapter`(`method` / `outcome`,`outcome` 区分 `decline` / `empty-permissions` / `unsupported-method`);回包未送达另记 `agent.direct_codex.approval.response_delivery_failed`,`cause` 区分 `response-write-failed` 与 `turn-bind-mismatch`。
|
||||
- 原因:线上对审批只回 `{"decision":"decline"}`,模型与用户都看不到是哪一道闸门(合同缺失 / 预算耗尽 / 阶段已收束 / item 不在途 / 无适配器)拦下的,只能靠复现。
|
||||
- 边界:`reason` 只接受 `execution.rs` 内的静态分类或宿主自己的错误文本,不带请求参数、上游正文、路径或凭据;有界去重一律按 `MAX_DENIED_REASON_LOGS = 64` 条封顶——适配器路径按回合内 `(method, reason)`、未绑定执行器路径按进程级 `(method, outcome)`、回包未送达按回合内原因各只记一次。
|
||||
- 影响范围:`apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/execution.rs`。
|
||||
|
||||
Reference in New Issue
Block a user