修复AGC模型请求与对话登录态自动续期 (#329)
Project CI / Repository checks (push) Successful in 2m40s
Project CI / Frontend tests (push) Successful in 3m23s
Project CI / Backend tests (push) Successful in 5m46s
Project CI / Native shell tests (push) Successful in 18m30s

## 变更说明

- AGC 客户端配套后端 API 在 401 时自动刷新登录态并重试一次,覆盖模型目录请求。
- DirectProject 对话鉴权失效时刷新平台会话、同步 Rust/Runner 凭据并重试同一 clientTurnId。
- 403 权限拒绝不触发续期;账号切换后不重发旧请求。
- 补充并发续期、失败保留原错误、权限边界和 Direct 对话重试测试。

## 验证

- npm run test -- apps/ai-game-creator-shell/tests/appSurface.test.ts apps/ai-game-creator-shell/tests/clientApi.test.ts apps/ai-game-creator-shell/tests/clientHttp.test.ts apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx
- npm run agc:typecheck
- npm run check:encoding
- git diff --check

Reviewed-on: #329
Co-authored-by: kdletters <kdletters@qq.com>
Co-committed-by: kdletters <kdletters@qq.com>
This commit was merged in pull request #329.
This commit is contained in:
2026-09-11 18:09:48 +08:00
committed by 段舒康
parent 11c8cbdf67
commit fafe6b63cd
5 changed files with 240 additions and 20 deletions
@@ -1350,3 +1350,8 @@ DirectProject 使用 `approvalPolicy=never`,避免每次原生调用再经过
- 等待预算耗尽时按 `project.write_lock.wait_exhausted` 记录 `commandId`、尝试次数、等待毫秒数、`projection=`contention / permission_denied)与持锁方身份,Unix 上明确判定的权限拒绝按 `project.write_lock.permission_denied` 记录;争用不在零等待入口里逐次记账,避免有界等待的上千次重试淹没日志。这条日志正是 Issue #318 现场缺的“谁在持锁、是不是自己人”。**这条日志与终态改判都只在真的等过(`max_attempts > 1`)时发生**:单次试探(hydrate 的 `try_acquire_*`)不写 `wait_exhausted``waitedMs≈0` 会让“耗尽”失去意义,而 hydrate 每次状态变化都会撞一次锁,写成日志就是噪声),也不做终态改判。
- 定向验收覆盖:同进程重叠写等待后成功、同一轮并行写多个文件、有界等待不占 runtime worker`current_thread` + 心跳任务)、活外部进程持锁(错误带 `ownerIsSelf=false` 且锁文件不被回收)、ACL 拒绝不投影成争用,外加两条平台无关判据用例(重试性只由错误码决定、终态改判三条件)——后两条让 Linux CI 也能盯住 Windows 分支。对应 `project_lock_recovery``direct_tool_bridge``project/write_lock` 定向测试;`tests/project_tools.rs` 既有的 `runtime_project_write_lock_waits_for_delete_pending_target` 继续覆盖“带句柄的 delete-pending 必须等到成功”。
- 仍待收口(后续事项):① 其余仍用零等待取锁的入口(`command.exec / project.verify / memory / conversation / task / checkpoint / 预览 / UI 编辑器 / 资源编辑器 / Tauri 命令`)本批不改,遇到同类争用仍会立刻失败;零等待入口无法区分“拆链窗口 / ACL 拒绝”,因此在前缀不变的前提下补一句“锁文件此刻不存在,可能是删除挂起、删除拆链窗口或权限 / ACL 拒绝”。② 锁策略已按“单一职责”收口到 `project/write_lock.rs`(887 行:取锁、等待分类、持锁方诊断、残留回收),`project/filesystem.rs` 回到项目文件 IO(680 行);仍待收口的是 Direct 锁用例,它们还留在 `direct_tool_bridge.rs`(3135 行,锁用例与桥实现混在一起),后续移到 `tests/project_lock_recovery.rs` 或独立测试文件。③ 行为级 Windows 用例(delete-pending 等)仍只在 Windows 本地执行,CI 没有 Windows runner;关键判据已参数化到 Linux 可覆盖,行为级覆盖仍需本地执行或后续补 runner。
## 2026-09-11 AGC 登录态自动续期
- AGC 前端请求客户端配套后端的鉴权 API(包括 `/api/llm/models`)收到 `401` 时,共享进行中的 refresh 请求;确认当前用户并安装 Rust / Runner 会话后,用新 access token 最多重试原请求一次。`403` 权限拒绝不触发续期;续期失败保留原鉴权错误,账号切换或登出后不重发旧请求。
- DirectProject 的 Rust/app-server 对话调用返回鉴权失效时,前端先刷新客户端平台会话并重新提交同一 `clientTurnId`;平台会话代次变化后由 app-server pool 使用新 access token 建立连接,避免长时间运行后必须重新登录。