Files
smartmate/backend/services/agent/tools/taskclass_result/write.go
Losita d7184b776b Version: 0.9.75.dev.260505
后端:
1.收口阶段 6 agent 结构迁移,将 newAgent 内核与 agentsvc 编排层迁入 services/agent
- 切换 Agent 启动装配与 HTTP handler 直连 agent sv,移除旧 service agent bridge
- 补齐 Agent 对 memory、task、task-class、schedule 的 RPC 适配与契约字段
- 扩展 schedule、task、task-class RPC/contract 支撑 Agent 查询、写入与 provider 切流
- 更新迁移文档、README 与相关注释,明确 agent 当前切流点和剩余 memory 迁移面
2026-05-05 16:00:57 +08:00

243 lines
7.5 KiB
Go
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.
package taskclass_result
import "fmt"
// BuildUpsertTaskClassView 把 upsert_task_class 的稳定结果摘要转成任务类写入卡片。
//
// 步骤化说明:
// 1. 先基于父包传入的 Status/Result 生成折叠态标题、摘要和稳定指标,保证成功/失败都能快速扫读;
// 2. 再把任务类字段、配置、任务项列表和失败原因拆成 kv/items/callout section避免前端继续回退 raw_text
// 3. raw_text 与 machine_payload 始终保留,便于模型链路、调试链路和后续交互共用同一份 observation 语义。
func BuildUpsertTaskClassView(input BuildUpsertTaskClassViewInput) WriteResultView {
status := normalizeStatus(input.Status)
if status == "" {
if input.Result.Success {
status = StatusDone
} else {
status = StatusFailed
}
}
items := buildTaskClassItemViews(input.Request.Items)
sections := buildUpsertSections(input.Result, input.Request, items, status)
return buildWriteResultView(
status,
buildUpsertTitle(input.Result, status),
buildUpsertSubtitle(input.Result, input.Request, status),
buildUpsertMetrics(input.Result, input.Request),
items,
sections,
input.Observation,
input.MachinePayload,
)
}
func buildUpsertTitle(result UpsertResult, status string) string {
if normalizeStatus(status) != StatusDone {
return "任务类写入失败"
}
if result.Created {
return "任务类已创建"
}
return "任务类已更新"
}
func buildUpsertSubtitle(result UpsertResult, request RequestSummary, status string) string {
name := fallbackText(request.Name, "未命名任务类")
itemCount := len(request.Items)
if normalizeStatus(status) == StatusDone {
action := "更新"
if result.Created {
action = "创建"
}
return fmt.Sprintf("已%s「%s」共 %d 项任务", action, name, itemCount)
}
if len(result.ValidationIssues) > 0 {
return fmt.Sprintf("「%s」校验未通过%s", name, result.ValidationIssues[0])
}
if result.Error != "" {
return fmt.Sprintf("「%s」写入失败%s", name, result.Error)
}
return fmt.Sprintf("「%s」写入失败请查看详情", name)
}
func buildUpsertMetrics(result UpsertResult, request RequestSummary) []MetricField {
action := "更新"
if result.Created {
action = "创建"
}
if !result.Success && request.RequestedID == 0 {
action = "创建尝试"
}
if !result.Success && request.RequestedID > 0 {
action = "更新尝试"
}
return []MetricField{
buildMetric("任务类数量", "1 个"),
buildMetric("任务项数量", fmt.Sprintf("%d 项", len(request.Items))),
buildMetric("来源", formatSourceCN(request.Source)),
buildMetric("写入方式", action),
}
}
func buildUpsertSections(
result UpsertResult,
request RequestSummary,
items []ItemView,
status string,
) []map[string]any {
sections := []map[string]any{
buildResultCallout(result, request, status),
buildKVSection("任务类字段", buildTaskClassFields(result, request)),
buildKVSection("排程配置", buildTaskClassConfigFields(request)),
}
if len(items) > 0 {
sections = append(sections, buildItemsSection("任务项列表", items))
} else {
sections = append(sections, buildCalloutSection(
"任务项列表",
"当前没有可展示的任务项。",
"info",
[]string{"如果这是一次失败写入,请优先检查 task_class.items 或顶层 items 入参是否完整。"},
))
}
if len(result.ValidationIssues) > 0 {
sections = append(sections, buildCalloutSection(
"校验失败原因",
"请求参数未通过后端校验。",
"warning",
normalizeStringSlice(result.ValidationIssues),
))
}
return sections
}
func buildResultCallout(result UpsertResult, request RequestSummary, status string) map[string]any {
if normalizeStatus(status) == StatusDone {
action := "更新"
if result.Created {
action = "创建"
}
detailLines := []string{
fmt.Sprintf("任务类:%s", fallbackText(request.Name, "未命名任务类")),
fmt.Sprintf("任务类 ID%d", resolveDisplayTaskClassID(result, request)),
fmt.Sprintf("任务项数量:%d 项", len(request.Items)),
}
return buildCalloutSection(
"写入结果",
fmt.Sprintf("已%s任务类结果可直接用于后续排程。", action),
"success",
detailLines,
)
}
reason := result.Error
if len(result.ValidationIssues) > 0 {
reason = result.ValidationIssues[0]
}
if reason == "" {
reason = "写入流程未返回明确失败原因,请查看原始 observation。"
}
return buildCalloutSection(
"写入失败",
reason,
"danger",
[]string{
fmt.Sprintf("来源:%s", formatSourceCN(request.Source)),
fmt.Sprintf("任务类:%s", fallbackText(request.Name, "未命名任务类")),
fmt.Sprintf("任务项数量:%d 项", len(request.Items)),
},
)
}
func buildTaskClassFields(result UpsertResult, request RequestSummary) []KVField {
return []KVField{
buildKVField("任务类 ID", fmt.Sprintf("%d", resolveDisplayTaskClassID(result, request))),
buildKVField("名称", fallbackText(request.Name, "未命名任务类")),
buildKVField("模式", formatModeCN(request.Mode)),
buildKVField("日期范围", formatDateRangeCN(request.StartDate, request.EndDate)),
buildKVField("学科类型", formatSubjectTypeCN(request.SubjectType)),
buildKVField("难度等级", formatLevelCN(request.DifficultyLevel)),
buildKVField("认知强度", formatLevelCN(request.CognitiveIntensity)),
buildKVField("来源", formatSourceCN(request.Source)),
}
}
func buildTaskClassConfigFields(request RequestSummary) []KVField {
return []KVField{
buildKVField("总节数", fmt.Sprintf("%d", request.TotalSlots)),
buildKVField("允许补位课程", formatBoolCN(request.AllowFillerCourse)),
buildKVField("推进策略", formatStrategyCN(request.Strategy)),
buildKVField("排除半天块", formatIntListCN(request.ExcludedSlots, "无", func(value int) string {
return fmt.Sprintf("第%d块", value)
})),
buildKVField("排除星期", formatIntListCN(request.ExcludedDaysOfWeek, "无", formatWeekdayCN)),
}
}
func buildTaskClassItemViews(items []TaskClassItemSummary) []ItemView {
if len(items) == 0 {
return make([]ItemView, 0)
}
out := make([]ItemView, 0, len(items))
for _, item := range items {
detailLines := []string{
"内容:" + fallbackText(item.Content, "未填写内容"),
"嵌入时间:" + formatEmbeddedTimeCN(item),
}
if item.ID > 0 {
detailLines = append(detailLines, fmt.Sprintf("任务项 ID%d", item.ID))
}
out = append(out, buildItem(
truncateText(item.Content, 28),
fmt.Sprintf("第 %d 项", maxInt(item.Order, 0)),
buildTaskClassItemTags(item),
detailLines,
map[string]any{
"id": item.ID,
"order": item.Order,
"embedded_week": item.EmbeddedWeek,
"embedded_day": item.EmbeddedDay,
"section_from": item.EmbeddedSectionFrom,
"section_to": item.EmbeddedSectionTo,
},
))
}
return out
}
func buildTaskClassItemTags(item TaskClassItemSummary) []string {
tags := []string{fmt.Sprintf("顺序 %d", maxInt(item.Order, 0))}
if item.EmbeddedWeek > 0 && item.EmbeddedDay > 0 {
tags = append(tags, formatEmbeddedTimeCN(item))
} else {
tags = append(tags, "未指定嵌入时间")
}
return tags
}
func resolveDisplayTaskClassID(result UpsertResult, request RequestSummary) int {
if result.TaskClassID > 0 {
return result.TaskClassID
}
return request.RequestedID
}
func maxInt(values ...int) int {
if len(values) == 0 {
return 0
}
best := values[0]
for _, value := range values[1:] {
if value > best {
best = value
}
}
return best
}