diff --git a/.project-docs/30-worklog/tasks/20260928-teacher-reply-cleanup-c8e4a219.md b/.project-docs/30-worklog/tasks/20260928-teacher-reply-cleanup-c8e4a219.md index f3aec683..2bbf2889 100644 --- a/.project-docs/30-worklog/tasks/20260928-teacher-reply-cleanup-c8e4a219.md +++ b/.project-docs/30-worklog/tasks/20260928-teacher-reply-cleanup-c8e4a219.md @@ -8,7 +8,7 @@ - Worktree: /Users/chillishark/Makelore 麦洛/.codex-worktrees/makelore-teacher-reply-cleanup - Base commit: ae0f72d8fa0089f87b41d272da220e1c1397aec8 - Owner: codex -- Status: Ready for Integration +- Status: In progress ## Scope @@ -115,3 +115,11 @@ - Verified same login/account/project/conversation/route, operation drafts, composer values and all persisted consultation draft text/references/pending payloads. One persisted absent pending field normalizes to null on mount; semantic comparison confirms no draft content or request identity was lost. Runtime verification contains only boolean/style/build metadata, no draft bodies or credentials. Temporary Main-memory backup and inspector removed. - Foreground monitor: trialFocused=false, unchanged foreground PID 88503. No show/focus calls were needed. Local trial metadata and next-launch bootstrap updated; production app untouched. No cloud publication, deliberate model test request, main merge or push. - Documentation structure and whitespace checks pass; the task-aware drift diagnostic remains limited to the unchanged imported manual-refresh task record described above, reconfirmed identical to 4f6bda4. + +## Visible Hint Clarification + +- User could not see the prior rename. Read-only runtime inspection confirmed the new build was loaded but no failed/cancelled request was currently displayed; the visible empty-composer entry still said “给我一点提示”. Explained the distinction and user explicitly confirmed to rename/style the composer entry too. +- Same task identity/ownership resumed and verified; reuse this follow-up's loaded project/peer context with no new conflict. User clarification supersedes the earlier preference for a transparent text hint. Plan: share the warm sticker styling between hint and retry, send the matching new label through the existing suggestions intent, preserve empty/type/clear behavior and legacy pending-payload reuse. Increase the reserved action-row height to 44px so the send control remains still. Update existing tests and preview with a background Renderer refresh. No backend or cloud-policy change. + +- Implemented shared hint/retry sticker styling and exact “继续看看👀” composer label/payload. The hint still hides on nonempty input; reserved 44px action height keeps the send button fixed. Existing request identity reuse covers both former labels (“帮我看看” and “给我一点提示”), without changing saved history. +- Verification passed: typecheck, full lint plus final test-file lint, production build, 59 UI tests and 15 headless browser checks. Existing tests distinguish the two same-label controls by composer/reply location. Screenshots at 319/508px show the visible empty-composer button and confirm no clipping or send-button movement. Shared native E2E assertions updated without launching a native test app. diff --git a/README.md b/README.md index 4dd1dab7..5e09cd5d 100644 --- a/README.md +++ b/README.md @@ -174,9 +174,9 @@ Pi 正式包必须继续运行 `pnpm run verify:artifact:pi`、`pnpm run smoke:p - 主动发言采用紧贴小头像的短气泡;只有存在真实主动消息或运营欢迎语时才显示这组浮层,收起消息时头像和气泡一起消失,顶部入口仍保留。长消息在气泡中最多显示三行,点击接回原智能体对话查看全文。不提供“智能体偶尔来看看”开关或本地模拟巡看控制,既有自动跟进与真实消息接收逻辑保留。作品原生预览对整组气泡和头像测量避让,避免图片被原生页面遮住。 - 学生在当前项目创作时,前端每 5 分钟请求一次智能体跟进;窗口隐藏、来源归档、主对话正在执行、智能体正在回复或学生正在智能体栏写草稿时延后。Main 再检查在线启停、来源归属、项目级冷却和已完成文本指纹,未变上下文按下述十五分钟冷却处理。跟进沿用运营模型、已发布 Skills 与当前智能体话题,生成符合所选配置的具体建议或引导;以主动智能体发言持久化,不伪造学生消息。模型调用沿用智能体计费规则。 - 进入项目时,智能体头像旁先显示运营发布的欢迎语气泡,不调用模型、不声称已检查项目;每个账号/项目主动收起后不重复弹出。真实的未读主动建议优先替换欢迎语。主动发言在头像旁直接显示气泡,不抢焦点、不盖住作品;作品区按气泡与原生预览的实际交叠范围避让,已有工具栏高度计入计算,气泡位于独立智能体栏时不额外留白,窗口/分栏尺寸变化和收起气泡时实时归还空间;“和智能体聊聊”接回同一段咨询,“等会儿聊”收起并保留历史。已有未处理气泡时不堆叠新邀请;咨询已展开时也显示气泡,直到学生主动点击查看或收起,期间的其他回复不会吞掉未读邀请。五分钟检查计时在刷新和项目切换后保留;智能体咨询里的新讨论也算进展,即使操作对话没有变化也会继续跟进;上下文完全未变时放缓到十五分钟一次,不永久停止。事件连接丢失时,每十五秒只读同步未完成回复,收到结果后停止轮询,不重复调用模型。失败如实提示,不以本地文案替代模型回复。已接受请求恢复使用原身份,退出账号和来源删除仍沿用 Main 中止边界。 -- 智能体支持自由提问;输入框为空时,底部显示轻量文字入口“给我一点提示”,输入文字后收起,清空后重现,发送按钮保持原位。只有学生点击才调用模型,结合当前操作对话与咨询历史推荐一个具体切入点,并生成围绕它的快捷回复。点击快捷回复会主动开始讨论;回复下方不再附加固定的二次求助链接;失败或中断后,可点暖黄色小按钮“继续看看👀”重试。这些快捷求助保留已有输入草稿,网络结果不确定时复用请求身份,已确认终态的请求不重复执行;解析失败可重新求助,不用固定问题伪装模型结果。服务端下发的推荐问题只填入草稿,由用户确认发送。界面不提供独立示范页面、“记一下”、共识或自动待办,智能体的回复下不再展示“我去试一试”和“复制”按钮,学生通过已有的操作对话/作品入口继续创作。 +- 智能体支持自由提问;输入框为空时,底部显示暖黄色小按钮“继续看看👀”,输入文字后收起,清空后重现,发送按钮保持原位。只有学生点击才调用模型,结合当前操作对话与咨询历史推荐一个具体切入点,并生成围绕它的快捷回复。点击快捷回复会主动开始讨论;回复下方不再附加固定的二次求助链接;失败或中断后,可点暖黄色小按钮“继续看看👀”重试。这些快捷求助保留已有输入草稿,网络结果不确定时复用请求身份,已确认终态的请求不重复执行;解析失败可重新求助,不用固定问题伪装模型结果。服务端下发的推荐问题只填入草稿,由用户确认发送。界面不提供独立示范页面、“记一下”、共识或自动待办,智能体的回复下不再展示“我去试一试”和“复制”按钮,学生通过已有的操作对话/作品入口继续创作。 - 老师咨询只展示老师正文和可点击的快捷回复卡片,学生也可在“和老师聊聊”输入框自由输入。点击卡片原样发送该回复,保留当前输入草稿;旧话题的数据不会恢复想法板、结构图、流程图或对照表及其操作。 -- “给我一点提示”由老师结合项目推荐一个具体切入点,快捷回复围绕这个切入点帮助学生接话;客户端不要求多个独立话题,也不固定正文长度、选项数量、前缀或表达风格。老师继续依据已配置职责帮助孩子整理想法、理解关系和承接已确认的共识,区分建议与已确认内容。 +- “继续看看👀”由老师结合项目推荐一个具体切入点,快捷回复围绕这个切入点帮助学生接话;客户端不要求多个独立话题,也不固定正文长度、选项数量、前缀或表达风格。老师继续依据已配置职责帮助孩子整理想法、理解关系和承接已确认的共识,区分建议与已确认内容。 - Main 对咨询回复统一使用 `{reply, quickReplies}`,本地读取工具的前言和云端非最终片段不当作最终回答;完整解析后展示正文和卡片,主动进展提醒仍直接展示正文。普通 Markdown、JSON 数据和代码示例保持正文。兼容读取旧 `{intro, questions}` 和带 `tool` 的回复,只提取正文与快捷回复,不恢复或更新组件。资源上限只用于防护,不做旧式字数截断;格式错误保留可读正文及原始回答,原文默认折叠、字面显示,不再次送进模型。 - 咨询正文支持 Markdown 标题、列表、表格、代码围栏、HTTP(S) 链接/图片和数学公式,长代码与表格在栏内横向滚动,不执行 HTML。云端正文维持 string 合同,未知对象不会猜测转成回答。工具活动只从云端主线程的类型化工具事件及 Main 本地读取过程获得,按本次问题/工具调用身份合并名称和状态,跨云端暂停、续接仍只计一次;暂停读取不算失败,状态以实际读取结果或问题终态为准,单独折叠显示;参数、结果原文和内部错误不混入回复,思考内容不作为正文。客户端仅保存自己实际收到的工具状态,不能补回旧历史或断线期间已经过期的事件。 - 云端咨询在 local_context 声明 read_protocol=2;需先部署配套 Yuxi API 和 worker,再升级客户端。云端持久累计读取字节及批次,每轮告知模型剩余额度;预算耗尽后消费最后一批结果,并以 tool_choice=none 要求根据现有证据形成答案和说明缺口。Main 限制实际返回量并拒绝第十三批读取,区分读取达到上限、上下文失效及格式无效。服务端对未声明协议的已安装旧客户端保留原工具参数与六批边界。 diff --git a/src/pages/Chat/TeacherChatPanel.tsx b/src/pages/Chat/TeacherChatPanel.tsx index 49eea574..8402a7ee 100644 --- a/src/pages/Chat/TeacherChatPanel.tsx +++ b/src/pages/Chat/TeacherChatPanel.tsx @@ -355,7 +355,7 @@ export function TeacherChatPanel({ (request) => request.status === 'preparing' || request.status === 'running' ); const helpUnavailable = busy || !topicEnabled || Boolean(running); - const askForSuggestions = () => void send({ text: '给我一点提示', intent: 'suggestions' }); + const askForSuggestions = () => void send({ text: '继续看看👀', intent: 'suggestions' }); const changeText = (next: string) => { setText(next); persistDraft(next, references, pending.current); }; const removeReferences = () => { setReferences([]); persistDraft(text, [], pending.current); }; const questions = definition?.suggested_questions ?? []; @@ -444,9 +444,9 @@ export function TeacherChatPanel({