修复 Codex app-server 鉴权错误分类
- 识别 401/403 上游鉴权失败并归类为 unauthorized - 增加错误分类回归测试并保持敏感诊断脱敏 - 更新 UI 工作流 Runtime 鉴权失败门禁说明
This commit is contained in:
@@ -244,12 +244,46 @@ fn game_creator_codex_app_server_connection_error(
|
||||
}
|
||||
}
|
||||
|
||||
fn game_creator_codex_app_server_error_detail_indicates_auth_failure(
|
||||
error: &serde_json::Value,
|
||||
) -> bool {
|
||||
let Some(error) = error.as_object() else {
|
||||
return false;
|
||||
};
|
||||
let detail = ["message", "additionalDetails"]
|
||||
.into_iter()
|
||||
.filter_map(|field| error.get(field).and_then(serde_json::Value::as_str))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
.to_ascii_lowercase();
|
||||
if detail.is_empty() {
|
||||
return false;
|
||||
}
|
||||
detail.contains("invalid token")
|
||||
|| detail.contains("invalid_api_key")
|
||||
|| detail.contains("invalid api key")
|
||||
|| detail.contains("401 unauthorized")
|
||||
|| detail.contains("403 forbidden")
|
||||
|| detail.contains("status 401")
|
||||
|| detail.contains("status 403")
|
||||
|| detail.contains("http 401")
|
||||
|| detail.contains("http 403")
|
||||
}
|
||||
|
||||
fn game_creator_codex_app_server_failed_turn_error(
|
||||
turn: &serde_json::Value,
|
||||
) -> platform_llm::LlmError {
|
||||
let Some(info) = turn
|
||||
let Some(error) = turn
|
||||
.get("error")
|
||||
.and_then(|error| error.get("codexErrorInfo"))
|
||||
.filter(|error| !error.is_null())
|
||||
else {
|
||||
return game_creator_codex_app_server_error_kind("other");
|
||||
};
|
||||
if game_creator_codex_app_server_error_detail_indicates_auth_failure(error) {
|
||||
return game_creator_codex_app_server_error_kind("unauthorized");
|
||||
}
|
||||
let Some(info) = error
|
||||
.get("codexErrorInfo")
|
||||
.filter(|info| !info.is_null())
|
||||
else {
|
||||
return game_creator_codex_app_server_error_kind("other");
|
||||
@@ -3593,6 +3627,30 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codex_app_server_failed_turn_maps_upstream_auth_details_to_unauthorized() {
|
||||
for detail in [
|
||||
"unexpected status 401 Unauthorized: Invalid token",
|
||||
"HTTP 403 Forbidden",
|
||||
"invalid_api_key",
|
||||
] {
|
||||
let error = game_creator_codex_app_server_failed_turn_error(&serde_json::json!({
|
||||
"status": "failed",
|
||||
"error": {
|
||||
"message": detail,
|
||||
"additionalDetails": "private upstream diagnostics",
|
||||
"codexErrorInfo": "other"
|
||||
}
|
||||
}));
|
||||
assert_eq!(
|
||||
error,
|
||||
platform_llm::LlmError::InvalidRequest(
|
||||
"codex-app-server-error:unauthorized".to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codex_app_server_rejects_non_responses_key_mapping() {
|
||||
let mut llm = test_llm();
|
||||
|
||||
@@ -55,6 +55,8 @@ ui-workflow.completed
|
||||
|
||||
`recognize` 现在直接复用 UI Editor 的 provider-backed `recognize_ui_impl`、`merge_ui_impl` 与 `bind_components_impl`:先对页面设计图执行多模态结构识别,再落盘合并后的唯一页面树,最后按 5 项一批绑定已登记图片/图标,并向模型提供 State 内已验证字体的 ID、family、face、weight 与 style。由 Agent Runtime 调用时,这三个阶段携带当前 `agent_id/run_id`,统一走活动 Provider 的 mode、请求快照、重试和恢复链路,不再从工作流偷偷创建另一套传统 HTTP client。Codex app-server 会把输入图片暂存到该连接的隔离工作区 `input-images/`,通过原生 `localImage` 输入发送;文本提示只保留图片占位符,避免把 base64 复制进提示词或 JSON-RPC。所有 LLM 工具参数仍沿用 UI Editor 的严格 schema、节点/深度/素材和字体白名单及有界输入校验。Provider 未配置、请求失败、工具调用缺失、结果不匹配、未知字体引用、绑定没有可渲染组件或仍有 `NeedReview/Blocked` 时,完成阶段不会推进;已落盘的中间阶段仍通过 manifest invalidation 更新客户端,不再使用 deterministic seed 冒充语义处理通过。
|
||||
|
||||
真实 Provider 鉴权失败时,Codex app-server 可能只返回 `codexErrorInfo=other`,而把上游 `401/403` 放在错误正文中。Runtime 必须从受控错误字段识别为 `codex-app-server-error:unauthorized`(公共摘要为 `codex-app-server-unauthorized`),只向公共运行记录暴露错误类别和指纹,不记录 Token 或上游原文。此错误不能伪造为 UI 工作流阶段完成;修复凭据后应从原有 run 的恢复边界重新执行。
|
||||
|
||||
## 画布跳转与客户端更新
|
||||
|
||||
点击画布中的 `ui-prototype` 时,工作台调用 `ensure_ui_design_resource_for_prototype`:
|
||||
|
||||
Reference in New Issue
Block a user