Files
weichenandCursor 84c0841acb feat(app): add composition root, stageflow, ContextUpdate, and SSE transport
Move construction and document OnOutbox out of server, give HTTP/CLI a shared task use case, and block already-cleared import/event arch rules.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 05:40:15 +00:00

141 lines
4.6 KiB
Go

package coordinator
import (
"context"
"fmt"
"chat-agent-system/internal/intent"
)
func isRunActionConfirmed(userCtx *UserProjectContext, targetAction string) bool {
if userCtx == nil || userCtx.PendingExpectation == nil {
return false
}
return userCtx.PendingExpectation.TargetAction == targetAction
}
func (e *CoordinatorEngine) handleRunStatusQuery(_ context.Context, _ *intent.CandidateIntent, userCtx *UserProjectContext) (*CoordinationResult, error) {
workDir := userCtx.WorkDir
reply := "📊 **运行状态查询(只读)**\n\n"
if workDir != "" {
reply += fmt.Sprintf("• 最近工作区:`%s`\n• 您可以在任务面板查看该运行的阶段、失败原因与产物摘要。\n", workDir)
} else {
reply += "• 当前会话未绑定具体工作区。请指定要查询的运行任务,或先在界面打开失败任务详情。\n"
}
return &CoordinationResult{
Status: StatusAccepted,
Intent: intent.IntentRunStatusQuery,
NaturalReply: reply,
UpdatedContext: userCtx,
}, nil
}
func (e *CoordinatorEngine) handleRunResume(_ context.Context, cand *intent.CandidateIntent, userCtx *UserProjectContext) (*CoordinationResult, error) {
workDir := cand.FilledSlots[intent.SlotWorkDir]
if workDir == "" {
workDir = userCtx.WorkDir
}
if workDir == "" {
msg := cand.ClarificationQuestion
if msg == "" {
msg = "续跑需要绑定目标工作区。请说明要恢复哪一次失败运行,或在工作区面板选择「继续」。"
}
return &CoordinationResult{
Status: StatusClarificationRequired,
Intent: intent.IntentRunResume,
ClarificationPrompt: msg,
NaturalReply: msg,
UpdatedContext: userCtx,
}, nil
}
if isRunActionConfirmed(userCtx, "run.resume") {
userCtx.applyPending(nil)
return &CoordinationResult{
Status: StatusAccepted,
Intent: intent.IntentRunResume,
NaturalReply: fmt.Sprintf("正在为您续跑工作区 `%s`…", workDir),
UpdatedContext: userCtx,
PendingAction: &PendingAction{
Kind: "taskrun.resume",
WorkDir: workDir,
},
ClearExpectation: true,
}, nil
}
msg := fmt.Sprintf(
"已理解您要续跑工作区 `%s`(复用已有上下文)。请在任务面板确认「继续」,或回复「确认续跑」后我将为您发起 resume 请求。",
workDir,
)
return &CoordinationResult{
Status: StatusClarificationRequired,
Intent: intent.IntentRunResume,
NaturalReply: msg,
ClarificationPrompt: msg,
UpdatedContext: userCtx,
NextExpectation: &intent.PendingExpectation{
ExpectedIntent: intent.IntentRunResume,
TargetAction: "run.resume",
Prompt: "确认续跑长任务",
AllowAffirmative: true,
Payload: map[string]string{
intent.SlotWorkDir: workDir,
},
DefaultOption: &intent.ExpectationOption{
OptionID: "confirm_resume",
Title: "确认续跑",
Intent: intent.IntentRunResume,
Slots: map[string]string{
intent.SlotWorkDir: workDir,
},
},
},
}, nil
}
func (e *CoordinatorEngine) handleRunRestart(_ context.Context, cand *intent.CandidateIntent, userCtx *UserProjectContext) (*CoordinationResult, error) {
if isRunActionConfirmed(userCtx, "run.restart") {
userCtx.applyPending(nil)
taskKey := cand.FilledSlots["task_key"]
if taskKey == "" && userCtx.TaskState != nil {
taskKey = userCtx.TaskState.ActiveTask
}
return &CoordinationResult{
Status: StatusAccepted,
Intent: intent.IntentRunRestart,
NaturalReply: "正在为您重新启动任务…",
UpdatedContext: userCtx,
ClearExpectation: true,
PendingAction: &PendingAction{
Kind: "taskrun.restart",
TaskKey: taskKey,
WorkDir: userCtx.WorkDir,
},
}, nil
}
msg := "已理解您希望重新运行任务(将创建新工作区,保留原始意图但不复用失败现场)。这是高风险操作,请确认后再执行。"
if cand.ClarificationQuestion != "" {
msg = cand.ClarificationQuestion
}
return &CoordinationResult{
Status: StatusClarificationRequired,
Intent: intent.IntentRunRestart,
NaturalReply: msg,
ClarificationPrompt: msg,
UpdatedContext: userCtx,
NextExpectation: &intent.PendingExpectation{
ExpectedIntent: intent.IntentRunRestart,
TargetAction: "run.restart",
Prompt: "确认重新运行长任务",
AllowAffirmative: false,
DefaultOption: &intent.ExpectationOption{
OptionID: "confirm_restart",
Title: "确认重新运行",
Intent: intent.IntentRunRestart,
},
},
}, nil
}