# 创作 Agent 流式失败保留可见回复修复 2026-05-05 ## 1. 问题 方洞挑战等轻量玩法复用 `usePlatformCreationAgentFlowController` 与 `creationAgentSse.ts` 消费 `reply_delta / session / error`。当上游 LLM 已经返回部分 `replyText`,但后续因为超时、上游断流、SSE 解析或最终 JSON 解析失败而发送 `error` 事件时,前端会在 `finally` 里退出流式态。 旧 UI 只在 `isStreamingReply=true` 时展示临时 assistant 气泡,因此用户会先看到一段回答,然后回答突然消失,只剩错误提示。 ## 2. 目标 1. 已经展示给用户的流式回复不能因为最终失败从聊天区消失。 2. SSE `error` 仍然终止本轮提交,并保留错误提示。 3. 后端错误不能只压成 `上游服务请求失败`,应优先把 LLM 流错误原因放到业务 `message`。 4. 不修改 SpacetimeDB schema、消息表结构或玩法运行规则。 ## 3. 前端契约 `readCreationAgentSessionFromSse()` 在收到 `reply_delta` 后再收到 `error` 时,必须先触发 `onUpdate(text)`,再抛出错误。调用方可以从最近一次可见文本中恢复 UI。 `usePlatformCreationAgentFlowController.submitMessage()` 的失败收尾规则: 1. 提交时仍先追加 optimistic user message。 2. 每次 `onUpdate` 同步更新 `streamingReplyText` 与最近可见回复引用。 3. 如果 `streamMessage()` 抛错且最近可见回复非空,把该文本追加为本地 assistant `warning` 消息。 4. 再设置 `error`,最后关闭 `isStreamingReply`。 5. 成功拿到最终 session 时,以后端 session snapshot 为准,并清空最近可见回复。 这条本地 `warning` 消息只用于失败态 UI 保留,不代表该 assistant 消息已经写入 SpacetimeDB。 ## 4. 后端契约 `creation_agent_llm_turn` 在 `LlmClient::stream_text()` 失败时,返回: ```text <玩法 generation_failed 文案>: ``` 同时写 `warn` 日志,便于结合 `logs/llm-raw` 定位上游原始输入输出。 方洞挑战 SSE 错误提取优先级: 1. `error.details.message` 2. `error.message` 3. 其它嵌套 JSON message 4. 原始 body 文本 5. 状态码兜底 ## 5. 验收 1. `reply_delta` 后收到 `error` 时,测试应断言 `onUpdate` 已经收到可见文本。 2. 控制器测试应断言失败后本地消息列表包含 user 消息和 assistant warning 消息。 3. `cargo check -p api-server` 通过。 4. `npm run typecheck` 与编码检查通过。