feat(coordinator): 增强工作区阶段元数据持久化与上下文自动关联

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WeiCHEN
2026-09-07 21:38:59 +08:00
co-authored by Cursor
parent b1484a7a9b
commit 3a15143fa7
4 changed files with 61 additions and 6 deletions
+4
View File
@@ -50,6 +50,10 @@ func main() {
os.Exit(1)
}
if *backend != "" {
cfg.AgentBackend = *backend
}
svc := bizdev.NewService(cfg)
// 0. 列出支持的阶段
+29
View File
@@ -2,6 +2,7 @@ package bizdev
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
@@ -267,6 +268,34 @@ func (s *Service) executeStageInternal(ctx context.Context, req StageRunRequest)
}
}
// 持久化阶段级元数据与事实黑板,便于 L2 上下文装载与对话系统读取
stageMetaRecord := squad.WorkspaceMetadata{
ProjectName: req.ProjectName,
CustomerName: req.CustomerName,
DeviceType: req.DeviceType,
IntendedUse: req.IntendedUse,
TargetMarket: req.TargetMarket,
TaskKey: string(req.Stage),
Status: "completed",
CreatedAt: start,
}
if b, err := json.MarshalIndent(stageMetaRecord, "", " "); err == nil {
_ = os.WriteFile(filepath.Join(workDir, "workspace.json"), b, 0o644)
}
bbRecord := squad.BlackboardState{
Fields: currentFields,
}
if b, err := json.MarshalIndent(bbRecord, "", " "); err == nil {
_ = os.WriteFile(filepath.Join(workDir, "blackboard.json"), b, 0o644)
}
if stageBrief != nil {
if b, err := json.MarshalIndent(stageBrief, "", " "); err == nil {
_ = os.WriteFile(filepath.Join(workDir, "advisor_brief.json"), b, 0o644)
}
}
return &StageRunResult{
Stage: req.Stage,
StageTitle: targetMeta.Title,
+25 -5
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"chat-agent-system/internal/bizdev"
@@ -152,16 +153,35 @@ func (a *ContextAssembler) AssembleFromWorkspace(workDir string, user UserInfo)
}
// 3. 尝试提取阶段与文档
if strings.HasPrefix(ctx.Project.CurrentWorkflow, "V0.1") {
ctx.Project.CurrentStage = bizdev.StageV01_Triage
} else if strings.HasPrefix(ctx.Project.CurrentWorkflow, "V0.5") {
ctx.Project.CurrentStage = bizdev.StageV05_Feasibility
} else if strings.HasPrefix(ctx.Project.CurrentWorkflow, "V1.0") {
ctx.Project.CurrentStage = bizdev.StageV10_Quoting
}
if ctx.Project.CurrentStage == "" {
ctx.Project.CurrentStage = bizdev.StageV01_Triage
}
ctx.AvailableActions = ComputeAvailableActions(ctx.Project.CurrentStage, user.ProjectRole)
// 4. 若有 output.md,尝试提取最新的参谋简报
outPath := filepath.Join(workDir, "output.md")
if outBytes, err := os.ReadFile(outPath); err == nil && len(outBytes) > 0 {
ctx.LatestAdvisorBrief = squad.ExtractAdvisorBriefing(ctx.Project.CurrentWorkflow, string(outBytes), ctx.BlackboardFacts)
ctx.UserDocs.Composed = append(ctx.UserDocs.Composed, ctx.Project.CurrentWorkflow)
// 4. 优先尝试直接读取持久化的 advisor_brief.json
briefPath := filepath.Join(workDir, "advisor_brief.json")
if data, err := os.ReadFile(briefPath); err == nil {
var brief squad.AdvisorBriefing
if json.Unmarshal(data, &brief) == nil {
ctx.LatestAdvisorBrief = &brief
}
}
// 5. 若无 advisor_brief.json 但有 output.md,尝试从文本抽取
if ctx.LatestAdvisorBrief == nil {
outPath := filepath.Join(workDir, "output.md")
if outBytes, err := os.ReadFile(outPath); err == nil && len(outBytes) > 0 {
ctx.LatestAdvisorBrief = squad.ExtractAdvisorBriefing(ctx.Project.CurrentWorkflow, string(outBytes), ctx.BlackboardFacts)
ctx.UserDocs.Composed = append(ctx.UserDocs.Composed, ctx.Project.CurrentWorkflow)
}
}
return ctx, nil
+3 -1
View File
@@ -103,8 +103,10 @@ func matchAdvanceStage(input string, currentStage bizdev.MaturityStage) *Candida
patterns := []string{
"进入下一阶段", "推进到下一阶段", "推进阶段", "进入方案", "进入论证",
"方案论证", "可行性论证", "开始方案", "进入报价", "开始报价", "商业锁定",
"进入v0.5", "推进到v0.5", "进入v1.0", "推进到v1.0", "可以进入",
"进入v0.1", "推进到v0.1", "进入v0.5", "推进到v0.5", "进入v1.0", "推进到v1.0", "可以进入",
"没有问题.*进入", "没问题.*推进", "通过.*下一阶段", "开始推进",
"做.*摸底", "开始.*摸底", "先做.*摸底", "进行.*摸底", "做v0.1", "先做v0.1",
"做.*论证", "做.*报价", "开始论证",
}
for _, p := range patterns {