deerflow2/.planning/phases/07-phase-06-mention-upload/07-01-PLAN.md

212 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
phase: 07-phase-06-mention-upload
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- frontend/src/components/workspace/input-box.tsx
- frontend/src/core/threads/hooks.ts
- frontend/src/components/ai-elements/prompt-input.tsx
- frontend/src/components/workspace/messages/message-list-item.tsx
- frontend/src/core/i18n/locales/zh-CN.ts
- frontend/src/core/i18n/locales/en-US.ts
- frontend/src/core/i18n/locales/types.ts
- frontend/src/core/threads/hooks.test.ts
- frontend/tests/e2e/input-and-compose.spec.ts
autonomous: true
requirements:
- P7-01
- P7-02
- P7-03
- P7-04
must_haves:
truths:
- "发送到后端的文本会拼接优先使用…附件和…Skill但消息区仅展示用户原文。"
- "拼接规则固定附件在前、Skill在后单类单出大小写不敏感去重。"
- "按钮发送、回车发送、建议词自动发送三条入口行为一致。"
artifacts:
- path: "frontend/src/core/threads/hooks.ts"
provides: "提交态增强文本与展示态原文分离"
contains: "payload text composition"
- path: "frontend/src/components/workspace/input-box.tsx"
provides: "references + selectedSkills 元数据传递"
contains: "handleSubmit"
- path: "frontend/src/components/workspace/messages/message-list-item.tsx"
provides: "人类消息渲染仍以原文为准"
contains: "contentToDisplay"
key_links:
- from: "frontend/src/components/workspace/input-box.tsx"
to: "frontend/src/core/threads/hooks.ts"
via: "PromptInputMessage 扩展字段"
pattern: "selectedSkills/references -> payload composition"
- from: "frontend/src/core/threads/hooks.ts"
to: "frontend/src/components/workspace/messages/message-list-item.tsx"
via: "optimistic content + persisted display consistency"
pattern: "original text only"
---
<objective>
实现 Phase 7 决策:发送时将附件与 Skill 提示文案拼接进提交给后端的提示词,但消息区不展示拼接内容。
Purpose: 在不破坏既有 `additional_kwargs.files` 语义和输入体验的前提下,增强模型侧提示优先级。
Output: 形成稳定的“提交态增强文本/展示态原文”链路,并由单测 + E2E 回归覆盖。
</objective>
<execution_context>
@/home/mt/.codex/get-shit-done/workflows/execute-plan.md
@/home/mt/.codex/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/REQUIREMENTS.md
@.planning/STATE.md
@.planning/phases/07-phase-06-mention-upload/07-CONTEXT.md
@.planning/phases/07-phase-06-mention-upload/07-RESEARCH.md
@.planning/phases/07-phase-06-mention-upload/07-VALIDATION.md
@frontend/src/components/workspace/input-box.tsx
@frontend/src/core/threads/hooks.ts
@frontend/src/components/ai-elements/prompt-input.tsx
@frontend/src/components/workspace/messages/message-list-item.tsx
@frontend/tests/e2e/input-and-compose.spec.ts
<interfaces>
From frontend/src/components/ai-elements/prompt-input.tsx:
```typescript
export type PromptInputMessage = {
text: string;
files: FileUIPart[];
references?: PromptInputReference[];
};
```
From frontend/src/core/threads/hooks.ts:
```typescript
const sendMessage = async (threadId: string | undefined, message: PromptInputMessage) => {
const text = message.text.trim();
// optimistic human message + submit payload
};
```
From frontend/src/components/workspace/input-box.tsx:
```typescript
onSubmit?.({ ...message, references });
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: 设计并接入“提交态增强文本”组装器</name>
<files>frontend/src/core/threads/hooks.ts, frontend/src/components/ai-elements/prompt-input.tsx</files>
<read_first>
- .planning/phases/07-phase-06-mention-upload/07-CONTEXT.md
- frontend/src/core/threads/hooks.ts
- frontend/src/components/ai-elements/prompt-input.tsx
- frontend/src/core/threads/submit-files.ts
</read_first>
<action>
扩展 `PromptInputMessage` 以承载发送时需要的 Skill 名列表(例如 `selectedSkills?: Array<{ title: string }>`),并在 `hooks.ts` 中新增纯函数组装器:输入原文、附件名集合(上传文件名 + references 文件名、Skill 名集合输出“提交态增强文本”。规则必须写死为附件在前、Skill在后、单类单出、大小写不敏感去重、空集合不拼接。拼接模板使用 `优先使用【...】和【...】`。保持 `additional_kwargs.files` 现有逻辑不变,不新建并行 envelope。
</action>
<acceptance_criteria>
- `PromptInputMessage` 新增可选 Skill 元数据字段,类型定义与调用点一致。
- `hooks.ts` 存在独立组装函数,且可单测验证 4 条决策规则(顺序、单类单出、去重、空值)。
-`buildFilesForSubmit``additional_kwargs.files` 流程未被改写为新结构。
</acceptance_criteria>
<verify>
<automated>cd frontend && rg -n "selectedSkills\?:|build.*Priority|优先使用【" src/components/ai-elements/prompt-input.tsx src/core/threads/hooks.ts</automated>
<automated>cd frontend && pnpm -s test -- --run src/core/threads/hooks.test.ts</automated>
</verify>
<done>提交链路具备可复用的“增强文本组装器”,且不破坏现有文件提交协议。</done>
</task>
<task type="auto">
<name>Task 2: InputBox 透传引用与 Skill 元数据,统一三类发送入口</name>
<files>frontend/src/components/workspace/input-box.tsx, frontend/src/app/workspace/chats/[thread_id]/page.tsx</files>
<read_first>
- .planning/phases/07-phase-06-mention-upload/07-CONTEXT.md
- frontend/src/components/workspace/input-box.tsx
- frontend/src/app/workspace/chats/[thread_id]/page.tsx
- frontend/src/hooks/use-iframe-skill.ts
</read_first>
<action>
`InputBox.handleSubmit` 中把当前 `references` 与已选 `selectedSkills` 一并传给 `onSubmit` 消息对象,确保按钮发送、回车发送、建议词自动发送都经过同一条 `requestSubmit -> handleSubmit` 链路,避免分支漏传。禁止直接修改 textarea 展示文本来承载拼接文案;输入框显示始终保持用户原文。
</action>
<acceptance_criteria>
- `onSubmit` 入参中包含 `references``selectedSkills`,且类型安全。
- `handleFollowupClick/confirmReplaceAndSend/confirmAppendAndSend` 最终提交均走相同 `handleSubmit` 透传逻辑。
- 输入框展示值不被拼接文案污染。
</acceptance_criteria>
<verify>
<automated>cd frontend && rg -n "selectedSkills|onSubmit\?\(\{\.\.\.message" src/components/workspace/input-box.tsx</automated>
<automated>cd frontend && pnpm -s test -- --run src/components/workspace/input-box</automated>
</verify>
<done>所有发送入口都带齐元数据并保持展示态原文。</done>
</task>
<task type="auto">
<name>Task 3: 保证消息区仅展示原文并补齐回归</name>
<files>frontend/src/core/threads/hooks.ts, frontend/src/components/workspace/messages/message-list-item.tsx, frontend/tests/e2e/input-and-compose.spec.ts, frontend/src/core/i18n/locales/zh-CN.ts, frontend/src/core/i18n/locales/en-US.ts, frontend/src/core/i18n/locales/types.ts</files>
<read_first>
- .planning/phases/07-phase-06-mention-upload/07-CONTEXT.md
- frontend/src/core/threads/hooks.ts
- frontend/src/components/workspace/messages/message-list-item.tsx
- frontend/tests/e2e/input-and-compose.spec.ts
- frontend/src/core/i18n/locales/zh-CN.ts
- frontend/src/core/i18n/locales/en-US.ts
- frontend/src/core/i18n/locales/types.ts
</read_first>
<action>
`sendMessage` 中区分 `displayText`(原文)与 `submitText`(原文+拼接文案optimistic human message 和消息渲染侧使用 `displayText`,提交给 `thread.submit` 使用 `submitText`。若后端回流的人类消息可能带拼接文案,则在渲染层加最小且明确的剥离逻辑(仅剥离本阶段固定模板尾段),但不得依赖宽泛正则误伤用户内容。新增 i18n 文案键用于提示拼接规则相关错误(若需要)。补 E2E断言发送后消息区不出现“优先使用【”片段同时请求提交内容包含拼接片段可通过拦截请求或 mock 验证)。
</action>
<acceptance_criteria>
- 发送请求文本包含拼接文案;消息区可见文本不包含拼接文案。
- 附件/Skill 名拼接顺序与去重规则符合 D-01~D-10。
- 新增回归测试覆盖“显示态与提交态分离”主路径。
</acceptance_criteria>
<verify>
<automated>cd frontend && pnpm -s test -- --run src/core/threads/hooks.test.ts</automated>
<automated>cd frontend && pnpm -s test:e2e --grep "优先使用|input|compose"</automated>
<automated>cd frontend && pnpm -s typecheck</automated>
</verify>
<done>端到端满足“拼接给模型但不展示给用户”的核心目标。</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| 输入框展示态 → 提交态 payload | 同一条用户消息在展示与提交存在双态,若处理不当会造成信息泄露或行为不一致。 |
| 前端组装器 → 后端存档消息 | 拼接文案若回流到历史消息,会暴露内部引导提示并污染用户可见记录。 |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-07-01 | I | `frontend/src/core/threads/hooks.ts` | mitigate | 明确区分 `displayText`/`submitText`,并通过测试验证消息区不回显拼接文本。 |
| T-07-02 | T | `frontend/src/components/workspace/input-box.tsx` | mitigate | 强制三入口走同一提交链路,避免某入口漏传 references/skills 造成规则绕过。 |
| T-07-03 | R | `frontend/tests/e2e/input-and-compose.spec.ts` | mitigate | 增加请求拦截断言,确保“显示态/提交态分离”可审计、可回归。 |
</threat_model>
<verification>
- `cd frontend && pnpm -s lint`
- `cd frontend && pnpm -s typecheck`
- `cd frontend && pnpm -s test -- --run src/core/threads/hooks.test.ts`
- `cd frontend && pnpm -s test:e2e --grep "input|compose|优先使用"`
</verification>
<success_criteria>
- 拼接模板与数据口径完全符合 1A/2A/3A/4A 决策。
- 消息区不展示拼接附加文本,且不影响现有附件/引用渲染。
- 三类发送入口行为一致并被自动化回归覆盖。
</success_criteria>
<output>
After completion, create `.planning/phases/07-phase-06-mention-upload/07-01-SUMMARY.md`
</output>