新增Agent Swarm纯聊天验证入口
新增无GUI终端REPL并接入真实External Runner与持久会话 支持全Agent状态事件、运行中steer、确认拒绝和恢复收束 新增agc:swarm短命令、配置门禁和Rust测试 记录真实Provider验证结果与现存父回执汇总缺口
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
"build": "npm --prefix ../.. exec tauri -- build",
|
||||
"llm-status": "node scripts/run-cli-with-config.mjs --llm-status",
|
||||
"agent-task": "node scripts/run-cli-with-config.mjs --agent-task",
|
||||
"swarm": "node scripts/run-cli-with-config.mjs --swarm-chat",
|
||||
"agent-run": "node scripts/run-cli-with-config.mjs --agent-run",
|
||||
"agent-run:smoke": "node scripts/smoke-agent-run-local-provider.mjs",
|
||||
"agent-runtime:real-e2e": "node scripts/agent-runtime-real-e2e.mjs",
|
||||
|
||||
@@ -383,6 +383,15 @@ if (
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
packageConfig.scripts?.swarm !==
|
||||
'node scripts/run-cli-with-config.mjs --swarm-chat'
|
||||
) {
|
||||
throw new Error(
|
||||
'AI game creator shell swarm must use client config before starting the interactive Agent runtime',
|
||||
);
|
||||
}
|
||||
|
||||
if (tauriConfig.productName !== 'Genarrative AI Game Creator') {
|
||||
throw new Error('AI game creator shell productName drifted');
|
||||
}
|
||||
@@ -713,6 +722,7 @@ for (const script of [
|
||||
'ai-game-creator-shell:dev-server',
|
||||
'ai-game-creator-shell:build',
|
||||
'ai-game-creator-shell:agent-task',
|
||||
'agc:swarm',
|
||||
'ai-game-creator-shell:typecheck',
|
||||
'ai-game-creator-shell:agent-run:smoke',
|
||||
'ai-game-creator-shell:check',
|
||||
@@ -722,6 +732,13 @@ for (const script of [
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
rootPackageConfig.scripts?.['agc:swarm'] !==
|
||||
'npm --prefix apps/ai-game-creator-shell run swarm --'
|
||||
) {
|
||||
throw new Error('root agc:swarm script must forward CLI args');
|
||||
}
|
||||
|
||||
if (
|
||||
rootPackageConfig.scripts?.['ai-game-creator-shell:build'] !==
|
||||
'npm --prefix apps/ai-game-creator-shell run build --'
|
||||
|
||||
@@ -14,6 +14,11 @@ pub(crate) enum CliCommand {
|
||||
task: String,
|
||||
initialize: bool,
|
||||
},
|
||||
SwarmChat {
|
||||
project_path: PathBuf,
|
||||
parent_agent_id: String,
|
||||
initialize: bool,
|
||||
},
|
||||
AgentEnqueue {
|
||||
project_path: PathBuf,
|
||||
agent_id: String,
|
||||
@@ -54,6 +59,7 @@ impl CliCommand {
|
||||
matches!(
|
||||
self,
|
||||
Self::AgentTask { .. }
|
||||
| Self::SwarmChat { .. }
|
||||
| Self::AgentEnqueue { .. }
|
||||
| Self::AgentConfirm { .. }
|
||||
| Self::AgentSteer { .. }
|
||||
@@ -72,6 +78,11 @@ impl CliCommand {
|
||||
initialize,
|
||||
..
|
||||
}
|
||||
| Self::SwarmChat {
|
||||
project_path,
|
||||
initialize,
|
||||
..
|
||||
}
|
||||
| Self::AgentEnqueue {
|
||||
project_path,
|
||||
initialize,
|
||||
@@ -356,6 +367,25 @@ pub(crate) fn parse_cli_command(args: &[String]) -> Result<Option<CliCommand>, S
|
||||
prompt: prompt.to_string(),
|
||||
}));
|
||||
}
|
||||
if args.first().map(String::as_str) == Some("--swarm-chat") {
|
||||
let mut rest = args[1..].to_vec();
|
||||
let initialize = if let Some(index) = rest.iter().position(|arg| arg == "--init") {
|
||||
rest.remove(index);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if rest.len() != 2 || rest.iter().any(|value| value.trim().is_empty()) {
|
||||
return Err(
|
||||
"用法:--swarm-chat [--init] <本地项目绝对路径> <parentAgentId>".to_string(),
|
||||
);
|
||||
}
|
||||
return Ok(Some(CliCommand::SwarmChat {
|
||||
project_path: PathBuf::from(&rest[0]),
|
||||
parent_agent_id: rest[1].trim().to_string(),
|
||||
initialize,
|
||||
}));
|
||||
}
|
||||
if args.first().map(String::as_str) == Some("--agent-task") {
|
||||
let mut rest = args[1..].to_vec();
|
||||
let initialize = if let Some(index) = rest.iter().position(|arg| arg == "--init") {
|
||||
@@ -534,6 +564,16 @@ pub(crate) fn run_cli_command(command: CliCommand) -> Result<(), String> {
|
||||
))
|
||||
}
|
||||
}
|
||||
CliCommand::SwarmChat {
|
||||
project_path,
|
||||
parent_agent_id,
|
||||
initialize,
|
||||
} => {
|
||||
let project_path = canonicalize_cli_path(&project_path, "本地项目路径", initialize)?;
|
||||
require_external_agent_runner_for_cli_runtime_write(&project_path)?;
|
||||
initialize_cli_agent_project(&project_path, initialize)?;
|
||||
run_game_creator_swarm_chat_at(&project_path, &parent_agent_id)
|
||||
}
|
||||
CliCommand::AgentEnqueue {
|
||||
project_path,
|
||||
agent_id,
|
||||
@@ -807,4 +847,42 @@ mod tests {
|
||||
.expect_err("agent steer must require config dir");
|
||||
assert!(error.contains("--config-dir"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_swarm_chat_and_requires_external_config_dir() {
|
||||
let project_path = std::env::current_dir().expect("current directory");
|
||||
let mut command = parse_cli_command(&[
|
||||
"--swarm-chat".to_string(),
|
||||
"--init".to_string(),
|
||||
project_path.display().to_string(),
|
||||
"code-prototype".to_string(),
|
||||
])
|
||||
.expect("parse swarm chat")
|
||||
.expect("swarm chat command");
|
||||
|
||||
assert_eq!(
|
||||
command,
|
||||
CliCommand::SwarmChat {
|
||||
project_path,
|
||||
parent_agent_id: "code-prototype".to_string(),
|
||||
initialize: true,
|
||||
}
|
||||
);
|
||||
assert!(command.requires_external_agent_runner());
|
||||
let error = prepare_cli_command_paths(&mut command, None)
|
||||
.expect_err("swarm chat must require config dir");
|
||||
assert!(error.contains("--config-dir"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swarm_chat_rejects_missing_or_extra_arguments() {
|
||||
assert!(parse_cli_command(&["--swarm-chat".to_string()]).is_err());
|
||||
assert!(parse_cli_command(&[
|
||||
"--swarm-chat".to_string(),
|
||||
"/tmp/game-project".to_string(),
|
||||
"code-prototype".to_string(),
|
||||
"extra".to_string(),
|
||||
])
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ mod process_session_bridge;
|
||||
mod project;
|
||||
mod repository_context;
|
||||
mod runner;
|
||||
mod swarm_cli;
|
||||
mod windows;
|
||||
|
||||
use agent::*;
|
||||
@@ -82,6 +83,7 @@ use process_session::*;
|
||||
use project::*;
|
||||
use repository_context::*;
|
||||
use runner::*;
|
||||
use swarm_cli::*;
|
||||
use windows::*;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize)]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
# Agent Swarm 纯聊天验证入口计划
|
||||
|
||||
更新时间:`2026-07-14`
|
||||
|
||||
## 目标
|
||||
|
||||
提供一版不依赖正常客户端 GUI 的终端聊天入口,让开发者选择一个父 Agent,通过真实 Agent Runtime 验证静态委派、动态隔离子 Agent、并行执行、确认动作、回执汇总和多轮持久化。
|
||||
|
||||
## 范围
|
||||
|
||||
- 新增 `--swarm-chat [--init] <本地项目绝对路径> <parentAgentId>`。
|
||||
- 新增短命令 `npm run agc:swarm -- --config-dir <项目外 AppData 绝对路径> [--init] <project> <parentAgentId>`。
|
||||
- 普通输入进入父 Agent background Runtime;不使用一次性 `--agent-chat`。
|
||||
- 复用 External Runner、active Session、现有 conversation、Agent 私有记忆、项目黑板、`agent.delegate`、`agent.spawn_isolated`、terminal receipt 和 all-join。
|
||||
- 展示全部 Agent 的状态、事件、父子身份和委派关系,并支持在终端批准或拒绝待确认动作。
|
||||
- 提供 `/help`、`/agents`、`/status`、`/history`、`/quit`。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不新增 Tauri 窗口、浏览器页面或本地 HTTP / SSE bridge。
|
||||
- 不新增 Provider 调用路径、Agent 数据库或 conversation 格式。
|
||||
- 不伪造 token streaming;首版展示 Runtime 状态 / 事件流和最终回复。
|
||||
- 不在终端退出时取消 Runner、run 或 Runner-owned process session。
|
||||
|
||||
## 实现步骤
|
||||
|
||||
1. 扩展 CLI command、参数解析和项目外 `--config-dir` 门禁。
|
||||
2. 新增独立终端 REPL 模块,复用项目初始化、Runtime resume、任务投递和 conversation 读取。
|
||||
3. 轮询全 Agent Runtime,按身份去重输出状态和事件;待确认时走现有 confirm / reject。
|
||||
4. 用“全 Runtime 非活跃 + 全队列为空 + 稳定观察窗口”判断一轮收束,再读取父 Agent 当前 Session 的新增 assistant 消息。
|
||||
5. 增加 npm 短命令、确定性测试、真实启动 smoke 和文档同步。
|
||||
|
||||
## 验收清单
|
||||
|
||||
- CLI parse、绝对路径、项目初始化、`--config-dir`、空输入、EOF 和 slash command。
|
||||
- 同一父 Agent 连续两轮使用同一 Session,退出重进后历史可见。
|
||||
- 两个静态 Agent 并行委派,多个动态 child 并行并形成唯一 all-join。
|
||||
- approve / reject 均能在终端完成,拒绝后父 Agent 能继续修正计划。
|
||||
- 父 Agent 暂时 idle、child 仍运行或 receipt 尚未认领时不提前结束。
|
||||
- Runner 或终端重启后恢复同一 run / session,不重放副作用。
|
||||
- 真实 Provider transcript 与 task / event / Agent DB / receipt / conversation 一致,最终父回复唯一且无密钥泄漏。
|
||||
|
||||
## 当前进度
|
||||
|
||||
- 已完成终端入口、短命令、Runtime 状态 / 事件输出、approve / reject、active Session 历史、same-run steer、活跃 `/quit`、启动 / 收束恢复扫描和 Runner 失联阻断。
|
||||
- 已用真实 `gpt-5.5` 观察到两个静态 Agent 并行、两条 child result、receipt 排队与重启恢复;终端确认、拒绝和活跃退出均生效。同一父 Session 连续 4 轮固定回复及 8 条消息历史恢复通过,最终双安静窗口收束返回 `FOURTH_OK`。
|
||||
- 未通过父 Agent 最终汇总:全量 `agent.run_status` 输出截断导致第一轮预算耗尽;第二轮 receipt continuation 未恢复原始只读目标并请求文件写入,已拒绝。
|
||||
- 待办:修复定向状态查询或 receipt continuation 目标恢复,复验唯一最终父回复;再补动态 isolated child 并行、唯一 all-join 和 Runner 强杀恢复。
|
||||
@@ -654,6 +654,20 @@ V1.14 对标 `codex fork`,允许开发者从任意已有静态 Agent 会话创
|
||||
|
||||
确定性验收必须覆盖 active / archived / legacy 源、空会话、消息与 messageId 精确复制、源与分叉后续隔离、provenance 持久化、运行中父任务和委派 child 阻断、非 active 源任务阻断、损坏 task journal 失败关闭、默认 Session Runtime 入队与分叉线性化、未提交分叉文件不可见、非法源 ID、catalog 写入失败清理以及重复点击创建不同 Session。前端测试必须证明按钮调用精确源 Session、成功后加载复制历史并切换 active、后续消息写入新 Session 且源会话不变、归档源可分叉、Runtime 忙时按钮禁用。
|
||||
|
||||
## V1.15 Agent Swarm 纯聊天验证入口
|
||||
|
||||
V1.15 新增不依赖 Tauri WebView 或正常客户端 GUI 的终端聊天入口,用于开发阶段直接验证多 Agent 协作。入口固定为 `--swarm-chat [--init] <本地项目绝对路径> <parentAgentId>`,推荐通过 `npm run agc:swarm -- --config-dir <项目外 AppData 绝对路径> [--init] <project> <parentAgentId>` 启动。它不是新的 Agent 实现:每条普通输入都投递给现有父 Agent background Runtime,继续由同一发布二进制的 External Runner 执行;不得退化到一次性 `--agent-chat`,也不得新建本地 HTTP 服务、旁路 Provider 客户端或第二套持久化。
|
||||
|
||||
- 首版复用父 Agent 当前 active Session;Runtime 继续把 user / assistant 写入 `.agent/conversations/agents/<agentId>/sessions/<sessionId>.jsonl`,静态委派、动态 `child-*`、私有记忆、项目黑板、durable action、verification gate 和 all-join 均沿用现有身份与恢复语义。`--init` 只复用现有项目初始化函数;Runtime 写命令仍强制显式传项目外 `--config-dir`。入口启动和一轮准备收束前都执行现有 resume / reconciliation 扫描,不能只凭 idle 快照跳过尚未发布的 receipt 或 join 修复。
|
||||
- 终端只提供聊天所需的轻量控制命令:`/help`、`/agents`、`/status`、`/history`、`/quit`。空闲时普通文本创建父 Agent 新 run;父 Agent run 仍处于 pending / running 时普通文本追加为同一 run steer,只有 child 忙而父 Agent 已终态时拒绝吞掉输入并要求稍后重发。确认动作在终端显示 Agent、run、action、tool 和安全摘要,并接受 `approve / reject`,分别调用现有 confirm / reject Runtime 路径,不能要求回到开发窗口。stdin 由独立读取线程投递,因此活跃 run 中 `/quit`、EOF、状态命令和 steer 仍可响应;退出只结束观察客户端。
|
||||
- 每轮轮询 `read_game_creator_agent_runtimes_at`,按 Agent / run / event 去重输出状态、phase、委派来源、父 Agent、delegationId、动态 child 和 join / receipt 事件。Provider token delta 当前没有经过 Runner RPC 暴露,首版只承诺 Runtime 状态与事件的持续输出以及持久化后的最终父 Agent 回复,禁止用拆字或延时打印伪装 token streaming。
|
||||
- 一轮只有在所有已发现 Runtime 都不处于 `pending / running / waiting-for-confirmation / cancelling / needs-reconciliation`,全部任务队列为空,并持续经过稳定观察窗口后才能收束。父 run 暂时 idle 但 delegated child 尚未终态、receipt 尚未入队或 all-join 尚未认领时不得提前返回。失败、取消和 reconciliation 要明确显示并保留项目现场,不自动重试副作用。
|
||||
- 终端退出只结束观察客户端,不终止 External Runner、已投递 run 或 Runner-owned process session;下次启动先调用现有 resume,再从 conversation 与 Runtime journal 恢复。首版只允许一个前台输入流,不承诺多个终端并发编辑同一 active Session。
|
||||
|
||||
确定性验收必须覆盖 CLI parse、项目绝对路径与 `--config-dir` 门禁、`--init`、空输入和 EOF、命令分流、历史恢复、连续两轮写入同一 Session、状态与事件去重、两个静态 Agent 并行委派、多个隔离 child 并行与唯一 all-join、confirm / reject、父 Agent receipt 汇总、稳定窗口不早退、Runner / 终端重启恢复以及失败与 reconciliation 显示。真实 Provider 验收必须保存一份脱敏 transcript,并以 task / event / Agent DB / receipt / conversation 的结构化事实证明并行、最终父回复唯一、副作用无重放和密钥零泄漏;未实际运行时只能标记未验收,不能凭确定性测试宣称 swarm 可用。
|
||||
|
||||
2026-07-14 首轮真实 `gpt-5.5` 验证已证明终端入口能够启动真实 External Runner、持久化父 Session、实时展示状态 / event / parent / delegation、并行运行 `design-foundation` 与 `balance-seed`,并在终端完成两次 `agent.delegate` approve、一次重复委派 reject、重启恢复、receipt 续跑、`file.write` reject 和活跃 run 中 `/quit`。独立收束复验在同一 `code-prototype` Session 连续完成 4 轮固定回复,重启后 `/history` 读取 8 条 user / assistant 消息,最后一轮按 `idle -> 安静窗口 -> receipt/join 恢复扫描 -> 安静窗口 -> 最终回复` 返回 `FOURTH_OK`。但端到端 swarm 汇总未通过:第一轮父 Agent 反复调用全量 `agent.run_status`,因输出截断无法看到目标 Agent,18 轮后 `budget-exhausted` 并压掉两条排队 receipt;第二轮按 receipt 模式续跑时,父 Agent 没有恢复原始“只读汇总”目标,转而读取项目并请求写 `game/balance.json`,已由终端拒绝。当前结论只能是“V1.15 验证入口可用、现有静态委派的父回执汇总策略未验收”,不得标记完整 Agent Swarm 通过;后续需修复定向状态查询或 receipt continuation 原目标恢复后再跑唯一最终父回复验收。动态 isolated child / all-join 也仍待通过该入口真实复验。
|
||||
|
||||
## 验收命令
|
||||
|
||||
- `npm run ai-game-creator-shell:typecheck`
|
||||
|
||||
@@ -46,6 +46,8 @@ V1.11 的受保护仓库控制目录同时包含 `.git / .agent / .agents / .cod
|
||||
|
||||
2026-07-14 起,同一文档的“V1.14 Agent 会话分叉”补齐 `codex fork` 风格的开发会话分支。开发 Agent 窗口可从 active、archived 或 legacy Session 复制截至当前的持久 conversation,创建带来源记录的新 active Session;源会话不变,后续消息与 run 按新 Session 隔离。分叉不复制 Runtime / pending action / process session,不推进项目 revision,并在当前 Agent 或委派 child 未终态时拒绝执行;Session 变更与 Runtime 入队共用 per-Agent lane gate,损坏任务日志失败关闭,catalog 提交前的分叉文件不会被列表暴露。
|
||||
|
||||
2026-07-14 起,同一文档的“V1.15 Agent Swarm 纯聊天验证入口”补充无 GUI 开发验收面。`npm run agc:swarm -- --config-dir <项目外AppData> [--init] <project> <parentAgentId>` 直接把每轮输入投递给真实父 Agent background Runtime,复用 External Runner、active Session、conversation、静态委派、动态隔离 child、私有记忆、项目黑板、确认策略和 all-join,不调用一次性 `--agent-chat`,不新建本地 HTTP 服务或平行数据库。终端持续显示全 Agent 状态、事件和父子 / 委派关系,提供 `/agents`、`/status`、`/history`、`/help`、`/quit` 以及 approve / reject;父 run 活跃时普通输入走 same-run steer,stdin channel 保证运行中仍可退出。入口启动和收束前执行恢复扫描,只有全 Runtime 非活跃、队列为空、恢复扫描无新增工作并通过稳定观察窗口后才输出绑定父 Session 的最后回复。首版没有 Runner Provider token delta,只承诺状态 / 事件实时输出和最终回复。真实 Provider 已证明入口、两个静态 Agent 并行、确认 / 拒绝、重启恢复和活跃退出,但父 Agent 的全量状态轮询与 receipt 原目标恢复仍导致汇总失败;当前不得宣称完整 swarm 已通过,动态 isolated child / all-join 也待复验。
|
||||
|
||||
2026-07-12 真实验收:发布 AppData 中的真实 `gpt-5.5` 已通过最终安全收紧后的 `llm-runtime` 套件,覆盖 Runner 强杀恢复且 run/session 身份稳定、仓库上下文、checkpoint/精确修改、失败命令诊断与修复复验、6 套确认生命周期、项目验证、桌面与移动非空画布证据、3 个隔离实例并行和唯一 all-join;95 条 task、161 条 event、137 条 Agent DB、13 条合法工具协议、副作用判重、终态投影、assistant audit、消息、回执和密钥泄露均以结构化落盘事实验收。`full` 套件仍要求 External Editor API 配置,缺失时必须返回 `BLOCKED(editorApi)`,不得记为通过。
|
||||
|
||||
2026-07-13 V1.3 真实验收:同一真实 Provider 套件已改为先读取 SHA-256,再用唯一一次 `project.patchset` 同时更新和创建文件,并使用自动 checkpointId 读取 2 项内容 hunks;prepared / completed 审计各 1 条、patchset revision 增量为 1,Runner 强杀恢复、命令和项目验证、双视口浏览器验证、隔离 Agent join、重复副作用与密钥扫描继续全部通过。
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
"ai-game-creator-shell:build": "npm --prefix apps/ai-game-creator-shell run build --",
|
||||
"ai-game-creator-shell:llm-status": "npm --prefix apps/ai-game-creator-shell run llm-status --",
|
||||
"ai-game-creator-shell:agent-task": "npm --prefix apps/ai-game-creator-shell run agent-task --",
|
||||
"agc:swarm": "npm --prefix apps/ai-game-creator-shell run swarm --",
|
||||
"ai-game-creator-shell:agent-run": "npm --prefix apps/ai-game-creator-shell run agent-run --",
|
||||
"ai-game-creator-shell:agent-run:smoke": "npm --prefix apps/ai-game-creator-shell run agent-run:smoke",
|
||||
"ai-game-creator-shell:agent-runtime:real-e2e": "npm --prefix apps/ai-game-creator-shell run agent-runtime:real-e2e --",
|
||||
|
||||
Reference in New Issue
Block a user