Files
weichenandCursor ba289e7b17 Add U1 task summary body contract helpers
Why: Freeze L1 skeleton KV keys and honest no-findings placeholder
so Backend can stop stuffing raw task text into progress cards.
Evidence: go test ./... -count=1
Impact: New TaskSummaryView helpers; findings[] still deferred to U2/U3.
Refs: fast-slow-channel-display-u1-plan W1

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 07:41:05 +00:00

101 lines
3.8 KiB
Go
Raw Permalink 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.
package core
// TaskSummaryView 是 U1 写入 ActivityCard.Body 的权威语义草图。
// 完整 TaskSnapshot(findings[]、revision、streamScope)留待 U2;本类型只冻结
// 运行中/终态的精炼骨架字段与 Body KV 键名,供 Backend 生成、旧客户端回退阅读。
type TaskSummaryView struct {
Title string // 业务动宾短标题(通常已在 ActivityCard.Title)
Focus string // 正在做什么,≤2 行
FindingsNote string // U1:无成果时诚实占位;结构化 findings 属 U3
Remaining string
NextStep string
OutcomeLine string // 完成后的结论一行;运行中可空
}
// Body KV 键名(U1 冻结;用户默认卡身可见,勿改成内部材料键)。
const (
TaskSummaryKVStatus = "状态"
TaskSummaryKVFocus = "正在做"
TaskSummaryKVFindings = "当前发现"
TaskSummaryKVRemaining = "剩余"
TaskSummaryKVNextStep = "下一步"
)
// 状态行用户文案(与执行态映射;排队/进行中/完成/失败)。
const (
TaskSummaryStatusQueued = "排队中"
TaskSummaryStatusRunning = "进行中"
TaskSummaryStatusDone = "已完成"
TaskSummaryStatusFailed = "执行失败"
)
// 无阶段成果时的诚实占位(R03-a);不得编造业务发现。
const TaskSummaryNoFindingsYet = "尚无阶段结论,正在读取材料"
// RunningBody 生成运行中(含排队)进度卡 Body:Markdown 占位 + 固定骨架 KV。
// extraKV(材料键等)保留在同一 UIKV 节点,供系统去重,不充当用户进度正文。
func (v TaskSummaryView) RunningBody(statusLabel string, extraKV [][2]string) []UINode {
focus := stringsOr(v.Focus, "处理已登记工作")
findings := stringsOr(v.FindingsNote, TaskSummaryNoFindingsYet)
remaining := stringsOr(v.Remaining, "待任务进展后更新")
next := stringsOr(v.NextStep, "继续处理已登记工作")
if statusLabel == "" {
statusLabel = TaskSummaryStatusRunning
}
kv := append(append([][2]string(nil), extraKV...),
[2]string{TaskSummaryKVStatus, statusLabel},
[2]string{TaskSummaryKVFocus, focus},
[2]string{TaskSummaryKVFindings, findings},
[2]string{TaskSummaryKVRemaining, remaining},
[2]string{TaskSummaryKVNextStep, next},
)
return []UINode{
{Type: UIMarkdown, Markdown: findings},
{Type: UIKV, KV: kv},
}
}
// FinishedBody 生成终态卡 Body:结论 Markdown + 骨架 KV(状态为已完成或执行失败)。
func (v TaskSummaryView) FinishedBody(statusLabel string, extraKV [][2]string) []UINode {
outcome := stringsOr(v.OutcomeLine, "(无结果摘要)")
findings := stringsOr(v.FindingsNote, outcome)
if statusLabel == "" {
statusLabel = TaskSummaryStatusDone
}
kv := append(append([][2]string(nil), extraKV...),
[2]string{TaskSummaryKVStatus, statusLabel},
[2]string{TaskSummaryKVFocus, stringsOr(v.Focus, "")},
[2]string{TaskSummaryKVFindings, findings},
[2]string{TaskSummaryKVRemaining, stringsOr(v.Remaining, "")},
[2]string{TaskSummaryKVNextStep, stringsOr(v.NextStep, "")},
)
// 去掉空值骨架行,避免完成卡出现空白「正在做」。
compact := make([][2]string, 0, len(kv))
for _, pair := range kv {
if pair[1] == "" && (pair[0] == TaskSummaryKVFocus || pair[0] == TaskSummaryKVRemaining || pair[0] == TaskSummaryKVNextStep) {
continue
}
compact = append(compact, pair)
}
return []UINode{
{Type: UIMarkdown, Markdown: outcome},
{Type: UIKV, KV: compact},
}
}
// CardDisplaysFailed 判断卡是否应按失败展示:含 CardFailed,以及旧客户端
// done + danger 兼容映射(U1 出口白名单)。
func CardDisplaysFailed(status CardStatus, tone string) bool {
if status == CardFailed {
return true
}
return status == CardDone && tone == "danger"
}
func stringsOr(s, fallback string) string {
if s == "" {
return fallback
}
return s
}