From 105b3f410349488efb7fc3acd37b66d79ed93ac8 Mon Sep 17 00:00:00 2001 From: WeiCHEN Date: Mon, 7 Sep 2026 21:38:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(coordinator):=20=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E5=8C=BA=E9=98=B6=E6=AE=B5=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8C=81=E4=B9=85=E5=8C=96=E4=B8=8E=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E8=87=AA=E5=8A=A8=E5=85=B3=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- cmd/bizdev-cli/main.go | 4 ++++ internal/bizdev/service.go | 29 +++++++++++++++++++++++++++++ internal/coordinator/context.go | 30 +++++++++++++++++++++++++----- internal/intent/recognizer.go | 4 +++- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/cmd/bizdev-cli/main.go b/cmd/bizdev-cli/main.go index 0bd3dcad..5e7c2c28 100644 --- a/cmd/bizdev-cli/main.go +++ b/cmd/bizdev-cli/main.go @@ -50,6 +50,10 @@ func main() { os.Exit(1) } + if *backend != "" { + cfg.AgentBackend = *backend + } + svc := bizdev.NewService(cfg) // 0. 列出支持的阶段 diff --git a/internal/bizdev/service.go b/internal/bizdev/service.go index b4ae0429..46345d70 100644 --- a/internal/bizdev/service.go +++ b/internal/bizdev/service.go @@ -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, diff --git a/internal/coordinator/context.go b/internal/coordinator/context.go index 9cfc6c7a..5336d0ea 100644 --- a/internal/coordinator/context.go +++ b/internal/coordinator/context.go @@ -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 diff --git a/internal/intent/recognizer.go b/internal/intent/recognizer.go index 21754825..c611a02e 100644 --- a/internal/intent/recognizer.go +++ b/internal/intent/recognizer.go @@ -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 {