Files
Agent-System/internal/coordinator/context.go
T

169 lines
6.1 KiB
Go

package coordinator
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"
"chat-agent-system/internal/bizdev"
"chat-agent-system/internal/intent"
"chat-agent-system/internal/squad"
)
// UserInfo 用户在系统与项目内的身份
type UserInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Role string `json:"role"` // 系统角色 (如 engineer, pm, director)
ProjectRole string `json:"project_role"` // 项目内角色 (如 编制人 composer, 审核人 reviewer, 批准人 approver)
}
// ProjectInfo 项目与工作流当前基准
type ProjectInfo struct {
ID string `json:"id"`
Name string `json:"name"`
CustomerName string `json:"customer_name"`
DeviceType string `json:"device_type"`
IntendedUse string `json:"intended_use"`
TargetMarket string `json:"target_market"`
CurrentWorkflow string `json:"current_workflow"`
CurrentStage bizdev.MaturityStage `json:"current_stage"`
StageRules []string `json:"stage_rules,omitempty"`
}
// UserDocsInfo 用户相关文档清单与认领状态
type UserDocsInfo struct {
Composed []string `json:"composed"` // 负责编制的文档
Reviewed []string `json:"reviewed"` // 负责审核的文档
Approved []string `json:"approved"` // 负责批准的文档
Claimed []string `json:"claimed"` // 已认领/已打开查阅的文档
}
// PendingItems 待用户处理或决策的待办项
type PendingItems struct {
ConfirmModifications []string `json:"confirm_modifications,omitempty"`
PendingReviews []string `json:"pending_reviews,omitempty"`
PendingApprovals []string `json:"pending_approvals,omitempty"`
MyDraftsInProgress []string `json:"my_drafts_in_progress,omitempty"`
UnreadSupplements []string `json:"unread_supplements,omitempty"`
}
// UserProjectContext 用户项目级全量统一上下文 (对话系统与执行系统共同消费)
type UserProjectContext struct {
SnapshotID string `json:"snapshot_id"`
AssembledAt time.Time `json:"assembled_at"`
User UserInfo `json:"user"`
Project ProjectInfo `json:"project"`
UserDocs UserDocsInfo `json:"user_docs"`
Pending PendingItems `json:"pending"`
BlackboardFacts map[string]string `json:"blackboard_facts"`
LatestAdvisorBrief *squad.AdvisorBriefing `json:"latest_advisor_brief,omitempty"`
AvailableActions []string `json:"available_actions"`
RecentEvents []string `json:"recent_events,omitempty"`
WorkDir string `json:"work_dir,omitempty"`
}
// ContextAssembler 上下文组装服务
type ContextAssembler struct{}
func NewContextAssembler() *ContextAssembler {
return &ContextAssembler{}
}
// ComputeAvailableActions 根据当前成熟度阶段与角色计算允许执行的操作集合
func ComputeAvailableActions(stage bizdev.MaturityStage, pRole string) []string {
actions := []string{"QUERY_PROGRESS", "SUPPLEMENT_INFO", "VIEW_DOC"}
switch stage {
case bizdev.StageV01_Triage:
actions = append(actions, "TRIGGER_TASK:intake", "ADVANCE_STAGE:V0.5_feasibility")
case bizdev.StageV05_Feasibility:
actions = append(actions,
"TRIGGER_TASK:research",
"TRIGGER_TASK:feasibility_reg",
"TRIGGER_TASK:prelim_design",
"ADVANCE_STAGE:V1.0_quoting",
)
case bizdev.StageV10_Quoting:
actions = append(actions, "TRIGGER_TASK:cdo_quote", "LOCK_COMMERCIAL")
default:
actions = append(actions, "ADVANCE_STAGE:V0.1_triage")
}
return actions
}
// ToSnapshot 转换为 L1 意图识别器所需的轻量上下文快照
func (ctx *UserProjectContext) ToSnapshot() *intent.ContextSnapshot {
if ctx == nil {
return nil
}
return &intent.ContextSnapshot{
SnapshotID: ctx.SnapshotID,
ProjectName: ctx.Project.Name,
CurrentStage: string(ctx.Project.CurrentStage),
AvailableActions: ctx.AvailableActions,
}
}
// AssembleFromWorkspace 基于现有工作区快速组装 UserProjectContext
func (a *ContextAssembler) AssembleFromWorkspace(workDir string, user UserInfo) (*UserProjectContext, error) {
snapID := fmt.Sprintf("ctx_%d", time.Now().UnixNano())
ctx := &UserProjectContext{
SnapshotID: snapID,
AssembledAt: time.Now(),
User: user,
WorkDir: workDir,
BlackboardFacts: make(map[string]string),
AvailableActions: []string{"QUERY_PROGRESS", "SUPPLEMENT_INFO", "VIEW_DOC"},
}
// 1. 尝试读取 workspace.json
wsMetaPath := filepath.Join(workDir, "workspace.json")
if data, err := os.ReadFile(wsMetaPath); err == nil {
var wsMeta squad.WorkspaceMetadata
if json.Unmarshal(data, &wsMeta) == nil {
ctx.Project.Name = wsMeta.ProjectName
ctx.Project.CustomerName = wsMeta.CustomerName
ctx.Project.DeviceType = wsMeta.DeviceType
ctx.Project.IntendedUse = wsMeta.IntendedUse
ctx.Project.TargetMarket = wsMeta.TargetMarket
ctx.Project.CurrentWorkflow = wsMeta.TaskKey
}
}
// 2. 尝试读取 blackboard.json
bbPath := filepath.Join(workDir, "blackboard.json")
if data, err := os.ReadFile(bbPath); err == nil {
var bb squad.BlackboardState
if json.Unmarshal(data, &bb) == nil {
for k, v := range bb.Fields {
ctx.BlackboardFacts[k] = v
}
for _, g := range bb.Gaps {
if g.Blocking && !g.Resolved {
ctx.Pending.ConfirmModifications = append(ctx.Pending.ConfirmModifications, g.Item)
}
}
}
}
// 3. 尝试提取阶段与文档
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)
}
return ctx, nil
}