完成 DirectProject 扩展导入阶段三
接入客户端已启用 MCP 的隔离原生配置 保留 agc_tools 并隔离第三方 MCP 配置与启动失败 支持 STDIO 和 HTTP 标准字段及来源相对工作目录 将 MCP 集合纳入 app-server 连接池指纹 补充 Plugin MCP 样例、定向测试和现行文档
This commit is contained in:
@@ -621,6 +621,12 @@ fn game_creator_codex_app_server_pool_key(
|
||||
} else {
|
||||
"disabled".to_string()
|
||||
};
|
||||
let client_mcp_identity = if workspace_mode == CodexAppServerWorkspaceMode::DirectProject {
|
||||
crate::client_extensions::enabled_client_mcp_fingerprint()
|
||||
.unwrap_or_else(|_| "invalid-client-mcp".to_string())
|
||||
} else {
|
||||
"disabled".to_string()
|
||||
};
|
||||
let stable = serde_json::json!({
|
||||
"credentialFingerprint": credential_fingerprint,
|
||||
"baseUrl": llm.base_url,
|
||||
@@ -635,6 +641,7 @@ fn game_creator_codex_app_server_pool_key(
|
||||
"workspaceMode": workspace_mode.pool_identity(),
|
||||
"skillPackIdentity": skill_pack_identity,
|
||||
"clientSkillIdentity": client_skill_identity,
|
||||
"clientMcpIdentity": client_mcp_identity,
|
||||
"controlledWebSearch": llm.web_search_enabled,
|
||||
"directToolBridgeProtocol": if workspace_mode == CodexAppServerWorkspaceMode::DirectProject { DIRECT_TOOL_BRIDGE_PROTOCOL } else { "disabled" },
|
||||
"providerProxyProtocol": if workspace_mode == CodexAppServerWorkspaceMode::DirectProject { CODEX_PROVIDER_PROXY_PROTOCOL } else { "disabled" },
|
||||
@@ -1115,11 +1122,10 @@ fn configure_game_creator_codex_app_server_command_for_mode(
|
||||
let controlled_web_search =
|
||||
workspace_mode == CodexAppServerWorkspaceMode::DirectProject && llm.web_search_enabled;
|
||||
command.arg("app-server").arg("--stdio");
|
||||
command
|
||||
.arg("-c")
|
||||
.arg("mcp_servers={}")
|
||||
.arg("-c")
|
||||
.arg("web_search=\"disabled\"");
|
||||
if workspace_mode != CodexAppServerWorkspaceMode::DirectProject {
|
||||
command.arg("-c").arg("mcp_servers={}");
|
||||
}
|
||||
command.arg("-c").arg("web_search=\"disabled\"");
|
||||
if workspace_mode != CodexAppServerWorkspaceMode::DirectProject {
|
||||
command.arg("-c").arg("agents.enabled=false");
|
||||
}
|
||||
@@ -1313,14 +1319,37 @@ fn prepare_isolated_game_creator_codex_home(
|
||||
fn trust_isolated_game_creator_codex_workspace(
|
||||
codex_home: &std::path::Path,
|
||||
workspace: &std::path::Path,
|
||||
client_mcp_servers: &[crate::client_extensions::ClientMcpRuntimeServer],
|
||||
) -> Result<(), platform_llm::LlmError> {
|
||||
let workspace = workspace.to_string_lossy();
|
||||
let quoted_workspace = quoted_toml_string(&workspace)?;
|
||||
let config = format!("[projects.{quoted_workspace}]\ntrust_level = \"trusted\"\n");
|
||||
std::fs::write(codex_home.join("config.toml"), config).map_err(|error| {
|
||||
platform_llm::LlmError::Transport(format!(
|
||||
"写入隔离 Codex app-server 项目信任配置失败:{error}"
|
||||
let mut project = toml::map::Map::new();
|
||||
project.insert(
|
||||
"trust_level".to_string(),
|
||||
toml::Value::String("trusted".to_string()),
|
||||
);
|
||||
let mut projects = toml::map::Map::new();
|
||||
projects.insert(
|
||||
workspace.to_string_lossy().into_owned(),
|
||||
toml::Value::Table(project),
|
||||
);
|
||||
let mut root = toml::map::Map::new();
|
||||
root.insert("projects".to_string(), toml::Value::Table(projects));
|
||||
if !client_mcp_servers.is_empty() {
|
||||
let mut mcp_servers = toml::map::Map::new();
|
||||
for server in client_mcp_servers {
|
||||
mcp_servers.insert(
|
||||
server.name.clone(),
|
||||
toml::Value::Table(server.config.clone().into_iter().collect()),
|
||||
);
|
||||
}
|
||||
root.insert("mcp_servers".to_string(), toml::Value::Table(mcp_servers));
|
||||
}
|
||||
let config = toml::to_string(&toml::Value::Table(root)).map_err(|error| {
|
||||
platform_llm::LlmError::InvalidConfig(format!(
|
||||
"序列化隔离 Codex app-server 配置失败:{error}"
|
||||
))
|
||||
})?;
|
||||
std::fs::write(codex_home.join("config.toml"), config).map_err(|error| {
|
||||
platform_llm::LlmError::Transport(format!("写入隔离 Codex app-server 配置失败:{error}"))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1503,8 +1532,18 @@ impl CodexAppServerConnection {
|
||||
.unwrap_or_else(|| isolated_workspace.clone()),
|
||||
)
|
||||
};
|
||||
let client_mcp_servers = if workspace_mode == CodexAppServerWorkspaceMode::DirectProject {
|
||||
crate::client_extensions::prepare_enabled_client_mcp_servers()
|
||||
.map_err(platform_llm::LlmError::InvalidConfig)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
if workspace_override.is_some() && workspace_mode.allows_workspace_writes() {
|
||||
trust_isolated_game_creator_codex_workspace(&isolated_codex_home, &workspace_path)?;
|
||||
trust_isolated_game_creator_codex_workspace(
|
||||
&isolated_codex_home,
|
||||
&workspace_path,
|
||||
&client_mcp_servers,
|
||||
)?;
|
||||
}
|
||||
let isolated_os_home = working_dir.path().join("home");
|
||||
let isolated_app_data = isolated_os_home.join("appdata");
|
||||
@@ -2512,6 +2551,21 @@ async fn read_game_creator_codex_app_server_stdout(
|
||||
.get("method")
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.unwrap_or_default();
|
||||
if method == "mcpServer/startupStatus/updated"
|
||||
&& inner.workspace_mode == CodexAppServerWorkspaceMode::DirectProject
|
||||
{
|
||||
if let (Some(name), Some(status)) = (
|
||||
message
|
||||
.pointer("/params/name")
|
||||
.and_then(serde_json::Value::as_str),
|
||||
message
|
||||
.pointer("/params/status")
|
||||
.and_then(serde_json::Value::as_str),
|
||||
) {
|
||||
let _ = crate::client_extensions::record_client_mcp_startup_status(name, status);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let safe_activity = direct_codex_safe_activity_for_notification(method);
|
||||
if !matches!(
|
||||
method,
|
||||
@@ -3684,6 +3738,40 @@ mod tests {
|
||||
assert!(joined.contains("mcp_servers.agc_tools.command="));
|
||||
assert!(joined.contains(DIRECT_TOOLS_MCP_MODE_FLAG));
|
||||
assert!(joined.contains("mcp_servers.agc_tools.required=true"));
|
||||
assert!(!joined.contains("mcp_servers={}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn isolated_direct_project_config_contains_client_mcp_without_agc_tools() {
|
||||
let directory = tempfile::tempdir().expect("temporary config home");
|
||||
let workspace = directory.path().join("workspace");
|
||||
std::fs::create_dir(&workspace).expect("create workspace");
|
||||
let client_mcp = crate::client_extensions::ClientMcpRuntimeServer {
|
||||
name: "plugin-search".to_string(),
|
||||
config: std::collections::BTreeMap::from([
|
||||
(
|
||||
"command".to_string(),
|
||||
toml::Value::String("fixture-search".to_string()),
|
||||
),
|
||||
("required".to_string(), toml::Value::Boolean(false)),
|
||||
]),
|
||||
};
|
||||
trust_isolated_game_creator_codex_workspace(directory.path(), &workspace, &[client_mcp])
|
||||
.expect("write isolated config");
|
||||
let config = std::fs::read_to_string(directory.path().join("config.toml"))
|
||||
.expect("read isolated config");
|
||||
let parsed = config
|
||||
.parse::<toml::Value>()
|
||||
.expect("parse isolated config");
|
||||
assert_eq!(
|
||||
parsed["mcp_servers"]["plugin-search"]["command"].as_str(),
|
||||
Some("fixture-search")
|
||||
);
|
||||
assert_eq!(
|
||||
parsed["mcp_servers"]["plugin-search"]["required"].as_bool(),
|
||||
Some(false)
|
||||
);
|
||||
assert!(parsed["mcp_servers"].get("agc_tools").is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -10,7 +10,7 @@
|
||||
| `multi-skill/` | 2 个 Skill:`art-skill`、`code-skill` | 一个 Skill root,分别导入 |
|
||||
| `mcp-config/` | 2 个 MCP:`search`、`filesystem` | 原生 `config.toml` |
|
||||
| `mcp-json/` | 2 个 MCP:`search`、`filesystem` | 兼容 `.mcp.json` |
|
||||
| `plugin/` | 1 个 Skill:`plugin-skill` | Plugin 只作为导入来源 |
|
||||
| `plugin/` | 1 个 Skill:`plugin-skill`、1 个 MCP:`plugin-search` | Plugin 只作为导入来源 |
|
||||
| `mixed-source/` | 1 个 Skill:`mixed-skill`、2 个 MCP:`search`、`filesystem` | 一个来源拆成多个独立项 |
|
||||
| `unknown/` | 1 个未知项:`unknown.bin` | 不执行、不作为 MCP 入口 |
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -36,7 +36,8 @@
|
||||
"id": "plugin",
|
||||
"source": "plugin",
|
||||
"items": [
|
||||
{ "type": "skill", "name": "plugin-skill" }
|
||||
{ "type": "skill", "name": "plugin-skill" },
|
||||
{ "type": "mcp", "name": "plugin-search" }
|
||||
],
|
||||
"ignoredCapabilities": ["hooks", "apps", "remote_plugin"]
|
||||
},
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"plugin-search": {
|
||||
"type": "stdio",
|
||||
"command": "fixture-plugin-search"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
- Plugin 边界:Plugin 只作为导入容器提取 Skill/MCP;当前 DirectProject 关闭的 hooks、apps、remote plugin 和完整 Plugin Runtime 不接入。单个可执行文件或脚本不提供手动指定为 MCP 入口的功能。
|
||||
- 信任边界:不审核第三方 Skill 文案、脚本、二进制、MCP tool 或网络行为;导入阶段不执行内容。客户端只做标准结构识别、必要配置解析和 zip staging 路径边界处理,且不向第三方扩展注入 AGC 凭据或内部路径。
|
||||
- 影响范围:AGC 客户端扩展设置 UI、客户端本地扩展存储、DirectProject Codex app-server 启动准备和 pool fingerprint;不新增 HTTP 服务、SpacetimeDB schema、公开 API 或独立 Plugin Runtime。
|
||||
- 当前实现:客户端导入/list、Skill 临时 root 和 MCP 隔离配置注入均已落地。第三方 MCP 只从客户端已启用独立项生成本次隔离 `CODEX_HOME/config.toml`,每项固定非 required;配置错误或 app-server 启动状态失败只更新对应 `last_error`,内置 `agc_tools` 继续由客户端单独注入。客户端已启用 Skill/MCP 的名称、来源路径和内容指纹共同参与 DirectProject app-server pool identity。
|
||||
- 验证方式:分三阶段验收:先验证导入拆分和完整列表,再验证 Skill 运行时发现和重命名,最后验证 MCP 配置合并、Plugin 提取和失败隔离;只增加对应的定向测试、`npm run check:encoding` 和 `git diff --check`。
|
||||
- 关联文档:`docs/technical/【技术方案】DirectProject客户端Skill与MCP扩展导入方案-2026-08-31.md`、`apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx`、`apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server.rs`。
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ SpacetimeDB crate、SDK、CLI / standalone 与生成 bindings 按 `2.8.3` 对齐
|
||||
## AGC DirectProject 与 UI workflow
|
||||
|
||||
- 通用 Agent Rust 分层为 `agent-runtime-core`(catalog、执行生命周期、ToolHost/spawn/all-join/Provider 契约)、`agent-runtime-orchestration`(动态无环任务图、ready、依赖波次、返工下游闭包和受限自主扩图提案)与 `platform-agent` 游戏适配器;循环返工通过新 pass / epoch 表达,不在单张依赖图中建立回边。LLM 可经宿主结构化 function call 提出新增节点/边,编排层只生成经校验的新候选图,epoch 与持久化仍由宿主掌控。
|
||||
- DirectProject 只连接客户端内置的 `agc_tools` STDIO MCP。它负责审核引用读取、标准美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive、已登记图片去背景、desktop/mobile 浏览器试玩和受控 `agc_web_search`;付费资源调用由客户端绑定回合、幂等账本、请求上限和投影权威。
|
||||
- DirectProject 始终连接客户端内置的 `agc_tools` STDIO MCP,并在启动时额外读取客户端扩展仓库中已启用的第三方 MCP 独立项。第三方 STDIO/HTTP 配置只写入本次隔离 `CODEX_HOME`,单项非 required,启停、重命名和内容指纹进入 app-server pool identity;完整 Plugin Runtime、hooks/apps 和单文件脚本手动指定入口仍关闭。`agc_tools` 继续负责审核引用读取、标准美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive、已登记图片去背景、desktop/mobile 浏览器试玩和受控 `agc_web_search`;付费资源调用仍由客户端绑定回合、幂等账本、请求上限和投影权威。
|
||||
- DirectProject 的 Codex 原生文件、搜索、命令、图片查看和 Skill 仅在真实 `game/` cwd 与 `workspaceWrite(writableRoots=[game])` 内可用;原生命令网络保持关闭。多 Agent、Apps、插件、hooks、图片生成、Goals、Workspace Dependencies、Tool Suggestion 和原生浏览器/电脑控制保持关闭。app-server 使用隔离 `CODEX_HOME`,provider 凭据只由 AGC 客户端代理持有,不能进入模型上下文或 shell 环境。
|
||||
- `ui-prototype`(设计图片)与 UI 编辑器 `UI` JSON 是不同资源。白名单 `ui.workflow.run` 按页面执行 `prepare → recognize → status → finalize`,由 provider-backed 识别、合并和组件绑定持久化 State/revision,并把 `reference-ready → structure-ready → merge-ready → binding-ready → application-ready → completed` 投影到 manifest。Provider 缺失、请求失败、工具缺失、结果不匹配或仍有待审节点时保留真实阶段并返回 blocker,不得用 deterministic seed 伪造完成。
|
||||
- UI workflow 的资源桥接与 Runtime 边界以 `docs/【技术方案】UI工作流资源桥接与Runtime执行-2026-08-24.md` 和 AGC 实施计划的 2026-08-24 覆盖段为准;只生成图片、登记空 JSON 或进入普通图片画布都不构成 workflow 完成。
|
||||
|
||||
@@ -1756,6 +1756,6 @@ V1.54 的公共编排层可以在运行前构造动态 DAG,但 LLM 在执行
|
||||
|
||||
## DirectProject 原生工具边界覆盖(2026-08-24)
|
||||
|
||||
本文中 V1.1/V1.52 关于 app-server 全局关闭 native shell、network、browser、plugin 和 multi-agent 的表述继续适用于 ToolHost/DirectHome 与 legacy Runtime;不再作为 DirectProject 的现行实现。DirectProject 恢复原生文件/搜索/命令、图片查看和 Skill,并通过隔离 `CODEX_HOME` 只注入审核后的 `agc_tools` MCP。平台美术、资源投影、浏览器试玩、受控搜索、付费副作用和 durable delegation 仍必须走 AGC 权威链路。
|
||||
本文中 V1.1/V1.52 关于 app-server 全局关闭 native shell、network、browser、plugin 和 multi-agent 的表述继续适用于 ToolHost/DirectHome 与 legacy Runtime;不再作为 DirectProject 的现行实现。DirectProject 恢复原生文件/搜索/命令、图片查看和 Skill,始终注入审核后的 `agc_tools` MCP,并可在启动时从客户端扩展仓库接入用户已启用的独立第三方 MCP 配置;第三方配置不进入全局 Codex home,不开启完整 Plugin Runtime。平台美术、资源投影、浏览器试玩、受控搜索、付费副作用和 durable delegation 仍必须走 AGC 权威链路。
|
||||
|
||||
DirectProject 的写入根固定为真实 `game/`,审批策略为 `never`,原生命令网络保持关闭,联网资料继续走受控 `agc_web_search`;shell 使用 Codex `shell_environment_policy` 的 glob 排除 API key、proxy、loopback bridge 和受控开关。配置了 AGC LLM Key 或可解析的 `OPENAI_API_KEY` 登录态时,真实 provider 凭据只由 AGC 本地 provider proxy 持有,Codex 仅获得连接级随机代理令牌;无法安全代理的 OAuth `auth.json` 继续关闭 native shell/unified exec。Codex 原生子 Agent、Apps、插件、hooks、图片生成、Goals、Workspace Dependencies、Tool Suggestion 以及未接入 AGC 证据链的浏览器/电脑控制保持关闭。系统提示词只传入最小身份、工作区、Skill 索引和副作用边界,不再批量注入源码快照或 Skill 正文。sandbox writableRoots 不提供 deny-read;`.agent` 与 `../assets` 的不可读约束仍需通过 prompt/Skill 行为合同和真实 smoke 验证,不能误称为 OS 强制隔离。
|
||||
|
||||
@@ -1188,7 +1188,7 @@ game-project/
|
||||
- 普通项目对话只由一个 project-bound Codex app-server thread 执行。客户端系统提示词只放最小工程合同、当前游戏源码有界快照、项目 prompts 和审核 Skill 索引;不再批量读取项目 `.codex/.agents` Skill 正文,也不恢复 Supervisor、专业 Agent 或 harness。
|
||||
- 首页恢复“做游戏 / 做素材 / 做方案”三个创作类型,默认“做游戏”。该选择与设置页的 Agent Runtime 模式无关;每次首页提交仍只自动创建一个新项目并进入项目工作台。用户正文原样进入项目对话,`game|art|doc` 仅作为受限结构化首轮上下文传给同一 Codex thread,不拼接“初始意图”文案、不产生首页对话、不切换 Provider 或恢复旧 Runtime 编排。
|
||||
- `agc-skill-pack.v1` 只包含项目结构、陶泥儿美术、Web 游戏实现、真实浏览器试玩、客户端资源投影五项 Skill。清单记录用途、触发条件、所需工具、版本和内容 SHA-256;审核文本按 UTF-8 读取并将 CRLF 规范为 LF 后计算指纹和安装,避免混合换行造成 Windows / Linux 构建结果漂移,语义内容变化时必须同步重算对应清单指纹并提升版本。同步统一运行 `npm run agc:skill-pack:sync`,只读校验由 AGC `typecheck` 和 release build 自动执行,发现漂移时直接列出 Skill 与实际摘要,不让失配内容进入构建产物。客户端把审核文件安装到隔离目录后通过 app-server `skills/extraRoots/set + skills/list` 注册并复核,完整正文由 Codex 原生 Skill 机制按意图加载,一层引用只能经 `agc_read_skill_resource` 读取清单内 Markdown。引用路径按平台无关规则拒绝反斜杠、盘符、UNC、绝对路径和 `..`,不能依赖当前宿主的 `std::path` 语义判断其它平台路径。
|
||||
- DirectProject 只连接客户端内置的 `agc_tools` STDIO MCP,工具固定为审核引用读取、标准陶泥儿美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive 语义生成、已登记图片去背景和 desktop/mobile 浏览器试玩。MCP 进程只做协议;真实浏览器与付费 External v1 调用通过随机 loopback 地址回到客户端主进程,因此不复制 GUI 登录态、开发者 Key、项目路径、revision、operation 或幂等键到模型上下文。已登记工具固定自动批准,但付费资源工具仍由客户端绑定稳定回合身份、限制单回合请求数、串行执行并优先恢复匹配账本;通用 shell、Codex 原生 webSearch、任意网络、多 Agent、插件和外部 MCP 继续关闭。`codex_app_server` 模式要求 `llm.webSearchEnabled=false`。
|
||||
- DirectProject 始终连接客户端内置的 `agc_tools` STDIO MCP;2026-08-31 起还会在启动时接入客户端扩展仓库中用户已启用的独立第三方 STDIO/HTTP MCP 配置,但不读取用户全局 Codex MCP、不开启完整 Plugin Runtime。`agc_tools` 工具固定为审核引用读取、标准陶泥儿美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive 语义生成、已登记图片去背景和 desktop/mobile 浏览器试玩。内置 MCP 进程只做协议;真实浏览器与付费 External v1 调用通过随机 loopback 地址回到客户端主进程,因此不复制 GUI 登录态、开发者 Key、项目路径、revision、operation 或幂等键到模型上下文。内置与用户启用的第三方 MCP 工具都沿用 DirectProject 自动批准方式,但付费资源工具仍由客户端绑定稳定回合身份、限制单回合请求数、串行执行并优先恢复匹配账本;Codex 原生 webSearch、任意原生命令网络、多 Agent 和完整插件能力继续关闭。
|
||||
- 陶泥儿生成继续复用持久幂等账本、operation 恢复、来源/下载/PNG 解码和 manifest 登记;普通客户端优先使用当前 AGC 登录会话及账号路由,只有受控的 ExternalDeveloper 发布模式才在客户端内部使用按服务器 origin 隔离的私有 Key。用户和模型都不需要提供或配置 API Key;凭据失效、来源不明或结果未知时失败关闭,不能自动换 Key 或重新扣费。
|
||||
- 自定义 LLM API Key 路由只在 DirectHome/DirectProject 经 loopback `/responses` 流式代理转发。代理不注入 Key,只要求请求自带 Bearer,并剥离开发网关错误携带的 `X-Codex-*` ChatGPT 账户额度头,防止隔离 app-server 把 API Provider 误判为余额 0;旧 ToolHost 保持原 Provider 行为。
|
||||
|
||||
@@ -1252,7 +1252,7 @@ game-project/
|
||||
|
||||
本文早期关于“DirectProject 关闭通用 shell、原生网络和主动工具”的描述属于迁移前基线,现由以下覆盖规则取代:DirectProject 仅在真实 `game/` cwd 与 `workspaceWrite(writableRoots=[game])` 内恢复 Codex 原生文件/搜索/命令、图片查看和 Skill;其余 ToolHost/DirectHome 合同不变。客户端审核的 `agc_tools` MCP 继续承担平台美术、资源登记、去背景、浏览器试玩和受控搜索,并保留项目锁、幂等账本、下载校验、恢复与投影权威。
|
||||
|
||||
DirectProject 使用 `approvalPolicy=never`,避免每次原生调用再经过泛化 ToolHost 包装;原生命令网络保持关闭,联网资料继续走受控 `agc_web_search`。多 Agent、Apps、插件、hooks、Goals、Workspace Dependencies、Tool Suggestion 和原生浏览器/电脑控制仍关闭,避免绕过 AGC durable delegation、浏览器证据和副作用审计;图片生成通过客户端审核的 `agc_tools.agc_generate_image` 暴露普通单图、角色图、视觉规范图和 UI 设计图,完整游戏美术包继续使用 `agc_tools.taonier_prepare_game_art`,两者都复用同一客户端登录态、幂等账本、下载校验和 manifest/revision 投影,不开放 Codex 原生 image tool。app-server 使用隔离 `CODEX_HOME`,明确清空外部 MCP 后只注入 `agc_tools`;配置了 AGC LLM Key 或可解析的 `OPENAI_API_KEY` 登录态时,真实 provider 凭据只由 AGC 本地 provider proxy 持有,Codex 仅使用连接级随机代理令牌;无法安全代理的 OAuth `auth.json` 继续关闭 native shell/unified exec。`agc_tools` 的平台授权由 AGC 客户端当前登录会话和受控后端完成,普通客户端不得把 DirectProject 请求改成外部 API Key 请求;401/403 只投影为客户端登录或权限异常,不向用户索要凭据或暴露内部 URL。shell 子进程采用 `shell_environment_policy` core 继承及 secret/proxy/bridge 排除,provider key 和桥接凭据不得进入命令环境。系统提示词不再预注入项目源码快照或 Skill 正文,Codex 按需读取当前 cwd 文件。
|
||||
DirectProject 使用 `approvalPolicy=never`,避免每次原生调用再经过泛化 ToolHost 包装;原生命令网络保持关闭,联网资料继续走受控 `agc_web_search`。多 Agent、Apps、完整插件 Runtime、hooks、Goals、Workspace Dependencies、Tool Suggestion 和原生浏览器/电脑控制仍关闭,避免绕过 AGC durable delegation、浏览器证据和副作用审计;图片生成通过客户端审核的 `agc_tools.agc_generate_image` 暴露普通单图、角色图、视觉规范图和 UI 设计图,完整游戏美术包继续使用 `agc_tools.taonier_prepare_game_art`,两者都复用同一客户端登录态、幂等账本、下载校验和 manifest/revision 投影,不开放 Codex 原生 image tool。app-server 使用隔离 `CODEX_HOME`:内置 `agc_tools` 由客户端启动参数注入,用户在客户端扩展列表启用的独立第三方 MCP 以原生配置写入该次隔离 home;全局 Codex MCP、禁用项、Plugin hooks/apps 和其它插件能力不进入 DirectProject。第三方项固定非 required,配置或启动失败只记录该项,不替换 `agc_tools`;provider session token、工具桥地址和受控搜索标记不得通过第三方 MCP 的环境转发字段泄露。配置了 AGC LLM Key 或可解析的 `OPENAI_API_KEY` 登录态时,真实 provider 凭据只由 AGC 本地 provider proxy 持有,Codex 仅使用连接级随机代理令牌;无法安全代理的 OAuth `auth.json` 继续关闭 native shell/unified exec。`agc_tools` 的平台授权由 AGC 客户端当前登录会话和受控后端完成,普通客户端不得把 DirectProject 请求改成外部 API Key 请求;401/403 只投影为客户端登录或权限异常,不向用户索要凭据或暴露内部 URL。shell 子进程采用 `shell_environment_policy` core 继承及 secret/proxy/bridge 排除,provider key 和桥接凭据不得进入命令环境。系统提示词不再预注入项目源码快照或 Skill 正文,Codex 按需读取当前 cwd 文件。
|
||||
## 2026-08-24 AGC UI 原型桥接与自主 UI workflow
|
||||
|
||||
- 2026-08-24 起,`ui-prototype` 与 UI 编辑器的 `UI` JSON 资源明确分离。设计图生成后必须由白名单 `ui.workflow.run` 按页面执行 `prepare → recognize → status → finalize`:为每个功能页面创建并关联 `UI` JSON,载入页面设计图和已登记图片/图标/字体,调用 UI Editor 的 provider-backed 结构识别、多树合并与分批组件绑定,持久化 State/revision,写入 `game/` 应用标记,并把 `reference-ready → structure-ready → merge-ready → binding-ready → application-ready → completed` 各阶段的 `generationKind` 和 manifest revision 投影给客户端。Provider 未配置、请求失败、工具调用缺失、结果不匹配、未知字体引用、未产出可渲染组件或仍有待审节点时保留最近真实阶段并返回 blocker,不得使用 deterministic seed 冒充完成。工作台点击 `ui-prototype` 时通过 `ensure_ui_design_resource_for_prototype` 幂等补齐关联资源;工作流完成后自动打开首个页面的 UI 编辑器 `visual-binding` 最终阶段,交给用户检查和手动调整。只生成图片、登记空 JSON 或进入普通图片画布均不构成 UI 工作流完成,详见 [`【技术方案】UI工作流资源桥接与Runtime执行-2026-08-24.md`](../【技术方案】UI工作流资源桥接与Runtime执行-2026-08-24.md)。
|
||||
|
||||
@@ -326,8 +326,14 @@ MCP · 来自 my-plugin.zip 启动失败
|
||||
|
||||
每个 MCP Server 独立启用和禁用。相对路径按来源目录解析,原始 command、args、cwd、env 或 URL 按原生配置保留。
|
||||
|
||||
运行时只转换 Codex 原生能够直接使用的标准字段。STDIO 支持 `command / args / env / env_vars / cwd`;HTTP 支持 `url / bearer_token_env_var / http_headers / env_http_headers`;两类都支持原生启动超时、工具超时和工具筛选字段。客户端启用状态是运行时权威,每个第三方项固定 `enabled=true`、`required=false`,并沿用 DirectProject 无逐工具弹窗的自动批准方式。第三方 MCP 配置写入本次隔离 `CODEX_HOME/config.toml`,避免配置中的环境值或静态 header 出现在进程命令行。
|
||||
|
||||
用户导入来源中的相对 `cwd` 按该 MCP 配置文件所在目录解析;未声明 `cwd` 的 STDIO Server 默认以该目录启动,从而保留脚本参数的原生相对路径语义。客户端不替用户猜测普通文件如何启动。
|
||||
|
||||
`agc_tools` 为 AGC 内部保留名称,第三方扩展不得覆盖。第三方 MCP 的工具调用继续继承 DirectProject 当前既有运行策略;本功能不新增逐工具审核系统。
|
||||
|
||||
客户端不会把 AGC provider session token、工具桥地址或受控搜索标记通过 `env_vars`、`bearer_token_env_var`、`env_http_headers` 转发给第三方 MCP。扩展自身静态声明的 `env` 和 `http_headers` 仍按原生配置使用。OAuth 登录 UI、OAuth 凭据中心和自动登录不属于本阶段。
|
||||
|
||||
### 8.3 失败处理
|
||||
|
||||
第三方扩展的解析或启动失败时:
|
||||
@@ -433,6 +439,8 @@ remove_client_extension(id)
|
||||
|
||||
### 阶段 3:MCP 和 Plugin 部分闭环
|
||||
|
||||
当前实施状态:已完成。客户端会在 DirectProject 启动前读取所有已启用 MCP 独立项,把可转换的 STDIO/HTTP 原生字段合并进本次隔离 `CODEX_HOME/config.toml`,再由现有启动参数单独注入内置 `agc_tools`。第三方项固定为非 required,结构错误或启动失败只更新对应扩展项的 `last_error`;Codex app-server 的 `mcpServer/startupStatus/updated` 通知用于清除或记录单项启动状态。已启用 MCP 的名称、来源相对路径和内容指纹已纳入 app-server pool key。Plugin 样例已覆盖同一来源中的 Skill/MCP 独立提取,不开启 Plugin Runtime。
|
||||
|
||||
完成:
|
||||
|
||||
- `config.toml` 每个 Server 独立导入;
|
||||
|
||||
Reference in New Issue
Block a user