完成 reasoning 最终回归与验收
补充 Responses reasoning 与工具调用共存回归测试 补充策划 Runtime 重试清理 reasoning 测试 同步 platform-llm README 与策划 Agent 技术方案 记录第五轮验收证据与未验证边界
This commit is contained in:
@@ -1451,6 +1451,38 @@ mod tests {
|
||||
assert!(session.history.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn scripted_design_provider_retry_clears_previous_reasoning_attempt() {
|
||||
let (_temp, root, _resources) = init_design_project();
|
||||
let mut session = new_design_session("design-fake", "quality");
|
||||
begin_design_turn(&mut session, "turn-reasoning-retry");
|
||||
let mut response = fake_response("reasoning-retry", "重试后的正文", Vec::new());
|
||||
response.reasoning = "重试后的推理".into();
|
||||
let _fake = fake_provider::install(
|
||||
vec![
|
||||
Err(platform_llm::LlmError::Upstream {
|
||||
status_code: 503,
|
||||
message: "busy".into(),
|
||||
}),
|
||||
Ok(response),
|
||||
],
|
||||
1,
|
||||
);
|
||||
let mut events = Vec::new();
|
||||
let response =
|
||||
request_scripted_design_provider(&root, &mut session, &mut |event| events.push(event))
|
||||
.await
|
||||
.expect("scripted retry provider");
|
||||
|
||||
let reasoning_events = events
|
||||
.iter()
|
||||
.filter_map(|event| event.reasoning_text.as_deref())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(reasoning_events, vec!["", "", "重试后的推理"]);
|
||||
assert_eq!(response.text, "重试后的正文");
|
||||
assert!(session.history.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn fake_provider_walks_five_phases_and_enters_consultant() {
|
||||
let (_temp, root, resources) = init_design_project();
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# 【实施计划】reasoning 最终回归与验收
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Milestone | `docs/project-memory/plans/【里程碑】Provider推理与正文分离及策划Agent展示-2026-09-14.md` |
|
||||
| Status | awaiting-review |
|
||||
| Owner | Codex |
|
||||
|
||||
## 一句话交付结果
|
||||
|
||||
用确定性回归、文档同步和门禁证据确认 Provider reasoning 旁路不会改变正文、工具调用、GameAgent 或策划会话持久化行为。
|
||||
|
||||
## 修改边界
|
||||
|
||||
本轮只补最终验收所需的测试、当前权威文档和证据记录;不新增协议字段、不扩展真实 Provider、不修改公开 API、SpacetimeDB schema、GameAgent 消费逻辑或 UI 组件。
|
||||
|
||||
## 实施顺序
|
||||
|
||||
1. 核对并补齐 platform-llm 的 reasoning 解析、正文隔离、工具调用共存、默认关闭和解析异常降级测试。
|
||||
2. 核对并补齐策划 Runtime 的 reasoning 事件、重试清理、错误清理和不写入 history 的测试证据。
|
||||
3. 核对 GameAgent、Direct/Codex 与 response stream 只消费正文的回归证据,修正过时的 crate README 语义。
|
||||
4. 更新主技术方案与里程碑状态,整理证据矩阵,运行最终门禁;完成后删除本轮及已完成的临时实施计划。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- Responses 和 Chat 的 reasoning 增量/终态均有确定性测试。
|
||||
- reasoning 永不进入正文、工具参数、正式 assistant message 或策划 history。
|
||||
- reasoning 与工具调用共存、无 reasoning 默认行为、reasoning 解析异常降级均有证据。
|
||||
- 策划 Runtime 的新回合、重试、项目切换和失败路径不会残留旧 reasoning。
|
||||
- GameAgent、Direct/Codex 和 response stream 的正文回归通过。
|
||||
- `cargo test`、`cargo check`、TypeScript、文档索引、编码和 diff 门禁通过;真实 Provider smoke 明确记录为未验证。
|
||||
|
||||
## 风险与回滚点
|
||||
|
||||
- 若补测试暴露正文或工具回归,优先回退调用方接线,不改变默认关闭契约。
|
||||
- 若文档与实现不一致,以源码和测试为准同步修正文档。
|
||||
- 真实 Provider 未连接时不宣称端到端协议 fidelity,只报告固定 fixture 和单元测试证据。
|
||||
|
||||
## 本轮验收证据
|
||||
|
||||
| 证据 | 结果 |
|
||||
| --- | --- |
|
||||
| `cargo test --manifest-path server-rs/Cargo.toml -p platform-llm` | PASS,152 个单元测试;1 个真实 Provider smoke 按需 `#[ignore]` |
|
||||
| `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell design_runtime` | PASS,10 个策划 Runtime 测试 |
|
||||
| `cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --tests` | PASS,既有编译警告未升级为错误 |
|
||||
| `npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit` | PASS |
|
||||
| `cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check`、AGC Tauri 同命令 | PASS |
|
||||
| `npm run check:encoding`、`npm run check:doc-index`、`git diff --check` | PASS |
|
||||
|
||||
未验证项:真实 Provider 和浏览器运行时 smoke;`ai-game-creator-shell:typecheck` 中的 `check-config.mjs` 仍受当前 Windows 沙箱私有 DACL 限制,已用独立 TypeScript 检查替代类型门禁。
|
||||
@@ -3,7 +3,7 @@
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| Version | 1.0 |
|
||||
| Status | proposed |
|
||||
| Status | awaiting-review |
|
||||
| Date | 2026-09-14 |
|
||||
| Parent Spec | `docs/technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md` |
|
||||
| Related Issue | `GenarrativeAI/Genarrative#331` |
|
||||
@@ -131,6 +131,20 @@ Responses 的原生 output 仍按当前方式保留,用于后续 Responses 会
|
||||
- 策划 Runtime 事件映射和 UI 生命周期;
|
||||
- GameAgent 正文与工具调用回归。
|
||||
|
||||
## 第五轮验收证据
|
||||
|
||||
| 验收面 | 证据 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| Chat / Responses reasoning 解析 | `cargo test --manifest-path server-rs/Cargo.toml -p platform-llm` | PASS,152 个单元测试;含字段、content part、SSE 增量、终态快照和正文隔离 |
|
||||
| reasoning 与工具调用共存 | `responses_response_captures_reasoning_alongside_tool_call`、既有 Chat/Responses 流式工具测试 | PASS |
|
||||
| 默认关闭与请求兼容 | `run_request_defaults_to_openai_responses_api_kind`、`reasoning_capture_switch_does_not_change_provider_request_body` | PASS |
|
||||
| 策划 Runtime 生命周期 | `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell design_runtime` | PASS,10 个测试;含事件映射、history 隔离、重试清理和失败清理 |
|
||||
| GameAgent / Direct/Codex 正文回归 | `cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --tests` 与现有 response stream / direct tests 编译 | PASS;新增字段未进入正文消费路径 |
|
||||
| 前端与文档门禁 | `npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` | PASS |
|
||||
| 格式门禁 | `cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check`、AGC Tauri 同命令 | PASS |
|
||||
|
||||
真实 Provider、浏览器运行时 smoke 和 `check-config.mjs` 的 Windows 私有 DACL 路径本轮未验证;前者需要凭据和运行环境,后者受当前沙箱权限限制,不能据此扩大验收结论。
|
||||
|
||||
## 契约与持久化策略
|
||||
|
||||
- 不修改 HTTP API、OpenAPI、SpacetimeDB schema 或生成绑定。
|
||||
|
||||
@@ -346,8 +346,8 @@ UI 使用“批准”和“继续修改”两个文字按钮,分别配 Lucide
|
||||
|
||||
开发构建的策划工作区页头在“刷新”旁提供“快速准备做成游戏测试”按钮。该入口与策划 Debug 日志共用 `GENARRATIVE_AGC_DESIGN_DEBUG=1` 开关:开关未启用时按钮不显示,命令也不可执行。入口仅进行本地 fixture 和会话状态写入,不调用 Provider;完成后自动刷新文件树与阶段,通过 `design-agent-update` 状态事件同步右侧审批/阶段操作区。随后仍需点击正常的“做成游戏”按钮执行资产登记与运行时切换。
|
||||
|
||||
## 15. 策划 Agent reasoning 展示现状
|
||||
## 15. 策划 Agent reasoning 展示
|
||||
|
||||
右侧栏已预留策划 Agent 的 `reasoningText` 事件字段和默认折叠的展示样式,但当前 Provider 解析链仍会过滤 reasoning 内容,尚未向策划 Runtime 产出该字段。因此现阶段只展示用户可见正文和工具状态;reasoning 折叠区在没有数据时不会出现。
|
||||
策划 Agent 的 Provider 请求显式开启 `capture_reasoning`,共享 `platform-llm` 将 Chat / Responses 的 reasoning 通过独立字段旁路传递,策划 Runtime 映射为已有 `DesignEvent.reasoningText`,前端复用右侧栏默认折叠的思考过程展示。正文、工具调用参数、正式 assistant message 和会话 history 继续使用原有字段;GameAgent、Direct/Codex 与通用 response stream 保持只消费正文的行为。
|
||||
|
||||
后续若补充 reasoning,需要在策划 Agent 专用 Provider 解析层接入,不能直接修改共享 Provider 以免影响 GameAgent。
|
||||
reasoning 捕获默认关闭。新回合和 Provider 重试会先清空同一响应槽的临时 reasoning,失败路径也会清理,避免旧内容残留。该能力不新增公开 API、SpacetimeDB 字段或独立 UI 组件。
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
2. `OpenAiChat`、`OpenAiResponses` 与 `Anthropic` 三类 API kind 都支持 JSON 请求、非流式响应和 SSE 流式响应;默认 API kind 仍为 `OpenAiResponses`。
|
||||
3. 三类协议都使用统一的 `function_tools` / `tool_choice` 输入和 `LlmRunResponse.tool_calls` 输出。Anthropic 请求使用顶层 `tools[].input_schema` 与对象形态 `tool_choice`;Anthropic URL 默认在 base URL 后拼 `/v1/messages`,如果 base URL 已以 `/v1` 结尾则只拼 `/messages`。
|
||||
4. Anthropic 当前仍不支持 `web_search`、图片内容和纯 system 消息;至少需要一条非 system 文本消息。角色动画、图片、视频、资产轮询仍留在其他平台适配和业务模块任务里。
|
||||
5. 流式 `on_delta` 只发送文本增量与完成原因;工具调用增量在 crate 内按 slot 聚合,完整调用只从最终 `LlmRunResponse.tool_calls` 读取。上下文管理、后台执行和业务状态不写回本 crate。
|
||||
5. 流式 `on_delta` 发送正文增量、可选的独立 reasoning 增量与完成原因;reasoning 只有在 `LlmRunRequest.capture_reasoning=true` 时才累计,默认关闭。工具调用增量在 crate 内按 slot 聚合,完整调用只从最终 `LlmRunResponse.tool_calls` 读取。reasoning 不进入 `delta_text`、`accumulated_text`、正式 assistant message 或工具参数;上下文管理、后台执行和业务状态不写回本 crate。
|
||||
6. 支持按 provider 打标签,但不把业务 prompt、SSE 转发和模块状态写回本 crate。
|
||||
7. `DashScope` 当前只通过“调用方显式提供兼容文本网关 base url”的方式接入,不复用图像 API。
|
||||
8. 角色动画、图片、视频、资产轮询仍留在后续 `platform-llm` / `platform-oss` / 业务模块任务里另行实现。
|
||||
|
||||
@@ -5332,6 +5332,8 @@ mod tests {
|
||||
.expect("tool call should keep the response valid without visible content");
|
||||
|
||||
assert_eq!(response.text, "");
|
||||
assert!(response.reasoning.is_empty());
|
||||
assert_eq!(response.tool_calls.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -5406,6 +5408,28 @@ mod tests {
|
||||
assert_eq!(response.reasoning, "先判断。再回答。");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn responses_response_captures_reasoning_alongside_tool_call() {
|
||||
let response = parse_responses_response_with_capture(
|
||||
LlmProvider::OpenAiCompatible,
|
||||
"fallback-model",
|
||||
true,
|
||||
r#"{"id":"resp_reasoning_tool","output":[{"type":"reasoning","summary":[{"type":"summary_text","text":"先分析工具需求。"}]},{"type":"message","content":[{"type":"output_text","text":"我先查询。"}]},{"type":"function_call","call_id":"call_lookup","name":"lookup","arguments":"{\"query\":\"项目\"}"}],"status":"completed"}"#,
|
||||
)
|
||||
.expect("Responses reasoning plus tool call should parse");
|
||||
|
||||
assert_eq!(response.text, "我先查询。");
|
||||
assert_eq!(response.reasoning, "先分析工具需求。");
|
||||
assert_eq!(
|
||||
response.tool_calls,
|
||||
vec![LlmToolCall {
|
||||
id: "call_lookup".to_string(),
|
||||
name: "lookup".to_string(),
|
||||
arguments: r#"{"query":"项目"}"#.to_string(),
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_events_capture_reasoning_delta_and_terminal_snapshot() {
|
||||
let chat = parse_sse_event_block(
|
||||
|
||||
Reference in New Issue
Block a user