修复运行时恢复路径栈溢出
为 pending continuation 与后台主循环增加可取消的 Tokio 任务边界 保留 durable batch 恢复防重和父任务取消语义 补充运行时技术约束与共享排障记录
This commit is contained in:
@@ -1,5 +1,37 @@
|
||||
use super::*;
|
||||
|
||||
async fn run_game_creator_agent_background_task_after_pending_stack_boundary(
|
||||
root: PathBuf,
|
||||
agent_id: String,
|
||||
task: String,
|
||||
runtime: AgentRuntimeState,
|
||||
continuation: AgentRuntimeContinuationContext,
|
||||
) -> AgentBackgroundTaskOutcome {
|
||||
// Debug builds give both pending execution and the background main loop large poll frames.
|
||||
// A joined child task prevents those frames from sharing one Tokio worker stack while
|
||||
// JoinSet still aborts the child if its parent continuation is dropped.
|
||||
let mut tasks = tokio::task::JoinSet::new();
|
||||
tasks.spawn(async move {
|
||||
run_game_creator_agent_background_task_with_context(
|
||||
root,
|
||||
agent_id,
|
||||
task,
|
||||
runtime,
|
||||
continuation,
|
||||
)
|
||||
.await
|
||||
});
|
||||
match tasks
|
||||
.join_next()
|
||||
.await
|
||||
.expect("pending continuation task must exist")
|
||||
{
|
||||
Ok(outcome) => outcome,
|
||||
Err(error) if error.is_panic() => std::panic::resume_unwind(error.into_panic()),
|
||||
Err(error) => panic!("pending continuation task was cancelled: {error}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn continue_game_creator_agent_pending_tool_action(
|
||||
root: PathBuf,
|
||||
agent_id: String,
|
||||
@@ -61,7 +93,7 @@ pub(crate) async fn continue_game_creator_agent_pending_tool_action(
|
||||
usize::try_from(batch.loop_iteration.saturating_sub(1)).unwrap_or(usize::MAX);
|
||||
continuation.context_stalled = false;
|
||||
continuation.applied_steer_cursor = batch.planned_steer_cursor;
|
||||
let outcome = run_game_creator_agent_background_task_with_context(
|
||||
let outcome = run_game_creator_agent_background_task_after_pending_stack_boundary(
|
||||
root.clone(),
|
||||
agent_id.clone(),
|
||||
pending.task.clone(),
|
||||
@@ -787,7 +819,7 @@ pub(crate) async fn continue_game_creator_agent_pending_tool_action(
|
||||
return;
|
||||
}
|
||||
}
|
||||
let outcome = run_game_creator_agent_background_task_with_context(
|
||||
let outcome = run_game_creator_agent_background_task_after_pending_stack_boundary(
|
||||
root.clone(),
|
||||
agent_id.clone(),
|
||||
pending.task.clone(),
|
||||
|
||||
@@ -3986,6 +3986,14 @@
|
||||
- 处理:先以 CAS 单独 commit `queued -> executing`,成功后才调 ToolHost;调用返回后再 commit observation。恢复见到 executing 或 ToolHost 返回 Unknown 时只能进入 reconciliation,不得自动重执行。重复 resume 不得继续增 revision 或重复 event。
|
||||
- 验证:在“ToolHost 已调用、observation commit 失败”处注入故障,序列化快照并用新 engine 重载;断言重复 resume 后 ToolHost 计数仍为 1,且只有显式 reconcile observation 才恢复 running。
|
||||
|
||||
## 大型 async 状态机不能在同一 Tokio poll 调用栈连续嵌套(2026-08-03)
|
||||
|
||||
- 现象:Supervisor collaboration durable isolated spawn 恢复测试在默认 Tokio worker 栈下稳定 `stack overflow`;单独运行同样失败,提高 `RUST_MIN_STACK` 后通过。
|
||||
- 原因:不是业务递归。debug 构建中 pending action continuation、后台 task queue 和 Agent 主循环各自形成大型 async poll frame;恢复路径在同一次 poll 调用链直接进入下一层状态机,累计超过 worker 默认栈。
|
||||
- 处理:在 pending continuation 与后台主循环之间建立独立 Tokio task 轮询边界,使 pending poll 先退栈后再轮询主循环。边界必须保留结构化取消语义;当前使用 `JoinSet`,父 continuation 被丢弃时同步 abort 子任务。不得只增大 CI 的 `RUST_MIN_STACK`,否则生产默认栈仍可能崩溃。
|
||||
- 验证:失败用例必须在未设置 `RUST_MIN_STACK` 时通过;同时覆盖 policy batch 全组和 pending/cancellation 回归,证明恢复不重复生成 isolated spawn、父任务取消不遗留后台子任务。
|
||||
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/pending_execution.rs`。
|
||||
|
||||
## Provider 可扩展不能用一个全局 protocol 枚举代替实例隔离
|
||||
|
||||
- 现象:把 `openai_chat / openai_responses / anthropic` 直接当 Provider 身份,注册第二个同协议 endpoint 时发生 ID 冲突;或为方便调用把 API Key、base URL、raw-log 目录放进全局状态,并行请求后日志串目录。
|
||||
|
||||
@@ -756,6 +756,7 @@ game-project/
|
||||
- 开发模式可通过本地项目文件面板执行 `file.list/read/write/delete`,普通用户界面不暴露文件面板。
|
||||
- 2026-07-17 起,同一 Runtime 文档的“V1.32 Runtime 强制 Supervisor 协作合同”作为 mixed swarm 可靠性事实源。项目可用 `.agent/collaboration-policy.json` 约束首波 static/isolated 模式、数量和 required static Agent;Runtime 在任何 child 副作用前整批校验并把合同指纹固化进 Provider batch v2。当前父 run 一旦形成 delivery/group,正式 `project-supervisor` 默认只负责编排、状态认领和验证,不再直接执行项目 mutation;专业 Agent/isolated child 权限与唯一 Supervisor 最终回复边界保持不变。
|
||||
- 2026-07-17 V1.32 最终代码已完成独立真实 Provider PASS:首批 mixed batch、三 isolated child、Runner 强杀恢复、专业返工、宿主验证、唯一最终回复与零重复/残留/泄漏同时成立。真实报告计数、隔离重试配置和仍待收敛的 tool-plan repair 成本统一以 Runtime 文档 V1.32 章节与共享决策记录为准。
|
||||
- 2026-08-03 恢复执行补充约束:pending action continuation 进入后台主循环时必须先跨越独立 Tokio task 轮询边界,不能让 pending executor、task queue 与 Agent 主循环的大型 async poll frame 在同一 worker 调用栈连续嵌套。边界必须随父 continuation 取消子任务并保持 durable action、batch、run/session 身份及恢复防重语义;当前使用 `JoinSet` 承担结构化取消。CI 和生产均使用默认 worker 栈验证,不以提高 `RUST_MIN_STACK` 代替代码边界。
|
||||
- 2026-07-18 起,同一 Runtime 文档的“V1.34 动态隔离子 Agent writeScopes 命令绕过封堵”作为 isolated child 的现行能力事实源。在 scope-aware OS sandbox 完成前,动态 child 无条件禁用 `project.verify / project.git_commit / command.exec / command.start / command.stdin / preview.start / agent.delegate / agent.spawn_isolated / project.restore / agent.schedule_ready / canvas.asset_generate / task.create / task.update / blackboard.write` 和全部 MCP;原生工具策略统一显示 `denied`,模板、项目 policy 与用户确认均不能放宽。保留固定只读 `command.run_limited`、同身份 `command.output_read / command.poll / command.terminate`、既有预览的 `preview.validate`,以及严格位于 `writeScopes` 内的 `file.write / file.patch / file.delete / project.patchset`。
|
||||
- V1.34 的新单动作在 confirmation 和 OS launcher 前拒绝;新多 action 原生 batch 只要含一个 denied member 就在独立 pending-action sidecar、confirmation、OS spawn、revision 和任何成员项目副作用前整批 abort,只保留 `aborted / nextActionIndex=0` batch 事实。旧 pending / approval / batch 真正进入执行器时仍重新应用当前 child 边界,旧 executing 未知结果继续进入既有 reconciliation。该安全收紧由恶意 sibling 写入、策略快照、batch、旧 pending 执行器重验和 isolated/mixed/collaboration/provider-batch 回归证明;不因本切片重跑已通过且 isolated mutation 为 0 的 V1.31/V1.32 外部 Provider suite。通用命令只有在后续 scope-aware OS sandbox 对所有后代强制同一 `writeScopes` 并通过独立决策与测试后才可重新评估开放。
|
||||
- 2026-07-18 起,同一 Runtime 文档的“V1.35 多 ready isolated all-join 原子认领与恢复”作为 `agent.run_status` 同父 run 多 group 认领的现行事实源。Runtime 按 `delegationGroupId` 排序并一次性预取全部 join 锁;任一后续锁忙时保持零 delivery mutation、零 claim sidecar。全锁就绪后,同一 action 的 durable claim journal 按 `prepared -> committed -> observed` 推进;部分 commit 或 Runner 恢复只能复用该 journal 幂等补齐。只认领可完整放入优先 `readyIsolatedJoins` 观察预算的有序前缀,未观察旧 claim 可由后续 action 完整重放,但不创建第二份 isolated claim。每个 claimed delivery 必须由匹配原 action/group 的 journal 覆盖;无 journal 的旧 delivery 每轮只迁移一个原 action,已有 journal 不得扩写或状态倒退,跨 action group 归属冲突失败关闭。成功 observation 写入 pending sidecar 后只能把本轮完整输出的 claim 标记 `observed`,任一未观察或无 journal claim 继续阻断 finalization;每个 group 审计按 `actionId + delegationGroupId` 唯一,并在 Agent DB 锁内修复 torn tail、全量核对后幂等追加。
|
||||
|
||||
Reference in New Issue
Block a user