同步master最新变更
合入当前主线的多窗口与配置更新 保留AGC画布交互和JSON识别修复 保留双方新增的项目排障记录并解决文档冲突
This commit is contained in:
@@ -1,6 +1,36 @@
|
||||
# AGC 后台模型别名与对话选择
|
||||
|
||||
## 契约
|
||||
## 本地自定义 LLM
|
||||
|
||||
- 本地 `game-creator.config.json` 的 `llm.customEnabled` 默认 `false`;显式设为 `true` 后,常用设置展示 API 地址、API Key、读取模型列表与勾选区域。DirectProject 沿用 OpenAI Responses 协议,地址填写 API 根地址(例如 `https://provider.example/v1`)。开关只由配置文件控制。
|
||||
- 点击读取后,客户端原生侧直接请求该地址下的 `GET /models`,使用自定义 Bearer Key,读取 OpenAI 兼容的 `data[].id`。请求有超时与响应大小上限,禁止携带平台登录凭据、禁止重定向;错误仅展示安全状态,不回显上游响应体或 Key。
|
||||
- 模型支持搜索、逐项勾选和独立的已勾选列表预览。`llm.visibleModels` 按勾选顺序保存模型 ID,第一项作为默认项。至少勾选一项才可保存;读取失败保留草稿和已勾选列表,不替用户清空或新增选择。
|
||||
- 首页与项目对话复用现有模型选择器;自定义模式只读取本地勾选目录,不请求平台模型目录。模型 ID 原样用于上游请求(允许 `/`、`.`、`:`),所选项被取消勾选时回退第一项。保存后刷新目录,下一回合使用新连接与模型,活动回合继续使用原快照。
|
||||
- 开启后,Codex 客户端凭据代理和 Rust LLM 调用均直连自定义端点,不走平台 `/api/llm` 或内置中转;配置缺失或请求失败明确报错,不回退官方路由。真实 Key 留在客户端,不进入 Codex 子进程环境、参数或模型上下文。平台图片、音频、账户和计费契约不变。
|
||||
- 配置加载、迁移和覆盖文件写入保留显式开启的连接和勾选列表;关闭时仍使用官方模型目录与官方路由。缓存不能跨自定义/官方目录或不同自定义连接复用。旧配置缺少新字段时保持官方行为。
|
||||
- 验收覆盖开关默认值、配置合并/保存/重载、直连凭据与模型传递、模型发现成功/失败/超时、勾选预览、仅显示勾选模型、目录切换、无平台目录请求和设置保存失败。自动化本地 HTTP 验证与真实供应商 smoke 分开报告。
|
||||
|
||||
在设置页显示的本地配置文件路径中,手动把现有 `llm` 对象的 `customEnabled` 设为 `true`(保留其它字段),重新打开常用设置即可配置连接和读取模型。界面没有开启开关,保存设置也不能把关闭状态改为开启。配置文件也支持直接填写以下字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"llm": {
|
||||
"customEnabled": true,
|
||||
"baseUrl": "https://provider.example/v1",
|
||||
"apiKey": "填写自己的密钥",
|
||||
"apiKind": "openai_responses",
|
||||
"visibleModels": ["provider/model-name", "another-model"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`visibleModels` 可先留空,再从端点读取并勾选;未完成勾选前不能发起自定义 LLM 对话。关闭时手动改回 `false`,后续回合使用官方目录和路由。
|
||||
|
||||
本地配置文件始终保留 `customEnabled`、`visibleModels`、`apiKey`、`baseUrl`、`model`、`apiKind`、`reasoningEffort` 七个键:官方路由下连接字段写官方地址与空 Key、协议写 `openai_responses`,便于手写自定义连接时对照;切换为自定义后这些值原样保留而不被启动清理。
|
||||
|
||||
自定义连接固定使用 OpenAI Responses 协议(`apiKind` 只接受 `openai_responses`),设置页把协议展示为只读项;推理档沿用对话输入盒中按回合生效的选择器,设置页只读展示当前档位,不新增第二处写入入口。
|
||||
|
||||
## 官方路由契约
|
||||
|
||||
- 后台 owner 在“AGC 模型”维护列表;每项包含稳定 `id`、必填 `alias`、服务端 `modelId`、`enabled`。默认项必须启用。标识唯一,别名唯一,列表最多 32 项。
|
||||
- 配置保存到私有 `agc_model_catalog` 单例表,使用 revision 乐观锁,重启及多 api-server 实例共享同一事实。缺少配置时使用初始目录,高质量对应 `gpt-6-astra`,快速对应 `gpt-5.6-luna`。
|
||||
@@ -14,7 +44,7 @@
|
||||
- `selectedModelIsDefault` 为真表示选择由平台默认项驱动(首次进入、默认项变化、所选模型失效回退),后台默认项变化时客户端跟随切换并提示;用户手动选择后置为假,不再被默认项变化覆盖。
|
||||
- 首页聊天框架的右下角同样提供模型选择入口(与项目对话右侧一致)。首页入口与项目对话共用同一份目录缓存、挂载即加载(失败时沿用上一次成功目录),选择仅影响后续创建/发送的轮次,不阻塞「开启创作」,因此模型目录不可用时仍可创建项目并使用后台默认项。
|
||||
- 项目右侧对话的模型选择器在对话进行中保持可交互:切换模型只写回客户端配置并作用于下一轮,当前回合不受影响;发送按钮仍由 `controlBusy` / `modelReady` 把关。
|
||||
- 设置页恢复到布局改版前的官方代理版本,不包含模型管理或模型选择,保留配置安全清理和官方代理锁定。
|
||||
- 自定义开关关闭时,设置页不包含模型管理或模型选择,使用官方代理锁定。
|
||||
|
||||
## 验收
|
||||
|
||||
|
||||
@@ -71,9 +71,11 @@ DirectProject 自身的 `read_direct_project_conversation` 也必须在 blocking
|
||||
|
||||
## 常用设置职责
|
||||
|
||||
本地配置 `llm.customEnabled` 为 `true` 时,常用设置开放自定义 Responses 连接、端点模型发现与勾选预览;开关只允许手动修改配置文件。模型选择、直连与凭据边界以 [AGC 后台模型别名与对话选择](./【技术方案】AGC后台模型别名与对话选择-2026-09-05.md) 的“本地自定义 LLM”为准,默认仍使用官方服务。
|
||||
|
||||
常用设置负责运行参数的读取、编辑和保存,配置读写独立于账号权限诊断。账号权限由登录会话与实际智能服务请求链路处理,设置面板只维护配置草稿与读写反馈。
|
||||
|
||||
保存配置复用写入前读取的高优先级本地覆盖内容:常用设置同步覆盖文件中已有的对应配置项,并保留当前模型 ID 和默认模型标记;模型选择仅同步 `selectedModelId` 与 `selectedModelIsDefault`;无冲突时不写覆盖文件。所有内容先完成序列化,多文件写入前保存原始内容,任一写入失败时逆序恢复已变更文件,回滚失败须明确报告。各文件沿用现有原子写入,不提供断电或进程崩溃下的多文件事务保证。全部成功后直接返回规范化配置,不执行保存后回读或外部诊断;单文件保存保持原路径。
|
||||
保存配置复用写入前读取的高优先级本地覆盖内容:常用设置同步覆盖文件中已有的对应配置项,并保留当前模型 ID 和默认模型标记;自定义模式取消勾选当前模型时回退第一项,并同步覆盖文件中的选择。模型选择仅同步 `selectedModelId` 与 `selectedModelIsDefault`;无冲突时不写覆盖文件。所有内容先完成序列化,多文件写入前保存原始内容,任一写入失败时逆序恢复已变更文件,回滚失败须明确报告。各文件沿用现有原子写入,不提供断电或进程崩溃下的多文件事务保证。全部成功后直接返回规范化配置,不执行保存后回读或外部诊断;单文件保存保持原路径。
|
||||
|
||||
## 2026-09-09 manifest 资源功能分类与自定义标签(UI 与写入)
|
||||
|
||||
@@ -559,6 +561,7 @@ Agent Runtime 负责:
|
||||
- 2026-07-10 补充:`agent.delegate` 已形成可恢复的父子任务闭环。`delegationId` 由 durable pending action 的 `actionId` 派生,子任务记录会保存 `parentAgentId / parentRunId / delegationId`,终态记录额外保存经过统一凭据清洗和安全截断的 `terminalDetail`;同一委派的提交和回执分别受 delegation 级 OS 文件锁保护,同一目标 Agent 的 runId 分配与 pending 追加还受任务账本 OS 锁保护。子任务进入 `completed / failed / cancelled / budget-exhausted` 任一终态时,Runtime 按 `delegationId` 幂等生成且至多生成一次 `agent.delegate.result` 回执,失败、排队或活跃取消、预算耗尽都必须回传,不能只覆盖成功。回执会向父 Agent 既有队列追加固定 runId、`source=agent-delegate-receipt` 的续跑任务,把完整的已清洗 `terminalDetail` 交回父 run,不再只保留 80 字符 UI 摘要;回执 prompt 明确禁止重复同一委派,排队期间不提前写入父会话,真正开始执行时才幂等落盘,用户消息或回执消息落盘失败时不会进入 LLM。回执任务保留父 run 关联,并在真正开始或恢复前再次检查父 run 状态,关联缺失或父 run 不存在时失败关闭;该续跑仍受父 Agent 原有 FIFO、per-Agent OS 锁、权限确认、取消、恢复和 `needs-reconciliation` 屏障约束,不直接重入父 run、不插队、不新增独立 worker;父 run 已取消或普通失败时只保留 suppressed receipt 审计,不自动复活,父 Session 归档与切换会被未结束委派阻止,极端归档竞态下回执回落到父 Agent 当前可写 Session。恢复先恢复 pending action / reconciliation 屏障,再扫描“子任务终态已落盘但回执未提交”的窗口并补齐缺失回执;`needs-reconciliation` 本身不回执,只有人工核对后最终取消才回传 `cancelled`。
|
||||
- 历史记录(已由 V1.1 独立 Runner 替代):Runtime 最初通过 `resume_game_creator_agent_runtime_tasks` 把本地 JSONL 队列重接到当前 App 进程。当前恢复入口仍保留权限、任务顺序和 `agent.runtime.background_task.recovered` 审计语义,但实际由独立 Runner 接管原 run / session;已发出的上游 LLM 请求仍不能从网络中间点续传。2026-07-27 起,Runner 归 Tauri GUI 生命周期所有,同一 AppData 只允许一个 GUI owner。GUI 启动子进程会显式声明 `--gui-owner-required` 并在就绪后 attach owner;Runner 若在启动检查前已发现 owner 释放则直接失败,不得退化成 CLI-owned Runner。Runner 使用独立 watchdog 线程每 100ms 监控 owner OS 锁,不依赖服务端主循环继续推进;owner 丢失后先触发 1.5 秒共享 deadline 的 draining、Provider 中断和 process session 回收,若主循环或排空链路卡死则在 1.75 秒后由 Runner 自身进程安全硬退出并清理匹配 bootId 的 endpoint。GUI 客户端还必须把完整 `runner.attach_gui_owner` 参数作为绑定规范化 AppData 的进程内登记保存;`ensure_external_agent_runner` 无论复用既有 endpoint 还是启动新 Runner,都要在把 endpoint 交给 Runtime 写请求前按新 `bootId` 补登记。同一登记 generation 在同一 boot 上幂等,补登记失败不得记录成功 boot 且本次 `ensure` 失败关闭;未建立 GUI 登记的普通 CLI 不执行该重放。OS owner 锁与 watchdog 已成立只代表进程受 GUI 生命周期约束,不能替代事件 sink 等进程内附加能力的逐 boot 恢复。因此正常最终退出、panic、SIGKILL 和 setup 中途失败都不会再因 busy 或主循环卡死而残留后台进程。endpoint 缺失 / 读取失败必须结合 Runner 实例锁判断;GUI 客户端强制兜底在 Linux 使用 pidfd、Windows 使用稳定进程 handle。macOS 没有等价稳定句柄,客户端不得在 start identity 检查后按裸 PID 强杀,而由跨平台 Runner 自身 watchdog 提供硬退出兜底。旧 endpoint 缺 start identity 时,只有认证 ping 精确匹配 PID + bootId 才允许迁移 busy 旧 Runner。未完成任务保持 durable 状态并在下一次启动走 reconciliation / recovery,不能伪造 completed 或重放副作用。关闭单个 WebView / 子窗口和普通 CLI 退出不触发该行为,版本切换与人工命令仍可使用只关闭空闲实例的 `runner.shutdown_if_idle`。
|
||||
- 2026-08-23 Runner 协议 v7 GUI owner 会话权威补充:GUI 取得 owner OS 锁时产生随机 `owner epoch`,并在私有 AppData 持久化只含 `owner epoch + session revision` 的 claim;每次登录、refresh、退出或换号都必须先单调推进 durable session revision,再同步 Runner。`runner.attach_gui_owner` 是 Runner 接受平台会话快照的唯一授权入口;只有 attach 携带的 epoch/revision 与 durable claim 完全一致才可安装或清除会话,新 GUI epoch 可替换旧进程留下的高 `authGeneration`,不用可在新 WebView 重置的 generation 猜测进程所有权。Runner 在 claim 缺失、不可读或与当前 attach 身份失配时立即清空进程内平台会话,并阻断除重新 attach 及必要管理请求以外的 Runtime 工作;旧 `platform.session.install/clear` 协议不再是授权入口。GUI 会话同步未得到完整 attach 确认时本地变更必须失败,并隔离或停止旧 Runner;即使进程终止失败,claim 失配门禁也不允许旧账号继续发起 Runtime 请求。claim 不保存 Access Token,Token 只随当次受保护的 attach IPC 进入 Runner 内存。
|
||||
- 2026-09-16 多窗口更正:同一 AppData 不再只允许一个 GUI 界面进程。原 owner OS 锁改为可被多个界面进程同时持有的参与者锁(`agent-runner.gui-participant.lock`),Runner 以“能否独占取得该锁”判断是否仍有界面进程存活,watchdog 与 attach 门禁都改用该判定。新增窗口默认只**采纳** durable claim(读同一 epoch/revision 并 attach),只有登录、refresh、退出或换号才发布新 claim(新 epoch + 本窗口 revision),因此同 claim 的重复 attach 不再清空平台会话,epoch 变化才允许强制替换。事件接收端从单槽改为按 token 去重的注册表并广播,保证第二个窗口 attach 后第一个窗口仍收到 manifest 失效与 Runtime update relay。claim 一致性与失败关闭语义不变。详见同文档「2026-09-16 AGC 同 AppData 多窗口共享 Agent Runner」。
|
||||
- 2026-08-05 GUI owner attachment 确认补充:登记参数必须保存 GUI manifest 事件接收端的真实 `event_sink_port` 与 `event_sink_token`,不得借用 actionId 等无关字段作为测试替身。每次 attach RPC 只有同时返回 `attached=true` 与 `eventSinkAttached=true` 才能把当前 `bootId` 标记为已登记;`eventSinkAttached` 缺失、为 false 或普通 RPC 失败都保持当前 boot 待重试。sink token 只留在私有进程内登记和 RPC 参数中,不进入日志、错误文本或公共状态。
|
||||
- 2026-07-10 补充,2026-07-16 由 V1.28 澄清:后台 planning 与预算内 final reply 使用专用最小上下文,只预置 Agent 身份、sessionId、runId、执行模式和工具策略;Agent 私有记忆、项目记忆、黑板、对话、资产、项目索引与文件正文只能经对应工具通过权限 gate 后作为 observation 进入下一轮。只有开发窗口的专业 Agent 前台直调可使用对应角色上下文;正式用户前台现已统一进入 `project-supervisor`。长黑板、记忆和对话按尾部截断,确保最新结论与最新定向消息优先保留。
|
||||
- 2026-07-10 补充,2026-07-16 由 V1.28 澄清:同一 Agent 的开发前台直调、流式调试和后台任务统一使用 `.agent/runtime/locks/<agentId>.lock` OS 文件锁。开发前台不再在整个 LLM 请求期间占用项目级写锁;同 Agent 后台任务在开发前台运行时只入队,前台成功或失败后把当前 Agent 锁直接移交给 drain,不重新抢锁,也不允许 drain 启动异常把已经完成的调试结果改判为失败。正式用户 GUI 不通过该入口直聊专业 Agent;不同 Agent 继续并行,真实项目写工具只在副作用执行期间短暂申请项目写锁。
|
||||
@@ -1458,3 +1461,42 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面
|
||||
- 运行中的正文和工具按原有唯一回合流实时显示;完成后,除最终回复和失败提示外,中间文本与所有工具调用统一放入默认收起的“执行过程”,允许手动展开,刷新或重新进入仍默认收起。
|
||||
- 最终回复沿用 Runtime 的最后一个 assistant item 合同,不按文本长度或相似度判断。失败回合不把最后一句过程输出伪装成最终回复。无流历史按同一用户消息边界划分,只保留最后一条 assistant 回复在外;用户消息与失败提示始终保留。
|
||||
- 验收覆盖已完成回合重进、真实活动回合恢复、跨项目迟到快照、运行到完成自动收起、历史无流、失败、发送时间刷新和旧记录时间缺失。不改变实际工具执行、鉴权、数据库或用户项目内容。
|
||||
|
||||
## 2026-09-16 AGC 同 AppData 多窗口共享 Agent Runner
|
||||
|
||||
### 目标与非目标
|
||||
|
||||
- 目标:同一个 AppData 可以同时运行多个 AGC 界面进程,它们共享同一个 Agent Runner、同一份平台登录态权威和同一份项目事实,并且都继续收到 manifest 失效与 Runtime update relay。
|
||||
- 非目标:不引入多 Runner、不做跨 AppData 的会话共享、不改变渲染层 generation 语义、不修改平台 HTTP 契约、SpacetimeDB schema 与 `/api/external/v1`。
|
||||
|
||||
### 参与入口、状态与跨模块边界
|
||||
|
||||
- 界面进程持有的 OS 锁改为**参与者锁** `agent-runner.gui-participant.lock`:它以共享句柄打开,任意数量的界面进程可同时持有;Runner、watchdog 与 attach 门禁只做“能否独占取得该锁”的探测,独占成功即表示已无界面进程存活。
|
||||
- durable claim `agent-runner.gui-owner.claim.json` 仍是唯一的 owner 授权记录,内容仍为 `ownerEpoch + sessionRevision`;claim 不保存 Access Token。
|
||||
- 项目级 `.agent/project.lock` 不变:多窗口共享 Runner 不等于共享项目写权,同一项目同一时刻仍只有一个写者。
|
||||
|
||||
### 正常、失败、重试与幂等行为
|
||||
|
||||
- 采纳:窗口启动时先读取 durable claim 并以同一 `epoch/revision` attach;claim 缺失或不可读时才发布新 claim。采纳路径不写 claim。
|
||||
- 发布:登录、refresh、退出或换号时,窗口写入新 claim(新 epoch + 本窗口 revision)再 attach;同一次发布在多个窗口并发发生时以最后一次成功写入的 claim 为准,落败窗口按最新 claim 重试,重试仍有界失败时向用户暴露错误,不做隐式合并。
|
||||
- 幂等:同一 claim 的重复 attach 是空操作,不得清空或替换 Runner 平台登录态;只有 epoch 变化或携带明确登出参数的 attach 才允许替换 / 清空。
|
||||
- 失败关闭:attach 携带的 epoch/revision 与 durable claim 不一致、claim 不可读、或 claim 在 attach 提交期间变化时,Runner 继续清空进程内平台会话并阻断除重新 attach 与必要管理请求以外的 Runtime 工作。
|
||||
- 事件:manifest 失效与 Runtime update relay 广播到全部已登记接收端(按 `event_sink_token` 去重,发送失败即淘汰该接收端),单个窗口退出或接收端失效不得影响其它窗口。
|
||||
- 生命周期:Runner 跟随“是否仍有界面进程存活”,不跟随某一个窗口;全部窗口退出后必须在有界时间内关停并清理 endpoint、释放实例锁。
|
||||
|
||||
### 契约与兼容
|
||||
|
||||
- 本机 GUI ↔ Runner 协议方法与参数不变;变化只在参与锁语义、claim 采纳/发布时机与事件接收端注册表。
|
||||
- 已退役的“同一 AppData 只允许一个 GUI owner”行为不再保留兼容分支;`startup.runner.owner-lock.failed` 诊断分类改名为参与者锁失败,仅在真正无法建立参与锁时出现。
|
||||
- 混用新旧版本二进制访问同一 AppData 不属于支持场景:旧版本仍以独占方式持有旧锁文件,可能让新版本判定为“仍有界面进程存活”。
|
||||
|
||||
### 验收标准与证据来源
|
||||
|
||||
- 定向 Rust 测试:参与者锁可多进程同时持有、全部释放后存活判定为假;同 claim 重复 attach 不改写登录态;epoch 变化才强制替换;两个接收端都收到同一事件;claim 采纳与发布的失败关闭路径。
|
||||
- 运行时 smoke:同一 AppData 启动两个真实 GUI,两个进程都完成 `startup.setup.complete`,`--agent-runner` 进程只有一个,关闭其中一个后另一个仍可继续使用 Runner。
|
||||
- 边界:项目级写锁继续拒绝两个窗口同时写同一项目;新增日志与错误文案不含 Token、Access Token、API Key 与绝对路径。
|
||||
|
||||
### 未决问题
|
||||
|
||||
- 两个窗口同时对同一项目发起 Runtime 写请求时,用户体验仍由项目级写锁串行决定;本次不引入跨窗口排队提示。
|
||||
- 平台会话在窗口间传播依赖共享 localStorage 与 Runner 权威;渲染层不做跨窗口事件推送,另一个窗口在下一次会话校验或刷新时收敛。
|
||||
|
||||
Reference in New Issue
Block a user