127 lines
4.4 KiB
Go
127 lines
4.4 KiB
Go
package runmgr
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"agent-system-backend/internal/runtime"
|
|
core "agent-system-core"
|
|
)
|
|
|
|
type materialIntakeState string
|
|
|
|
const (
|
|
materialNone materialIntakeState = "none"
|
|
materialQueued materialIntakeState = "queued"
|
|
materialRunning materialIntakeState = "running"
|
|
materialReusedRunning materialIntakeState = "reused_running"
|
|
materialCompleted materialIntakeState = "completed"
|
|
materialFailed materialIntakeState = "failed"
|
|
materialUnknown materialIntakeState = "unknown"
|
|
)
|
|
|
|
type materialIntakeDecision struct {
|
|
Note string
|
|
State materialIntakeState
|
|
CardID core.ID
|
|
}
|
|
|
|
func (d materialIntakeDecision) needsAcknowledgement(userText string) bool {
|
|
return d.State == materialRunning || d.State == materialReusedRunning || d.State == materialQueued ||
|
|
d.State == materialFailed || d.State == materialUnknown ||
|
|
(d.State == materialCompleted && userText == "")
|
|
}
|
|
|
|
// materialDecisionForNote reads server-owned task state after intake or reuse;
|
|
// an absent card is unknown rather than proof that work has started.
|
|
func (m *Manager) materialDecisionForNote(rc *runCtx, key, note string) materialIntakeDecision {
|
|
decision := materialIntakeDecision{Note: note, State: materialUnknown}
|
|
if m.cards == nil {
|
|
return decision
|
|
}
|
|
cards, err := m.cards.List(rc.run.Owner, rc.run.ConversationID)
|
|
if err != nil {
|
|
return decision
|
|
}
|
|
var current *core.ActivityCard
|
|
for i := range cards {
|
|
card := &cards[i]
|
|
if card.Kind != core.CardKindProgress || card.ProjectID != rc.run.ProjectID ||
|
|
card.Task == nil || card.Task.InputRevision != key {
|
|
continue
|
|
}
|
|
if current == nil || card.CreatedAt.After(current.CreatedAt) ||
|
|
(card.CreatedAt.Equal(current.CreatedAt) && current.Task.Terminal() && !card.Task.Terminal()) {
|
|
current = card
|
|
}
|
|
}
|
|
if current != nil {
|
|
decision.CardID = current.ID
|
|
if current.Task.ExecutionState == "completed" {
|
|
if m.taskSourcesAvailable(rc.run.Owner, rc.run.ProjectID, current.Task) {
|
|
decision.State = materialCompleted
|
|
decision.Note = materialDoneNote
|
|
} else {
|
|
decision.State = materialUnknown
|
|
}
|
|
} else if current.Task.ExecutionState == "queued" {
|
|
decision.State = materialQueued
|
|
} else if current.Task.Terminal() {
|
|
decision.State = materialFailed
|
|
decision.Note = ""
|
|
} else {
|
|
decision.State = materialRunning
|
|
}
|
|
}
|
|
return decision
|
|
}
|
|
|
|
type materialAckRunner struct {
|
|
decision materialIntakeDecision
|
|
attachmentCount int
|
|
hasUserFocus bool
|
|
}
|
|
|
|
func (materialAckRunner) Name() string { return "material-acknowledgement" }
|
|
|
|
func (r materialAckRunner) Execute(rc runtime.RunCtx) error {
|
|
if err := rc.Context().Err(); err != nil {
|
|
return err
|
|
}
|
|
text := r.reply()
|
|
if err := rc.Emit(core.EvRunPhase, core.RunPhasePayload{Phase: core.PhaseResponding}); err != nil {
|
|
return err
|
|
}
|
|
if err := rc.Emit(core.EvMessageDelta, core.MessageDeltaPayload{Index: 0, Text: text}); err != nil {
|
|
return err
|
|
}
|
|
return rc.SetAssistantParts([]core.Part{{Type: core.PartText, Text: text}})
|
|
}
|
|
|
|
func (r materialAckRunner) reply() string {
|
|
lead := ""
|
|
if r.decision.State == materialCompleted {
|
|
lead = "这批材料已整理完成,可在“材料整理”卡查看结果。"
|
|
} else if r.decision.State == materialQueued {
|
|
lead = fmt.Sprintf("已收到 %d 份材料,整理任务正在排队。", r.attachmentCount)
|
|
} else if r.decision.State == materialReusedRunning {
|
|
lead = "这批材料仍在整理,已有任务会继续更新“材料整理”卡。"
|
|
} else if r.decision.State == materialFailed {
|
|
if r.decision.CardID == "" {
|
|
lead = "材料已收到,但后台整理未能启动;请稍后重新提出请求。"
|
|
} else {
|
|
lead = "后台整理未能完成;请查看“材料整理”卡中的已保存成果和未完成范围。"
|
|
}
|
|
} else if r.decision.State == materialUnknown {
|
|
if r.decision.CardID == "" {
|
|
return "材料已收到,但暂时无法确认整理状态;当前没有可核对的工作卡,请稍后刷新会话或重新提出请求。数字、分期和归属判断待确认。"
|
|
}
|
|
lead = "材料已收到,但暂时无法确认整理状态;请查看工作卡。"
|
|
} else {
|
|
lead = fmt.Sprintf("已收到 %d 份材料,正在整理。", r.attachmentCount)
|
|
}
|
|
if r.hasUserFocus {
|
|
lead += "你提出的工作重点已带入整理任务。"
|
|
}
|
|
return lead + "材料中的数字、分期和归属判断在核对依据前均标为待确认;有依据的发现会显示在“材料整理”卡。"
|
|
}
|