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>
101 lines
3.8 KiB
Go
101 lines
3.8 KiB
Go
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
|
||
}
|