合并 origin/master 到资源工作台 V3 分支:解 4 处冲突并保留两侧行为
Project CI / Repository checks (pull_request) Successful in 3m14s
Project CI / Frontend tests (pull_request) Successful in 3m57s
Project CI / Backend tests (pull_request) Successful in 6m30s
Project CI / Native shell tests (pull_request) Successful in 17m27s

- WorkspaceLauncher.tsx:保留本分支清单快照 CAS 拒收提示(manifestMergeNotice 提示条、data-manifest-merge-* 观察点、recoverRejectedManifestSnapshot「重新读取清单」)与 activeVersionId/onActiveVersionChange 版本口径,并入 master 的策划/游戏运行态切换(onMakeGame + switchToGameRuntime、suppressInitialGameTurn 抑制首轮、supervisor key 带 agentRuntimeMode、onSwitchToGameRuntime),planningStartMode 统一取 master 的派生值(上下文 startMode 为 planning 且未切到 game 运行时)
- ProjectSupervisorView.tsx:props 同时保留本分支 versions/activeVersionId 与 master 的 designView/onDesignApprove/onDesignClarify/onDesignRetry,DesignAgentSurface 审批链路与本分支资源引用输入区并存;directCodex 输入区保留本分支 @ 引用按钮 + 模型选择 + 发送按钮控制条,发送按钮禁用条件并入 master 的 designView 审批待定口径,模型选择沿用 master 的「对话中可切换」口径
- styles.css:本分支追加的资源画布/输入区样式块与 master 追加的 .design-agent-reasoning 样式块都保留,并补上本分支最后一条规则的收尾大括号
- view/project-development/index.tsx:保留本分支的 image-editor 引用(ImageCanvasProjectAssetPickerDialog、ImageCanvasQuickEditPanelView、ImageCanvasSelectedLayerToolbarView、useImageCanvasFloatingOptionDismiss),去掉 master 对已退役 features/asset-canvas 的 import(本分支已由 resource-canvas 取代),保留 master 的 DesignWorkspacePanel 与 planningStartMode 策划工作台分支
- tests/workspaceLauncherManifestMerge.test.tsx:补 master 新引入的 get_design_agent_runtime_mode mock(返回 null,与 master 各套件同口径),拒收提示断言不变
- tests/appSurface/design-agent.suite.ts:审批待定禁用输入的断言改用本分支 Lexical 输入区的禁用口径(容器 data-disabled + editor.setEditable(false)),断言意图不变
- 验证:npm run typecheck 通过;apps/ai-game-creator-shell typecheck 通过;apps/ai-game-creator-shell/tests 96 个测试文件 1380 通过 4 跳过 0 失败;全仓 vitest 297 通过 2 失败(scripts 下两例为 Windows 权限语义导致的既有失败,相关文件与实现均未参与本次合并);npm run check:encoding 与 git diff --check 通过
This commit is contained in:
2026-09-12 17:31:51 +08:00
120 changed files with 12599 additions and 183 deletions
@@ -114,6 +114,7 @@ pub async fn proxy_llm_chat_completions(
.into_iter()
.map(map_chat_message)
.collect::<Vec<_>>(),
responses_input: None,
max_output_tokens: None,
enable_web_search: false,
request_timeout_ms: None,
@@ -48,6 +48,7 @@ pub fn build_gpt5_multimodal_request(
LlmMessage::new(LlmMessageRole::System, system_prompt.into()),
LlmMessage::multimodal(LlmMessageRole::User, user_parts),
],
responses_input: None,
max_output_tokens: None,
request_timeout_ms: None,
enable_web_search: false,
+3 -1
View File
@@ -1,6 +1,6 @@
# platform-llm 平台适配 crate
更新:`2026-08-06`
更新:`2026-09-10`
## 1. crate 职责
@@ -34,6 +34,8 @@
Responses 如果只发送 `response.completed``response.incomplete`,解析器会从其中的 `response.output[]` 恢复 `function_call`;恢复时使用 output 数组下标作为 slot。`response.incomplete` 表示上游没有完成本轮生成:其中的工具调用即使参数是完整 JSON 也返回 `Deserialize`,纯正文则保留为可用的降级结果。三种协议的并行工具调用只在平台层做 slot 聚合,不代表工具会在平台层并发执行。
需要原生工具续轮时,调用 `LlmRunRequest::with_responses_input(Vec<Value>)`,由调用方提供包含当前 system 指令的完整 input,替代 `messages`。该入口固定使用 Responses,并发送 `store=false``include=["reasoning.encrypted_content"]``LlmRunResponse.responses_output` 原样保存非流式 output 数组或流式终态事件的 response.output 数组,包含 reasoning、function_call 和 message;调用方将这些项按顺序追加到历史,并在对应 function_call 后加入同 call_id 的 function_call_output。更换阶段指令时替换 input 中的 system 消息,不依赖 previous_response_id。普通 messages 入口保留原请求参数;其他协议的 responses_output 为空。neutral provider adapter 无法无损表达原生历史,拒绝该输入,使用此入口必须直接调用 LlmClient。
## 4. 流式与参数契约
1. `LlmRunRequest.max_output_tokens` 是协议中立的生成预算,包含可见输出与 Provider 可能使用的隐藏 reasoning token,不包含输入 token,也不保证可见正文长度。Responses 映射为 `max_output_tokens`Anthropic 映射为 `max_tokens`Chat 由 `LlmConfig.openai_chat_token_budget_field` 显式映射为当前 `max_completion_tokens` 或兼容网关旧字段 `max_tokens`,每次只发送一个。默认保留 legacy,已验证支持新字段的 endpoint 必须显式 opt-in;禁止按模型名猜测或收到 `400` 后自动重放。
File diff suppressed because it is too large Load Diff
@@ -327,6 +327,11 @@ pub fn provider_request_from_llm_request(
request_id: &str,
request: LlmRunRequest,
) -> Result<ProviderRequest, ProviderError> {
if request.responses_input.is_some() {
return Err(ProviderError::invalid_request(
"Responses 原生 input 必须通过 LlmClient 发送,neutral adapter 不支持无损映射",
));
}
let messages = request
.messages
.into_iter()
@@ -422,6 +427,7 @@ pub fn llm_response_from_provider_response(
total_tokens: usage.total_tokens(),
}),
tool_calls,
responses_output: Vec::new(),
})
}
@@ -872,6 +878,7 @@ mod tests {
#[test]
fn existing_llm_response_maps_to_neutral_response_identity() {
let response = LlmRunResponse {
responses_output: Vec::new(),
provider: LlmProvider::OpenAiCompatible,
model: "model-1".to_string(),
text: "完成".to_string(),