deerflow2/.planning/phases/06-/06-01-PLAN.md

179 lines
7.6 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: 06-
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- frontend/src/core/messages/utils.ts
- frontend/src/components/ai-elements/prompt-input.tsx
- frontend/src/core/threads/hooks.ts
- frontend/src/core/threads/hooks.test.ts
autonomous: true
requirements:
- ATREF-03
must_haves:
truths:
- "用户发送带文件引用的消息后,消息体仍通过 additional_kwargs.files 传输,不新增并行主结构。"
- "引用文件在提交结构中可区分来源与类型,且不破坏现有文件渲染链路。"
- "引用项失效时会被自动剔除并提示,但文本消息仍可发送。"
artifacts:
- path: "frontend/src/core/messages/utils.ts"
provides: "FileInMessage 扩展字段(引用来源/类型)与兼容解析"
- path: "frontend/src/components/ai-elements/prompt-input.tsx"
provides: "PromptInputMessage 新增引用文件字段契约"
- path: "frontend/src/core/threads/hooks.ts"
provides: "上传文件与引用文件合并提交到 additional_kwargs.files"
- path: "frontend/src/core/threads/hooks.test.ts"
provides: "提交结构与软失败行为的单元测试"
key_links:
- from: "frontend/src/components/ai-elements/prompt-input.tsx"
to: "frontend/src/core/threads/hooks.ts"
via: "PromptInputMessage.references"
pattern: "references"
- from: "frontend/src/core/threads/hooks.ts"
to: "frontend/src/core/messages/utils.ts"
via: "FileInMessage 扩展字段"
pattern: "additional_kwargs:\\s*\\{\\s*files"
---
<objective>
先定义并落地“引用文件提交契约”,确保 Phase 6 的数据链路稳定可回归。
Purpose: 把最难回滚的协议与提交流程先锁定,避免后续 UI 实现完成后才发现协议不兼容。
Output: 扩展后的消息类型、提交流程、以及针对合并/软失败的自动化测试。
</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/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/06-/06-CONTEXT.md
@.planning/phases/06-/06-RESEARCH.md
@.planning/phases/06-/06-VALIDATION.md
@frontend/src/components/ai-elements/prompt-input.tsx
@frontend/src/core/messages/utils.ts
@frontend/src/core/threads/hooks.ts
@frontend/src/core/threads/hooks.test.ts
</context>
<interfaces>
From `frontend/src/components/ai-elements/prompt-input.tsx`:
```typescript
export type PromptInputMessage = {
text: string;
files?: FileUIPart[];
};
```
From `frontend/src/core/messages/utils.ts`:
```typescript
export interface FileInMessage {
filename: string;
size: number;
path?: string;
status?: "uploading" | "uploaded";
}
```
From `frontend/src/core/threads/hooks.ts`:
```typescript
const filesForSubmit: FileInMessage[] = uploadedFileInfo.map(...)
await thread.submit({
messages: [{ type: "human", additional_kwargs: { files: filesForSubmit } }],
});
```
</interfaces>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: 扩展引用文件契约并写 RED 测试</name>
<files>frontend/src/core/messages/utils.ts, frontend/src/components/ai-elements/prompt-input.tsx, frontend/src/core/threads/hooks.test.ts</files>
<read_first>
- frontend/src/core/messages/utils.ts
- frontend/src/components/ai-elements/prompt-input.tsx
- frontend/src/core/threads/hooks.test.ts
- .planning/phases/06-/06-CONTEXT.md
</read_first>
<behavior>
- Test 1: `PromptInputMessage` 支持 `references` 字段,类型可表达 `artifact|upload` 来源per D-06
- Test 2: `FileInMessage` 支持可选 `ref_kind/ref_source` 元数据且旧字段保持可用per D-05, D-06
</behavior>
<action>`PromptInputMessage` 新增 `references` 数组字段;在 `FileInMessage` 增加 `ref_kind: "mention"``ref_source: "artifact" | "upload"` 可选字段;先在 `hooks.test.ts` 新增失败用例,断言提交 payload 含 `additional_kwargs.files[*].ref_kind/ref_source` 且不删除已有 `filename/size/path/status` 字段(按 D-05、D-06</action>
<acceptance_criteria>
- `rg -n "references\\?:" frontend/src/components/ai-elements/prompt-input.tsx` 返回至少 1 行。
- `rg -n "ref_kind|ref_source" frontend/src/core/messages/utils.ts` 返回至少 2 行。
- 新增测试在实现前失败RED失败信息包含 `ref_kind``ref_source` 字样。
</acceptance_criteria>
<verify>
<automated>cd frontend && node --test src/core/threads/hooks.test.ts</automated>
</verify>
<done>类型契约完成并有可复现的失败测试,明确约束提交结构。</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: 在线程提交链路合并上传文件与引用文件并实现软失败</name>
<files>frontend/src/core/threads/hooks.ts, frontend/src/core/threads/hooks.test.ts</files>
<read_first>
- frontend/src/core/threads/hooks.ts
- frontend/src/core/threads/hooks.test.ts
- frontend/src/core/uploads/api.ts
- .planning/phases/06-/06-CONTEXT.md
- .planning/phases/06-/06-RESEARCH.md
</read_first>
<behavior>
- Test 1: 上传文件 + 引用文件会统一写入 `additional_kwargs.files`且上传文件不被覆盖per D-05
- Test 2: 引用失效时仅剔除失效项并 toast文本仍会继续提交per D-07
</behavior>
<action>`sendMessage` 中新增引用文件合并逻辑:`uploadedFileInfo` 先转 `FileInMessage`,再追加 `message.references`(保留 `ref_kind/ref_source`);提交前根据传入的有效引用列表进行二次过滤,失效项通过 `toast.error("部分引用已失效,已自动移除")` 提示并继续 `thread.submit`;禁止创建 `mentions` 等并行结构(按 D-05、D-07</action>
<acceptance_criteria>
- `rg -n "additional_kwargs:\\s*\\{\\s*files" frontend/src/core/threads/hooks.ts` 命中提交代码。
- `rg -n "ref_kind|ref_source" frontend/src/core/threads/hooks.ts` 命中引用元信息写入。
- `rg -n "已自动移除|stale" frontend/src/core/threads/hooks.ts` 命中软失败分支。
</acceptance_criteria>
<verify>
<automated>cd frontend && node --test src/core/threads/hooks.test.ts</automated>
</verify>
<done>提交链路兼容 uploads + references软失败生效且单测通过。</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| input-box→thread submit API | 用户可控输入跨越到后端提交 envelope |
| thread artifacts/uploads→引用元信息 | 候选文件元数据进入消息体 |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-06-01-01 | T | `frontend/src/core/threads/hooks.ts` | mitigate | 仅接受候选池中引用并在提交前二次过滤拒绝自由路径注入ASVS V5。 |
| T-06-01-02 | I | `additional_kwargs.files` | mitigate | 强制 thread 范围来源不引入全局检索避免跨线程信息泄露ASVS V4。 |
| T-06-01-03 | D | `sendMessage` 合并逻辑 | mitigate | 失效引用软剔除并继续提交,避免单点失败阻断消息发送。 |
</threat_model>
<verification>
- `cd frontend && node --test src/core/threads/hooks.test.ts`
- `cd frontend && pnpm -s typecheck`
</verification>
<success_criteria>
- `additional_kwargs.files` 成为上传与引用的唯一提交结构。
- 引用元信息可被编码且不影响既有文件渲染。
- 失效引用不会导致整条消息发送失败。
</success_criteria>
<output>
After completion, create `.planning/phases/06-/06-01-SUMMARY.md`
</output>