merge: fix/stageflow-type-ownership
This commit is contained in:
+4
-3
@@ -5,7 +5,7 @@
|
||||
|
||||
## 焦点
|
||||
|
||||
1. **TRACK-S**: [D7a intent 解绑](./short-term/2026-09-15-intent-bizdev-boundary.md)(D6 已合入。下一波 D5/D4/D7b)
|
||||
1. **TRACK-S**: [D5 stageflow](./short-term/2026-09-15-stageflow-type-ownership.md)(D6/D7a 已合入。D4 getter 仍开放)
|
||||
2. **CHAT-INTENT**: [对话意图运行时状态](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md)(双标签 busy 已签:项目 **6275** / `DOC_BUSY` 单 run;不删 `sess-p143-u9` 探针)
|
||||
3. **CHAT**: [对话历史刷新活验已补](../test-reports/2026-09-13-chat-history-refresh-test-report.md)(项目 6252 闲聊刷新同集 + guest 403;编制任务链仍开放)
|
||||
|
||||
@@ -65,7 +65,8 @@
|
||||
| Cursor | event-e1c-projection-cutover | fix/event-projection-cutover | - | events | done |
|
||||
| Cursor | event-e2-hook-guard | fix/event-e2-hook-guard | - | events | done |
|
||||
| Cursor | doccontent-canonical-boundary | fix/doccontent-canonical-boundary | - | docgov | done |
|
||||
| Cursor | intent-bizdev-boundary | fix/intent-bizdev-boundary | - | intent | in_progress |
|
||||
| Cursor | intent-bizdev-boundary | fix/intent-bizdev-boundary | - | intent | done |
|
||||
| Cursor | stageflow-type-ownership | fix/stageflow-type-ownership | - | stageflow | in_progress |
|
||||
|
||||
> 新任务开始前登记。`branch` 必须为 `feature/<slug>` 或 `fix/<slug>`,**禁止** `dev` / `test` / `main`。同一 `mutex` 同时仅一个 `in_progress`。
|
||||
|
||||
@@ -77,7 +78,7 @@
|
||||
|
||||
| holder | phase | since | scope | queue |
|
||||
|--------|-------|-------|-------|-------|
|
||||
| Cursor | merging | 2026-09-15 | D6 doccontent canonical;mode=off | - |
|
||||
| Cursor | merging | 2026-09-15 | D5 stageflow types;mode=off | - |
|
||||
|
||||
**phase**: `idle` | `merging` | `smoke` | `e2e`
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
title: "D5 stageflow 类型归属与 D7b chatflow 首批"
|
||||
status: in_progress
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
owner: Cursor
|
||||
branch: fix/stageflow-type-ownership
|
||||
worktree: "-"
|
||||
mutex: stageflow
|
||||
---
|
||||
|
||||
# D5 stageflow 类型归属与 D7b chatflow 首批
|
||||
|
||||
## 目标
|
||||
|
||||
coordinator 生产代码不再 import bizdev;task/stage 请求走 stageflow 类型;chatflow assembler 改用 maturity。
|
||||
|
||||
## 范围
|
||||
|
||||
- stageflow 类型别名与状态常量
|
||||
- coordinator 构造改为 StageTaskRunner + ContextServices
|
||||
- chatflow 去掉 bizdev import
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不复制行为方法成 DTO(身份别名 + token golden)
|
||||
- 不删除 bizdev 八个 getter(D4)
|
||||
- 不搬空 chat 包
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 类型边界与 coordinator 解绑
|
||||
2. [x] chatflow assembler
|
||||
3. [x] 表征测试与 arch-check
|
||||
4. [x] 报告
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] coordinator 生产 import 无 bizdev
|
||||
- [x] [S2/S4b 报告](../../test-reports/2026-09-15-stageflow-type-ownership-test-report.md)
|
||||
@@ -27,7 +27,7 @@
|
||||
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 | done | [test piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md) | — | `pi-agent` |
|
||||
| 三环境运维 | dev/test/main + 共享 KB | done | [PROJECT.md](../../PROJECT.md) §4;四环境 healthy | — | `infra` |
|
||||
| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) | CI `TEST_DATABASE_URL` 隔离库仍缺;文档运行时真实 UI 已按 UI_PHASE 分文件且 post-restart 断言最终 A1 正文。`-race` 全包并行 TempDir flake 为基建残留 | `ci` |
|
||||
| 模块解耦与可靠事件 | 文档可靠性纵向试点、PG 持久事件交付与选择性模块化 | partial | [架构](../system-design/2026-09-14-module-decoupling-architecture.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[Phase 1](../remediation/2026-09-14-module-decoupling-refactor-plan.md);[Phase 2 审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[Phase 2 修订计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md);[E0A](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md);[E0B](../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md);[E1A](../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md);[E1B](../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md);[E1C](../test-reports/2026-09-15-event-e1c-projection-test-report.md);[E2](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md);[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[D6](../test-reports/2026-09-15-doccontent-canonical-boundary-test-report.md) | E0A–E2 隔离库已过;dispatcher 默认 off。删除闭包 API 须等 live。D6 canonical 已抽出。Track S 其余与 Track P/FAV 另列 | `architecture-docs` |
|
||||
| 模块解耦与可靠事件 | 文档可靠性纵向试点、PG 持久事件交付与选择性模块化 | partial | [架构](../system-design/2026-09-14-module-decoupling-architecture.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[Phase 1](../remediation/2026-09-14-module-decoupling-refactor-plan.md);[Phase 2 审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[Phase 2 修订计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md);[E0A](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md);[E0B](../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md);[E1A](../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md);[E1B](../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md);[E1C](../test-reports/2026-09-15-event-e1c-projection-test-report.md);[E2](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md);[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[D6](../test-reports/2026-09-15-doccontent-canonical-boundary-test-report.md);[D7a](../test-reports/2026-09-15-intent-bizdev-boundary-test-report.md);[D5](../test-reports/2026-09-15-stageflow-type-ownership-test-report.md) | E0A–E2 隔离库已过;dispatcher 默认 off。D5/D6/D7a/D7b-chatflow 已合入。删除闭包 API 须等 live。D4 getter 原子删除与 Track P 实现、FAV 另列。HTTP/PI 已有独立 remediation(Phase 2 只立项) | `architecture-docs` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -42,11 +42,12 @@ imports:
|
||||
config: []
|
||||
coordinator:
|
||||
- agent
|
||||
- bizdev
|
||||
- app/stageflow
|
||||
- ctxmgr
|
||||
- docgov
|
||||
- intent
|
||||
- kb
|
||||
- maturity
|
||||
- projectinstance
|
||||
- squad
|
||||
- stream
|
||||
@@ -83,9 +84,9 @@ imports:
|
||||
- workflowdef
|
||||
- workspace
|
||||
app/chatflow:
|
||||
- bizdev
|
||||
- coordinator
|
||||
- ctxmgr
|
||||
- maturity
|
||||
- projectinstance
|
||||
app/docnotify:
|
||||
- docgov
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# D5 stageflow 类型归属与 D7b chatflow 首批测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
coordinator 通过 bizdev DTO 与 locator 调用编排根。D5 要求 use-case 请求/结果归 stageflow,coordinator 最终不 import bizdev。D7b 允许按用例收紧 import;本批只迁 `app/chatflow` assembler 的阶段常量。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- coordinator 生产包 import 无 bizdev。
|
||||
- StageTaskRunner / UseCase 使用 stageflow 类型;token `failed` / `pending_author_confirmation` 不变。
|
||||
- chatflow assembler 使用 `maturity.StageV01_Triage`。
|
||||
- 顾问案例推荐仍能通过注入的 ContextManager 填充。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux 7.0.0-31-generic |
|
||||
| Go | go1.27.1 linux/amd64 |
|
||||
| 分支 | `fix/stageflow-type-ownership` |
|
||||
| 层级 | 表征/短测 + arch-check |
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
既有 ADVANCE_STAGE / pending confirmation / chat session 表征仍过;arch-check 收紧 coordinator 与 chatflow allowlist。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 表征
|
||||
|
||||
- **测试输入 (Input)**:`go test -short -count=1 ./internal/coordinator ./internal/app/stageflow ./internal/app/chatflow ./internal/app ./internal/chat ./internal/bizdev ./internal/archtest ./cmd/bizdev-cli`
|
||||
- **实际输出 (Actual Output)**:上述包全部 `ok`(cli 2.3s,其余 <0.15s)
|
||||
- **评价判定 (Evaluation / Verdict)**:**PASS**
|
||||
- **性能与耗时 (Duration & Latency)**:约 3.6s
|
||||
|
||||
### 5.2 arch-check
|
||||
|
||||
- **测试输入 (Input)**:`./scripts/arch-check.sh --mode block`
|
||||
- **实际输出 (Actual Output)**:`arch-check block: production gate passed`
|
||||
- **评价判定 (Evaluation / Verdict)**:**PASS**
|
||||
- **性能与耗时 (Duration & Latency)**:~0.12s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| coordinator/stageflow/chatflow/app/chat/bizdev/cli | PASS |
|
||||
| arch-check | PASS |
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
D5 与 D7b **首批 PASS**。类型仍是 bizdev 结构的别名,未机械复制方法。D4 八个 getter 仍在;`internal/chat` 仍 import bizdev 跑任务。下一步:no-new-callers 门禁后原子删除 getter。
|
||||
@@ -662,7 +662,7 @@ func handleChatMode(
|
||||
}
|
||||
|
||||
rec := intent.NewRecognizer()
|
||||
engine := coordinator.NewCoordinatorEngine(svc)
|
||||
engine := coordinator.NewCoordinatorEngine(stageflow.New(svc))
|
||||
session := chat.NewSession("cli_chat_sess", userCtx, rec, engine)
|
||||
session.CtxMgr = svc.ContextManager()
|
||||
|
||||
|
||||
+2
-1
@@ -88,7 +88,7 @@ func Assemble(cfg *config.Config, svc *bizdev.Service) (*Runtime, error) {
|
||||
|
||||
rec := intent.NewRecognizer()
|
||||
dialogueBackend := agent.NewBackend(cfg.AgentBackend, cfg)
|
||||
coordEngine := coordinator.NewCoordinatorEngineWithDialogue(svc, dialogueBackend, cfg.DataDir)
|
||||
coordEngine := coordinator.NewCoordinatorEngineWithDialogue(nil, dialogueBackend, cfg.DataDir)
|
||||
pool := svc.Pool()
|
||||
stores, storeErr := auth.NewStores(context.Background(), pool, cfg)
|
||||
if storeErr != nil {
|
||||
@@ -130,6 +130,7 @@ func Assemble(cfg *config.Config, svc *bizdev.Service) (*Runtime, error) {
|
||||
|
||||
stages := stageflow.New(svc)
|
||||
coordEngine.SetStageTaskRunner(stages)
|
||||
coordEngine.SetContextServices(svc.ContextManager(), svc.KB())
|
||||
if instSvc != nil && instSvc.Available() {
|
||||
coordEngine.SetInstanceService(instSvc)
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
// Assembler adapts coordinator.ContextAssembler and ChatLog so prompt context
|
||||
@@ -43,10 +43,10 @@ func (a *Assembler) Assemble(ctx context.Context, p Principal, req AssembleReque
|
||||
WorkDir: req.WorkDir,
|
||||
Project: req.Fallback,
|
||||
BlackboardFacts: make(map[string]string),
|
||||
AvailableActions: coordinator.ComputeAvailableActions(bizdev.StageV01_Triage, req.User.ProjectRole),
|
||||
AvailableActions: coordinator.ComputeAvailableActions(maturity.StageV01_Triage, req.User.ProjectRole),
|
||||
}
|
||||
if userCtx.Project.CurrentStage == "" {
|
||||
userCtx.Project.CurrentStage = bizdev.StageV01_Triage
|
||||
userCtx.Project.CurrentStage = maturity.StageV01_Triage
|
||||
}
|
||||
if userCtx.Project.CurrentWorkflow == "" {
|
||||
userCtx.Project.CurrentWorkflow = "intake"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package stageflow
|
||||
|
||||
import "chat-agent-system/internal/bizdev"
|
||||
|
||||
// Use-case request/result types live at the stageflow boundary.
|
||||
// They alias bizdev domain structs so mapping stays identity until a later
|
||||
// contract commit copies fields; characterization tests lock the tokens.
|
||||
type (
|
||||
TaskRunRequest = bizdev.TaskRunRequest
|
||||
TaskRunResult = bizdev.TaskRunResult
|
||||
StageRunRequest = bizdev.StageRunRequest
|
||||
StageRunResult = bizdev.StageRunResult
|
||||
MaterialInput = bizdev.MaterialInput
|
||||
StageMeta = bizdev.StageMeta
|
||||
TaskMeta = bizdev.TaskMeta
|
||||
)
|
||||
|
||||
const (
|
||||
TaskStatusCompleted = bizdev.TaskStatusCompleted
|
||||
TaskStatusFailed = bizdev.TaskStatusFailed
|
||||
TaskStatusQualityFailed = bizdev.TaskStatusQualityFailed
|
||||
TaskStatusPendingAuthorConfirmation = bizdev.TaskStatusPendingAuthorConfirmation
|
||||
)
|
||||
@@ -3,8 +3,6 @@ package stageflow
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
)
|
||||
|
||||
var ErrClosed = errors.New("stageflow: executor not configured")
|
||||
@@ -12,8 +10,8 @@ var ErrClosed = errors.New("stageflow: executor not configured")
|
||||
// Executor is the unique application owner for task and stage runs.
|
||||
// HTTP, CLI and coordinator must call this instead of bizdev directly.
|
||||
type Executor interface {
|
||||
ExecuteTask(ctx context.Context, req bizdev.TaskRunRequest) (*bizdev.TaskRunResult, error)
|
||||
ExecuteStage(ctx context.Context, req bizdev.StageRunRequest) (*bizdev.StageRunResult, error)
|
||||
ExecuteTask(ctx context.Context, req TaskRunRequest) (*TaskRunResult, error)
|
||||
ExecuteStage(ctx context.Context, req StageRunRequest) (*StageRunResult, error)
|
||||
}
|
||||
|
||||
// UseCase adapts bizdev orchestration without moving domain tables.
|
||||
@@ -25,14 +23,14 @@ func New(biz Executor) *UseCase {
|
||||
return &UseCase{Biz: biz}
|
||||
}
|
||||
|
||||
func (u *UseCase) ExecuteTask(ctx context.Context, req bizdev.TaskRunRequest) (*bizdev.TaskRunResult, error) {
|
||||
func (u *UseCase) ExecuteTask(ctx context.Context, req TaskRunRequest) (*TaskRunResult, error) {
|
||||
if u == nil || u.Biz == nil {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
return u.Biz.ExecuteTask(ctx, req)
|
||||
}
|
||||
|
||||
func (u *UseCase) ExecuteStage(ctx context.Context, req bizdev.StageRunRequest) (*bizdev.StageRunResult, error) {
|
||||
func (u *UseCase) ExecuteStage(ctx context.Context, req StageRunRequest) (*StageRunResult, error) {
|
||||
if u == nil || u.Biz == nil {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
|
||||
@@ -23,7 +23,16 @@ func (s *stubBiz) ExecuteStage(_ context.Context, req bizdev.StageRunRequest) (*
|
||||
return &bizdev.StageRunResult{Success: true, StageTitle: string(req.Stage)}, nil
|
||||
}
|
||||
|
||||
func TestUseCaseDelegates(t *testing.T) {
|
||||
func TestUseCaseTypeIdentity(t *testing.T) {
|
||||
var req TaskRunRequest
|
||||
req.TaskKey = "intake"
|
||||
if req.TaskKey != "intake" {
|
||||
t.Fatal("alias lost fields")
|
||||
}
|
||||
if TaskStatusFailed != "failed" || TaskStatusPendingAuthorConfirmation != "pending_author_confirmation" {
|
||||
t.Fatalf("status tokens drifted")
|
||||
}
|
||||
}
|
||||
biz := &stubBiz{}
|
||||
httpUC := New(biz)
|
||||
cliUC := New(biz)
|
||||
|
||||
@@ -101,6 +101,7 @@ func TestBizDev_CaseRecommendation_FullLink_E2E(t *testing.T) {
|
||||
|
||||
rec := intent.NewRecognizer()
|
||||
engine := coordinator.NewCoordinatorEngine(svc)
|
||||
engine.SetContextServices(svc.ContextManager(), svc.KB())
|
||||
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
SnapshotID: "ctx_new_consult",
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"chat-agent-system/internal/agent"
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/chat"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/config"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/intent"
|
||||
)
|
||||
|
||||
@@ -101,6 +101,7 @@ func TestLongTaskGovernance_QualityE2E(t *testing.T) {
|
||||
svc := bizdev.MustNewService(t, cfg)
|
||||
dialogueBackend := agent.NewBackend("pi-agent", cfg)
|
||||
engine := coordinator.NewCoordinatorEngineWithDialogue(svc, dialogueBackend, cfg.DataDir)
|
||||
engine.SetContextServices(svc.ContextManager(), svc.KB())
|
||||
rec := intent.NewRecognizer()
|
||||
reportRoot := qualityReportDir(t)
|
||||
ctx := context.Background()
|
||||
@@ -112,12 +113,12 @@ func TestLongTaskGovernance_QualityE2E(t *testing.T) {
|
||||
_ = os.MkdirAll(scenarioADir, 0o755)
|
||||
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
User: coordinator.UserInfo{ID: "1", Name: "张工", Role: "engineer", ProjectRole: "composer"},
|
||||
User: coordinator.UserInfo{ID: "1", Name: "张工", Role: "engineer", ProjectRole: "composer"},
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "掌上无线超声系统",
|
||||
CustomerName: "华西医院微创神经外科",
|
||||
DeviceType: "超声软组织手术吸引设备",
|
||||
IntendedUse: "脑组织空化乳化与同轴吸引",
|
||||
IntendedUse: "脑组织空化乳化与同轴吸引",
|
||||
TargetMarket: "中国 NMPA 三类",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
},
|
||||
@@ -290,4 +291,3 @@ func qualityVerdict(res *bizdev.TaskRunResult) string {
|
||||
}
|
||||
return fmt.Sprintf("⚠️ 未完全通过(评分 %.0f,违规: %s)", res.QualityReport.Score, strings.Join(res.QualityReport.Violations, "; "))
|
||||
}
|
||||
|
||||
|
||||
@@ -278,6 +278,7 @@ func TestChatSession_AdvisorCaseRecommendation(t *testing.T) {
|
||||
// 2. 发起新会话咨询
|
||||
rec := intent.NewRecognizer()
|
||||
engine := coordinator.NewCoordinatorEngine(svc)
|
||||
engine.SetContextServices(svc.ContextManager(), svc.KB())
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "超声软组织刀研发咨询",
|
||||
@@ -626,7 +627,3 @@ func TestChatSession_QueryRewrite_EllipsisAndPronoun(t *testing.T) {
|
||||
t.Errorf("expected pronoun resolution to project name, got: %s", session.UserCtx.RewrittenQuery)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
func TestEngine_IntentPlan_QueryThenQuery(t *testing.T) {
|
||||
@@ -27,7 +27,7 @@ func TestEngine_IntentPlan_QueryThenQuery(t *testing.T) {
|
||||
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
User: coordinator.UserInfo{ID: "1", Name: "用户"},
|
||||
Project: coordinator.ProjectInfo{Name: "测试项目", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: coordinator.ProjectInfo{Name: "测试项目", CurrentStage: maturity.StageV01_Triage},
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestEngine_ExpectationPlusNew_ExecutesQueryKeepsConfirm(t *testing.T) {
|
||||
engine := coordinator.NewCoordinatorEngine(nil)
|
||||
|
||||
ctx := &intent.ContextSnapshot{
|
||||
CurrentStage: string(bizdev.StageV01_Triage),
|
||||
CurrentStage: string(maturity.StageV01_Triage),
|
||||
PendingExpectation: &intent.PendingExpectation{
|
||||
ExpectedIntent: intent.IntentAdvanceStage,
|
||||
AllowAffirmative: true,
|
||||
@@ -68,8 +68,8 @@ func TestEngine_ExpectationPlusNew_ExecutesQueryKeepsConfirm(t *testing.T) {
|
||||
}
|
||||
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
User: coordinator.UserInfo{ID: "1", Name: "用户"},
|
||||
Project: coordinator.ProjectInfo{Name: "项目", CurrentStage: bizdev.StageV01_Triage},
|
||||
User: coordinator.UserInfo{ID: "1", Name: "用户"},
|
||||
Project: coordinator.ProjectInfo{Name: "项目", CurrentStage: maturity.StageV01_Triage},
|
||||
PendingExpectation: ctx.PendingExpectation,
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func TestResolveRejectCard_AuthorExecuteDenied(t *testing.T) {
|
||||
func TestHandleDocGovReject_UnauthorizedAuthor(t *testing.T) {
|
||||
engine := NewCoordinatorEngine(nil)
|
||||
userCtx := &UserProjectContext{
|
||||
User: UserInfo{ID: "u1", Name: "张工", Role: "author", ProjectRole: "author"},
|
||||
User: UserInfo{ID: "u1", Name: "张工", Role: "author", ProjectRole: "author"},
|
||||
Project: ProjectInfo{Name: "NeuroPulse"},
|
||||
}
|
||||
recRes := &intent.IntentRecognitionResult{
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/kb"
|
||||
"chat-agent-system/internal/maturity"
|
||||
"chat-agent-system/internal/squad"
|
||||
)
|
||||
|
||||
@@ -28,18 +28,18 @@ type UserInfo struct {
|
||||
|
||||
// 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"`
|
||||
CreatorUserID int64 `json:"creator_user_id,omitempty"`
|
||||
ActiveWorkflowKey string `json:"active_workflow_key,omitempty"`
|
||||
WorkflowSelectionVersion int `json:"workflow_selection_version,omitempty"`
|
||||
CurrentWorkflow string `json:"current_workflow"`
|
||||
CurrentStage bizdev.MaturityStage `json:"current_stage"`
|
||||
StageRules []string `json:"stage_rules,omitempty"`
|
||||
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"`
|
||||
CreatorUserID int64 `json:"creator_user_id,omitempty"`
|
||||
ActiveWorkflowKey string `json:"active_workflow_key,omitempty"`
|
||||
WorkflowSelectionVersion int `json:"workflow_selection_version,omitempty"`
|
||||
CurrentWorkflow string `json:"current_workflow"`
|
||||
CurrentStage maturity.MaturityStage `json:"current_stage"`
|
||||
StageRules []string `json:"stage_rules,omitempty"`
|
||||
}
|
||||
|
||||
// UserDocsInfo 用户相关文档清单与认领状态
|
||||
@@ -78,20 +78,20 @@ type DocumentSummaryReader func(ctx context.Context, target string) (*ReadableDo
|
||||
// UserProjectContext 用户项目级全量统一上下文 (对话系统与执行系统共同消费)
|
||||
type UserProjectContext struct {
|
||||
mu sync.Mutex
|
||||
Version int64 `json:"version"`
|
||||
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"`
|
||||
PendingExpectation *intent.PendingExpectation `json:"pending_expectation,omitempty"`
|
||||
Version int64 `json:"version"`
|
||||
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"`
|
||||
PendingExpectation *intent.PendingExpectation `json:"pending_expectation,omitempty"`
|
||||
InteractiveCard *intent.InteractiveCardPayload `json:"interactive_card,omitempty"`
|
||||
AvailableActions []string `json:"available_actions"`
|
||||
RecentEvents []string `json:"recent_events,omitempty"`
|
||||
WorkDir string `json:"work_dir,omitempty"`
|
||||
AvailableActions []string `json:"available_actions"`
|
||||
RecentEvents []string `json:"recent_events,omitempty"`
|
||||
WorkDir string `json:"work_dir,omitempty"`
|
||||
// RecentDialogue 近轮对话(供 Phase A 对话 LLM 使用,不序列化到快照)
|
||||
RecentDialogue []DialogueTurn `json:"-"`
|
||||
// DialogueSummary 早期对话滚动压缩摘要(由 ctxmgr 维护生成,不序列化到快照)
|
||||
@@ -124,20 +124,20 @@ func NewContextAssembler() *ContextAssembler {
|
||||
}
|
||||
|
||||
// ComputeAvailableActions 根据当前成熟度阶段与角色计算允许执行的操作集合
|
||||
func ComputeAvailableActions(stage bizdev.MaturityStage, pRole string) []string {
|
||||
func ComputeAvailableActions(stage maturity.MaturityStage, pRole string) []string {
|
||||
actions := []string{"QUERY_PROGRESS", "SUPPLEMENT_INFO", "VIEW_DOC"}
|
||||
|
||||
switch stage {
|
||||
case bizdev.StageV01_Triage:
|
||||
case maturity.StageV01_Triage:
|
||||
actions = append(actions, "TRIGGER_TASK:intake", "ADVANCE_STAGE:V0.5_feasibility")
|
||||
case bizdev.StageV05_Feasibility:
|
||||
case maturity.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:
|
||||
case maturity.StageV10_Quoting:
|
||||
actions = append(actions, "TRIGGER_TASK:cdo_quote", "LOCK_COMMERCIAL")
|
||||
default:
|
||||
actions = append(actions, "ADVANCE_STAGE:V0.1_triage")
|
||||
@@ -147,7 +147,7 @@ func ComputeAvailableActions(stage bizdev.MaturityStage, pRole string) []string
|
||||
}
|
||||
|
||||
// ComputeAvailableActionsWithWorkflow 结合激活工作流、成熟度阶段与角色权限计算可用操作集合
|
||||
func ComputeAvailableActionsWithWorkflow(stage bizdev.MaturityStage, pRole string, activeWorkflow string, isCreator bool) []string {
|
||||
func ComputeAvailableActionsWithWorkflow(stage maturity.MaturityStage, pRole string, activeWorkflow string, isCreator bool) []string {
|
||||
actions := ComputeAvailableActions(stage, pRole)
|
||||
actions = appendUniqueCapability(actions, "QUERY_WORKFLOW")
|
||||
if isCreator {
|
||||
@@ -208,7 +208,7 @@ func (ctx *UserProjectContext) ToSnapshot() *intent.ContextSnapshot {
|
||||
}
|
||||
|
||||
// BuildNextExpectation 根据当前成熟度阶段与项目名构造参谋下一步建议选项草稿
|
||||
func BuildNextExpectation(stage bizdev.MaturityStage, projectName string) *intent.PendingExpectation {
|
||||
func BuildNextExpectation(stage maturity.MaturityStage, projectName string) *intent.PendingExpectation {
|
||||
if projectName == "" {
|
||||
projectName = "本项目"
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func BuildNextExpectation(stage bizdev.MaturityStage, projectName string) *inten
|
||||
var snippet string
|
||||
|
||||
switch stage {
|
||||
case bizdev.StageV01_Triage:
|
||||
case maturity.StageV01_Triage:
|
||||
snippet = fmt.Sprintf("项目「%s」当前处于初始摸底期,基准产品画像已梳理完成。", projectName)
|
||||
options = []intent.ExpectationOption{
|
||||
{
|
||||
@@ -226,7 +226,7 @@ func BuildNextExpectation(stage bizdev.MaturityStage, projectName string) *inten
|
||||
Description: "自动比选技术路线,并梳理分类路径与型检标准",
|
||||
Intent: intent.IntentAdvanceStage,
|
||||
Slots: map[string]string{
|
||||
intent.SlotTargetStage: string(bizdev.StageV05_Feasibility),
|
||||
intent.SlotTargetStage: string(maturity.StageV05_Feasibility),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -246,7 +246,7 @@ func BuildNextExpectation(stage bizdev.MaturityStage, projectName string) *inten
|
||||
},
|
||||
}
|
||||
|
||||
case bizdev.StageV05_Feasibility:
|
||||
case maturity.StageV05_Feasibility:
|
||||
snippet = fmt.Sprintf("项目「%s」已完成方案成型与法规对齐,具备进入商务核算的条件。", projectName)
|
||||
options = []intent.ExpectationOption{
|
||||
{
|
||||
@@ -255,7 +255,7 @@ func BuildNextExpectation(stage bizdev.MaturityStage, projectName string) *inten
|
||||
Description: "生成精细化 CDO 工时与成本核算表,锁定立项商务方案",
|
||||
Intent: intent.IntentAdvanceStage,
|
||||
Slots: map[string]string{
|
||||
intent.SlotTargetStage: string(bizdev.StageV10_Quoting),
|
||||
intent.SlotTargetStage: string(maturity.StageV10_Quoting),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -275,7 +275,7 @@ func BuildNextExpectation(stage bizdev.MaturityStage, projectName string) *inten
|
||||
},
|
||||
}
|
||||
|
||||
case bizdev.StageV10_Quoting:
|
||||
case maturity.StageV10_Quoting:
|
||||
snippet = fmt.Sprintf("项目「%s」已完成商务锁定,报价核算表已就绪。", projectName)
|
||||
options = []intent.ExpectationOption{
|
||||
{
|
||||
@@ -307,7 +307,7 @@ func BuildNextExpectation(stage bizdev.MaturityStage, projectName string) *inten
|
||||
Description: "快速沉淀第一版立项画像并为您准备沟通话术",
|
||||
Intent: intent.IntentAdvanceStage,
|
||||
Slots: map[string]string{
|
||||
intent.SlotTargetStage: string(bizdev.StageV01_Triage),
|
||||
intent.SlotTargetStage: string(maturity.StageV01_Triage),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -381,15 +381,15 @@ func (a *ContextAssembler) AssembleFromWorkspace(workDir string, user UserInfo)
|
||||
ctx.Project.CurrentWorkflow = ctx.Project.ActiveWorkflowKey
|
||||
}
|
||||
if strings.HasPrefix(ctx.Project.CurrentWorkflow, "V0.1") || ctx.Project.CurrentWorkflow == "intake" {
|
||||
ctx.Project.CurrentStage = bizdev.StageV01_Triage
|
||||
ctx.Project.CurrentStage = maturity.StageV01_Triage
|
||||
} else if strings.HasPrefix(ctx.Project.CurrentWorkflow, "V0.5") {
|
||||
ctx.Project.CurrentStage = bizdev.StageV05_Feasibility
|
||||
ctx.Project.CurrentStage = maturity.StageV05_Feasibility
|
||||
} else if strings.HasPrefix(ctx.Project.CurrentWorkflow, "V1.0") {
|
||||
ctx.Project.CurrentStage = bizdev.StageV10_Quoting
|
||||
ctx.Project.CurrentStage = maturity.StageV10_Quoting
|
||||
}
|
||||
|
||||
if ctx.Project.CurrentStage == "" {
|
||||
ctx.Project.CurrentStage = bizdev.StageV01_Triage
|
||||
ctx.Project.CurrentStage = maturity.StageV01_Triage
|
||||
}
|
||||
|
||||
isCreator := false
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
func TestComputeAvailableActions(t *testing.T) {
|
||||
actionsV01 := coordinator.ComputeAvailableActions(bizdev.StageV01_Triage, "composer")
|
||||
actionsV01 := coordinator.ComputeAvailableActions(maturity.StageV01_Triage, "composer")
|
||||
foundAdvance := false
|
||||
for _, a := range actionsV01 {
|
||||
if a == "ADVANCE_STAGE:V0.5_feasibility" {
|
||||
@@ -22,7 +22,7 @@ func TestComputeAvailableActions(t *testing.T) {
|
||||
t.Errorf("expected V0.1 actions to contain advance to V0.5: %v", actionsV01)
|
||||
}
|
||||
|
||||
actionsV05 := coordinator.ComputeAvailableActions(bizdev.StageV05_Feasibility, "composer")
|
||||
actionsV05 := coordinator.ComputeAvailableActions(maturity.StageV05_Feasibility, "composer")
|
||||
foundAdvanceQuote := false
|
||||
for _, a := range actionsV05 {
|
||||
if a == "ADVANCE_STAGE:V1.0_quoting" {
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/agent"
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
type scriptedDialogueBackend struct {
|
||||
@@ -49,7 +49,7 @@ func TestDialogueLLM_CasualChatUsesBackend(t *testing.T) {
|
||||
Project: ProjectInfo{
|
||||
ID: "p-dialogue-1",
|
||||
Name: "CUSA-Dialogue-Test",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
BlackboardFacts: map[string]string{},
|
||||
RecentDialogue: []DialogueTurn{
|
||||
@@ -128,7 +128,7 @@ func TestDialogueLLM_AmbiguousFallbackUsesBackend(t *testing.T) {
|
||||
}
|
||||
engine := NewCoordinatorEngineWithDialogue(nil, backend, t.TempDir())
|
||||
userCtx := &UserProjectContext{
|
||||
Project: ProjectInfo{Name: "CUSA", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{Name: "CUSA", CurrentStage: maturity.StageV01_Triage},
|
||||
}
|
||||
rec := &intent.IntentRecognitionResult{
|
||||
RawInput: "请详细解释压电换能器的逆压电效应与变幅杆阻抗匹配。",
|
||||
@@ -158,7 +158,7 @@ func TestDialogueLLM_FallbackToTemplateOnBackendFailure(t *testing.T) {
|
||||
backend := &scriptedDialogueBackend{fail: true}
|
||||
engine := NewCoordinatorEngineWithDialogue(nil, backend, t.TempDir())
|
||||
userCtx := &UserProjectContext{
|
||||
Project: ProjectInfo{Name: "CUSA", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{Name: "CUSA", CurrentStage: maturity.StageV01_Triage},
|
||||
}
|
||||
rec := &intent.IntentRecognitionResult{
|
||||
RawInput: "你好",
|
||||
@@ -190,7 +190,7 @@ func TestDialogueLLM_PersonalizedGuidanceAndWarmPersona(t *testing.T) {
|
||||
User: UserInfo{Name: "张工", Role: "engineer", ProjectRole: "composer"},
|
||||
Project: ProjectInfo{
|
||||
Name: "CUSA-Warm",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
PersonalizedGuidance: "【用户个性化工作习惯与偏好指导 (Memory Injection)】\n• 沟通风格:该用户偏好【结构精炼、结论先行】\n• 重点关注:该用户较关心【法规标准合规与审评审批风险】\n",
|
||||
Pending: PendingItems{
|
||||
@@ -236,7 +236,7 @@ func TestDialogueLLM_QueryProgressNoBriefUsesBackend(t *testing.T) {
|
||||
engine := NewCoordinatorEngineWithDialogue(nil, backend, t.TempDir())
|
||||
userCtx := &UserProjectContext{
|
||||
User: UserInfo{Name: "张工", ProjectRole: "composer"},
|
||||
Project: ProjectInfo{Name: "医疗器械研发项目", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{Name: "医疗器械研发项目", CurrentStage: maturity.StageV01_Triage},
|
||||
}
|
||||
rec := &intent.IntentRecognitionResult{
|
||||
RawInput: "简单分析一下这个项目有什么风险",
|
||||
@@ -269,7 +269,7 @@ func TestDialogueLLM_QueryProgressNoBriefFallsBackToSynthesizedTemplate(t *testi
|
||||
backend := &scriptedDialogueBackend{fail: true}
|
||||
engine := NewCoordinatorEngineWithDialogue(nil, backend, t.TempDir())
|
||||
userCtx := &UserProjectContext{
|
||||
Project: ProjectInfo{Name: "医疗器械研发项目", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{Name: "医疗器械研发项目", CurrentStage: maturity.StageV01_Triage},
|
||||
}
|
||||
rec := &intent.IntentRecognitionResult{
|
||||
RawInput: "简单分析一下这个项目有什么风险",
|
||||
|
||||
@@ -13,11 +13,12 @@ import (
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/agent"
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/app/stageflow"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/kb"
|
||||
"chat-agent-system/internal/maturity"
|
||||
"chat-agent-system/internal/projectinstance"
|
||||
"chat-agent-system/internal/squad"
|
||||
"chat-agent-system/internal/stream"
|
||||
@@ -72,19 +73,19 @@ type CoordinationResult struct {
|
||||
|
||||
// CoordinatorEngine L2 协调引擎
|
||||
type CoordinatorEngine struct {
|
||||
bizdevSvc bizdev.BizdevService
|
||||
stageTasks StageTaskRunner
|
||||
instSvc *projectinstance.Service
|
||||
assembler *ContextAssembler
|
||||
dialogueBackend agent.Backend
|
||||
dataDir string
|
||||
ctxMgr *ctxmgr.ContextManager
|
||||
kbClient *kb.Client
|
||||
}
|
||||
|
||||
// StageTaskRunner is the application owner for ExecuteTask / ExecuteStage.
|
||||
// Wired from app/stageflow; tests may leave it nil and fall back to bizdevSvc.
|
||||
type StageTaskRunner interface {
|
||||
ExecuteTask(ctx context.Context, req bizdev.TaskRunRequest) (*bizdev.TaskRunResult, error)
|
||||
ExecuteStage(ctx context.Context, req bizdev.StageRunRequest) (*bizdev.StageRunResult, error)
|
||||
ExecuteTask(ctx context.Context, req stageflow.TaskRunRequest) (*stageflow.TaskRunResult, error)
|
||||
ExecuteStage(ctx context.Context, req stageflow.StageRunRequest) (*stageflow.StageRunResult, error)
|
||||
}
|
||||
|
||||
func (e *CoordinatorEngine) SetStageTaskRunner(r StageTaskRunner) {
|
||||
@@ -97,10 +98,14 @@ func (e *CoordinatorEngine) tasks() StageTaskRunner {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
if e.stageTasks != nil {
|
||||
return e.stageTasks
|
||||
return e.stageTasks
|
||||
}
|
||||
|
||||
func (e *CoordinatorEngine) SetContextServices(ctxMgr *ctxmgr.ContextManager, kbClient *kb.Client) {
|
||||
if e != nil {
|
||||
e.ctxMgr = ctxMgr
|
||||
e.kbClient = kbClient
|
||||
}
|
||||
return e.bizdevSvc
|
||||
}
|
||||
|
||||
// SetInstanceService 注入项目工作流实例服务(对话推进与实例门禁合流)。
|
||||
@@ -110,17 +115,17 @@ func (e *CoordinatorEngine) SetInstanceService(svc *projectinstance.Service) {
|
||||
}
|
||||
}
|
||||
|
||||
func NewCoordinatorEngine(bizdevSvc bizdev.BizdevService) *CoordinatorEngine {
|
||||
func NewCoordinatorEngine(runner StageTaskRunner) *CoordinatorEngine {
|
||||
return &CoordinatorEngine{
|
||||
bizdevSvc: bizdevSvc,
|
||||
assembler: NewContextAssembler(),
|
||||
stageTasks: runner,
|
||||
assembler: NewContextAssembler(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewCoordinatorEngineWithDialogue 注入对话 LLM 后端(Phase A:CASUAL / AMBIGUOUS)
|
||||
func NewCoordinatorEngineWithDialogue(bizdevSvc bizdev.BizdevService, dialogueBackend agent.Backend, dataDir string) *CoordinatorEngine {
|
||||
func NewCoordinatorEngineWithDialogue(runner StageTaskRunner, dialogueBackend agent.Backend, dataDir string) *CoordinatorEngine {
|
||||
return &CoordinatorEngine{
|
||||
bizdevSvc: bizdevSvc,
|
||||
stageTasks: runner,
|
||||
assembler: NewContextAssembler(),
|
||||
dialogueBackend: dialogueBackend,
|
||||
dataDir: dataDir,
|
||||
@@ -324,10 +329,10 @@ func (e *CoordinatorEngine) ProcessIntent(
|
||||
|
||||
// enrichAdvisorBriefWithCases 结合上下文与意图槽位检索相似标杆案例并注入参谋锦囊
|
||||
func (e *CoordinatorEngine) enrichAdvisorBriefWithCases(ctx context.Context, brief *squad.AdvisorBriefing, userCtx *UserProjectContext, slots map[string]string) {
|
||||
if brief == nil || e.bizdevSvc == nil {
|
||||
if brief == nil || e.ctxMgr == nil {
|
||||
return
|
||||
}
|
||||
ctxMgr := e.bizdevSvc.ContextManager()
|
||||
ctxMgr := e.ctxMgr
|
||||
if ctxMgr == nil {
|
||||
return
|
||||
}
|
||||
@@ -414,7 +419,7 @@ func (e *CoordinatorEngine) handleAmbiguousConsult(ctx context.Context, cand *in
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf("完全理解您想再掂量一下。针对「%s」目前的节点,我帮您快速对照一下:\n\n", projName))
|
||||
|
||||
if currentStage == bizdev.StageV01_Triage {
|
||||
if currentStage == maturity.StageV01_Triage {
|
||||
sb.WriteString("• 若推进 V0.5(方案成型与法规对齐):\n")
|
||||
sb.WriteString(" 我可帮您梳理初步架构与注册分类路径,并预估型检成本,便于与客户深入沟通;\n")
|
||||
sb.WriteString("• 若先放一放 / 多做调研:\n")
|
||||
@@ -761,9 +766,9 @@ func (e *CoordinatorEngine) handleAdvanceStage(ctx context.Context, cand *intent
|
||||
}
|
||||
|
||||
targetStageStr := cand.FilledSlots[intent.SlotTargetStage]
|
||||
targetStage := bizdev.MaturityStage(targetStageStr)
|
||||
targetStage := maturity.MaturityStage(targetStageStr)
|
||||
if targetStage == "" {
|
||||
targetStage = bizdev.StageV05_Feasibility
|
||||
targetStage = maturity.StageV05_Feasibility
|
||||
}
|
||||
|
||||
streamer := stream.FromContext(ctx)
|
||||
@@ -835,7 +840,7 @@ func (e *CoordinatorEngine) handleAdvanceStage(ctx context.Context, cand *intent
|
||||
}
|
||||
|
||||
// 3. 调用底层 L3 调度器执行阶段跃迁
|
||||
stageRes, err := e.tasks().ExecuteStage(ctx, bizdev.StageRunRequest{
|
||||
stageRes, err := e.tasks().ExecuteStage(ctx, stageflow.StageRunRequest{
|
||||
Stage: targetStage,
|
||||
ProjectName: userCtx.Project.Name,
|
||||
CustomerName: userCtx.Project.CustomerName,
|
||||
@@ -929,7 +934,7 @@ func (e *CoordinatorEngine) handleTriggerTask(ctx context.Context, cand *intent.
|
||||
fmt.Sscanf(userCtx.User.ID, "%d", &userID)
|
||||
}
|
||||
|
||||
taskRes, err := e.tasks().ExecuteTask(ctx, bizdev.TaskRunRequest{
|
||||
taskRes, err := e.tasks().ExecuteTask(ctx, stageflow.TaskRunRequest{
|
||||
TaskKey: taskKey,
|
||||
ProjectName: userCtx.Project.Name,
|
||||
CustomerName: userCtx.Project.CustomerName,
|
||||
@@ -999,9 +1004,9 @@ func (e *CoordinatorEngine) handleTriggerTask(ctx context.Context, cand *intent.
|
||||
|
||||
// formatTriggerTaskReply builds sync coordinator copy for a TaskRunResult.
|
||||
// Pending high-risk candidates must not claim "正文已保存 / 已完成".
|
||||
func formatTriggerTaskReply(taskRes *bizdev.TaskRunResult, outPath string) (reply string, taskStatus string) {
|
||||
func formatTriggerTaskReply(taskRes *stageflow.TaskRunResult, outPath string) (reply string, taskStatus string) {
|
||||
if taskRes == nil {
|
||||
return "任务执行失败。", bizdev.TaskStatusFailed
|
||||
return "任务执行失败。", stageflow.TaskStatusFailed
|
||||
}
|
||||
taskStatus = taskRes.TerminalStatus()
|
||||
if taskRes.AwaitsAgentConfirmation() {
|
||||
@@ -1019,7 +1024,7 @@ func formatTriggerTaskReply(taskRes *bizdev.TaskRunResult, outPath string) (repl
|
||||
return sb.String(), taskStatus
|
||||
}
|
||||
|
||||
func attachTaskRunProjection(res *CoordinationResult, taskRes *bizdev.TaskRunResult) {
|
||||
func attachTaskRunProjection(res *CoordinationResult, taskRes *stageflow.TaskRunResult) {
|
||||
if res == nil || taskRes == nil {
|
||||
return
|
||||
}
|
||||
@@ -1072,12 +1077,12 @@ func (e *CoordinatorEngine) handleTriggerAdhocTask(ctx context.Context, cand *in
|
||||
|
||||
// 任务简报材料化:作为首要输入材料注入工作区(context/materials_text/task_brief.md),
|
||||
// 供 organizer 专员在容器内直接读到用户原始诉求(否则首步将报"无材料可整理")
|
||||
briefMaterial := bizdev.MaterialInput{
|
||||
briefMaterial := stageflow.MaterialInput{
|
||||
Filename: "task_brief.md",
|
||||
Content: []byte(fmt.Sprintf("# 任务简报(用户原始诉求,权威等级:primary_evidence)\n\n%s\n", brief)),
|
||||
}
|
||||
|
||||
taskRes, err := e.tasks().ExecuteTask(ctx, bizdev.TaskRunRequest{
|
||||
taskRes, err := e.tasks().ExecuteTask(ctx, stageflow.TaskRunRequest{
|
||||
TaskKey: taskKey,
|
||||
Title: title,
|
||||
ProjectName: userCtx.Project.Name,
|
||||
@@ -1086,7 +1091,7 @@ func (e *CoordinatorEngine) handleTriggerAdhocTask(ctx context.Context, cand *in
|
||||
IntendedUse: userCtx.Project.IntendedUse,
|
||||
TargetMarket: userCtx.Project.TargetMarket,
|
||||
Fields: userCtx.BlackboardFacts,
|
||||
Materials: []bizdev.MaterialInput{briefMaterial},
|
||||
Materials: []stageflow.MaterialInput{briefMaterial},
|
||||
AutoRepair: true,
|
||||
ProjectID: projectID,
|
||||
UserID: userID,
|
||||
@@ -1671,7 +1676,7 @@ func (e *CoordinatorEngine) handleQueryRegulations(ctx context.Context, cand *in
|
||||
}
|
||||
|
||||
var hits []kb.HitItem
|
||||
if e != nil && e.bizdevSvc != nil && e.bizdevSvc.KB() != nil && strings.TrimSpace(searchQuery) != "" {
|
||||
if e != nil && e.kbClient != nil && strings.TrimSpace(searchQuery) != "" {
|
||||
cacheKey := ctxmgr.HashKey("regulatory_search", searchQuery)
|
||||
cache := ctxmgr.GetGlobalCache()
|
||||
if cached, ok := cache.Get(ctxmgr.LayerC1Search, cacheKey); ok {
|
||||
@@ -1679,7 +1684,7 @@ func (e *CoordinatorEngine) handleQueryRegulations(ctx context.Context, cand *in
|
||||
hits = ch
|
||||
}
|
||||
} else {
|
||||
kbHits, err := e.bizdevSvc.KB().Search(ctx, searchQuery, kb.SearchOptions{
|
||||
kbHits, err := e.kbClient.Search(ctx, searchQuery, kb.SearchOptions{
|
||||
Domains: []kb.KnowledgeDomain{kb.DomainRegulatory},
|
||||
Limit: 5,
|
||||
})
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
// TestEngine_ClarificationBeforeAmbiguousConsult 缺驳回理由必须返回定向澄清,不得进入参谋模糊咨询
|
||||
@@ -17,7 +17,7 @@ func TestEngine_ClarificationBeforeAmbiguousConsult(t *testing.T) {
|
||||
|
||||
ctx := &intent.ContextSnapshot{
|
||||
SnapshotID: "ctx_engine_clarify",
|
||||
CurrentStage: string(bizdev.StageV05_Feasibility),
|
||||
CurrentStage: string(maturity.StageV05_Feasibility),
|
||||
ActiveDocID: "doc-002",
|
||||
DocLifecycleState: "reviewing",
|
||||
UserDocRole: "reviewer",
|
||||
@@ -38,7 +38,7 @@ func TestEngine_ClarificationBeforeAmbiguousConsult(t *testing.T) {
|
||||
User: coordinator.UserInfo{ID: "user_102", Name: "李审核", Role: "reviewer", ProjectRole: "reviewer"},
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "智能内窥镜项目",
|
||||
CurrentStage: bizdev.StageV05_Feasibility,
|
||||
CurrentStage: maturity.StageV05_Feasibility,
|
||||
},
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
@@ -75,8 +75,8 @@ func TestEngine_ClaimQueryMustNotExecuteWrite(t *testing.T) {
|
||||
}
|
||||
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
User: coordinator.UserInfo{ID: "user_101", Name: "张工", Role: "engineer", ProjectRole: "composer"},
|
||||
Project: coordinator.ProjectInfo{Name: "测试项目"},
|
||||
User: coordinator.UserInfo{ID: "user_101", Name: "张工", Role: "engineer", ProjectRole: "composer"},
|
||||
Project: coordinator.ProjectInfo{Name: "测试项目"},
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ func TestEngine_RunStatusQuery_WithWorkDir(t *testing.T) {
|
||||
}
|
||||
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
User: coordinator.UserInfo{ID: "1", Name: "用户"},
|
||||
Project: coordinator.ProjectInfo{Name: "项目"},
|
||||
WorkDir: "/data/dev/ws-123",
|
||||
User: coordinator.UserInfo{ID: "1", Name: "用户"},
|
||||
Project: coordinator.ProjectInfo{Name: "项目"},
|
||||
WorkDir: "/data/dev/ws-123",
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/maturity"
|
||||
"chat-agent-system/internal/squad"
|
||||
"strings"
|
||||
)
|
||||
@@ -75,7 +75,7 @@ func TestCoordinatorEngine_QueryProgress_NoBrief_SubstantiveReply(t *testing.T)
|
||||
Name: "医疗器械研发项目",
|
||||
CustomerName: "北京水木东方",
|
||||
CurrentWorkflow: "intake",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func TestCoordinatorEngine_AdvanceStage(t *testing.T) {
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "超声测试项目",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
User: coordinator.UserInfo{
|
||||
ProjectRole: "composer",
|
||||
@@ -167,7 +167,7 @@ func TestCoordinatorEngine_AdvanceStage(t *testing.T) {
|
||||
TopIntent: &intent.CandidateIntent{
|
||||
Intent: intent.IntentAdvanceStage,
|
||||
FilledSlots: map[string]string{
|
||||
intent.SlotTargetStage: string(bizdev.StageV05_Feasibility),
|
||||
intent.SlotTargetStage: string(maturity.StageV05_Feasibility),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -180,7 +180,7 @@ func TestCoordinatorEngine_AdvanceStage(t *testing.T) {
|
||||
if res.Status != coordinator.StatusAccepted {
|
||||
t.Errorf("expected status ACCEPTED, got %s", res.Status)
|
||||
}
|
||||
if userCtx.Project.CurrentStage != bizdev.StageV05_Feasibility {
|
||||
if userCtx.Project.CurrentStage != maturity.StageV05_Feasibility {
|
||||
t.Errorf("expected stage V0.5_feasibility, got %s", userCtx.Project.CurrentStage)
|
||||
}
|
||||
}
|
||||
@@ -190,9 +190,9 @@ func TestCoordinatorEngine_DeclineExpectation(t *testing.T) {
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "超声测试项目",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
PendingExpectation: coordinator.BuildNextExpectation(bizdev.StageV01_Triage, "超声测试项目"),
|
||||
PendingExpectation: coordinator.BuildNextExpectation(maturity.StageV01_Triage, "超声测试项目"),
|
||||
}
|
||||
|
||||
recRes := &intent.IntentRecognitionResult{
|
||||
@@ -225,7 +225,7 @@ func TestCoordinatorEngine_AmbiguousConsult(t *testing.T) {
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "超声测试项目",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ func TestCoordinatorEngine_AdvanceStageWithPatch(t *testing.T) {
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "超声测试项目",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
BlackboardFacts: make(map[string]string),
|
||||
}
|
||||
@@ -266,8 +266,8 @@ func TestCoordinatorEngine_AdvanceStageWithPatch(t *testing.T) {
|
||||
Intent: intent.IntentAdvanceStage,
|
||||
Branch: intent.BranchExpectationHit,
|
||||
FilledSlots: map[string]string{
|
||||
intent.SlotTargetStage: string(bizdev.StageV05_Feasibility),
|
||||
"target_market": "欧洲CE",
|
||||
intent.SlotTargetStage: string(maturity.StageV05_Feasibility),
|
||||
"target_market": "欧洲CE",
|
||||
},
|
||||
PatchSlots: map[string]string{
|
||||
"target_market": "欧洲CE",
|
||||
@@ -580,9 +580,9 @@ func TestCoordinatorEngine_RejectExpectationAndAffirmativeChain(t *testing.T) {
|
||||
TopIntent: &intent.CandidateIntent{
|
||||
Intent: intent.IntentDocGovReviewReject,
|
||||
FilledSlots: map[string]string{
|
||||
intent.SlotTargetDoc: "doc_cardio_01",
|
||||
intent.SlotRejectReason: "第3节缺少血液相容性溶血试验评价指标",
|
||||
intent.SlotTargetSection: "第3节",
|
||||
intent.SlotTargetDoc: "doc_cardio_01",
|
||||
intent.SlotRejectReason: "第3节缺少血液相容性溶血试验评价指标",
|
||||
intent.SlotTargetSection: "第3节",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -982,5 +982,3 @@ func TestCoordinatorEngine_TestingAnalysis(t *testing.T) {
|
||||
t.Errorf("reply must not contain commercial triage boilerplate, got: %s", res.NaturalReply)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,9 +36,9 @@ func (e *CoordinatorEngine) handleSwitchWorkflow(_ context.Context, cand *intent
|
||||
|
||||
if userCtx.Project.ActiveWorkflowKey == targetWF {
|
||||
return &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentSwitchWorkflow,
|
||||
NaturalReply: fmt.Sprintf("当前项目已激活工作流「%s」,无需重复切换。", targetWF),
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentSwitchWorkflow,
|
||||
NaturalReply: fmt.Sprintf("当前项目已激活工作流「%s」,无需重复切换。", targetWF),
|
||||
UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}
|
||||
@@ -83,9 +83,9 @@ func (e *CoordinatorEngine) handleTriggerWorkflow(_ context.Context, cand *inten
|
||||
targetWF, workflowDisplayName(targetWF),
|
||||
)
|
||||
return &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentTriggerWorkflow,
|
||||
NaturalReply: msg,
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentTriggerWorkflow,
|
||||
NaturalReply: msg,
|
||||
UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}
|
||||
@@ -107,9 +107,9 @@ func (e *CoordinatorEngine) handleQueryWorkflowStatus(_ context.Context, _ *inte
|
||||
}
|
||||
}
|
||||
return &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentQueryWorkflowStatus,
|
||||
NaturalReply: sb.String(),
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentQueryWorkflowStatus,
|
||||
NaturalReply: sb.String(),
|
||||
UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}
|
||||
@@ -129,9 +129,9 @@ func (e *CoordinatorEngine) handleQueryDocStatus(ctx context.Context, cand *inte
|
||||
defaultStr(lifecycle, "请在工作台文档面板查看详情"),
|
||||
)
|
||||
return &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentQueryDocStatus,
|
||||
NaturalReply: reply,
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentQueryDocStatus,
|
||||
NaturalReply: reply,
|
||||
UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}
|
||||
@@ -149,18 +149,18 @@ func (e *CoordinatorEngine) handleHelpCapabilities(_ context.Context, _ *intent.
|
||||
}
|
||||
sb.WriteString("\n高风险操作(工作流切换、文档审批、阶段推进)需要明确确认后才会执行。")
|
||||
return &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentHelpCapabilities,
|
||||
NaturalReply: sb.String(),
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentHelpCapabilities,
|
||||
NaturalReply: sb.String(),
|
||||
UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *CoordinatorEngine) handleUnsupportedAction(_ context.Context, _ *intent.CandidateIntent, userCtx *UserProjectContext) (*CoordinationResult, error) {
|
||||
return &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentUnsupportedAction,
|
||||
NaturalReply: "我理解您的诉求,但该操作目前仅支持通过界面按钮完成(如下载、共享、批量导出、直接修改受控正文等),暂不支持自然语言自动执行。",
|
||||
Status: StatusAccepted,
|
||||
Intent: intent.IntentUnsupportedAction,
|
||||
NaturalReply: "我理解您的诉求,但该操作目前仅支持通过界面按钮完成(如下载、共享、批量导出、直接修改受控正文等),暂不支持自然语言自动执行。",
|
||||
UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}
|
||||
@@ -244,8 +244,8 @@ func buildWorkflowSwitchExpectation(targetWF string, userCtx *UserProjectContext
|
||||
},
|
||||
},
|
||||
Payload: map[string]string{
|
||||
intent.SlotTargetWorkflow: targetWF,
|
||||
"selection_version": fmt.Sprintf("%d", userCtx.Project.WorkflowSelectionVersion),
|
||||
intent.SlotTargetWorkflow: targetWF,
|
||||
"selection_version": fmt.Sprintf("%d", userCtx.Project.WorkflowSelectionVersion),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
func TestEngine_SwitchWorkflow_NonCreatorRejected(t *testing.T) {
|
||||
@@ -24,11 +24,11 @@ func TestEngine_SwitchWorkflow_NonCreatorRejected(t *testing.T) {
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
User: coordinator.UserInfo{ID: "42", Name: "张工", ProjectRole: "composer"},
|
||||
Project: coordinator.ProjectInfo{
|
||||
Name: "测试项目",
|
||||
CreatorUserID: 1,
|
||||
ActiveWorkflowKey: "main",
|
||||
Name: "测试项目",
|
||||
CreatorUserID: 1,
|
||||
ActiveWorkflowKey: "main",
|
||||
WorkflowSelectionVersion: 1,
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
},
|
||||
AvailableActions: []string{"SWITCH_WORKFLOW"},
|
||||
BlackboardFacts: map[string]string{},
|
||||
@@ -61,7 +61,7 @@ func TestEngine_QueryWorkflowStatus(t *testing.T) {
|
||||
Name: "测试项目",
|
||||
ActiveWorkflowKey: "product_manager",
|
||||
WorkflowSelectionVersion: 2,
|
||||
CurrentStage: bizdev.StageV05_Feasibility,
|
||||
CurrentStage: maturity.StageV05_Feasibility,
|
||||
},
|
||||
AvailableActions: []string{"QUERY_WORKFLOW", "TRIGGER_WORKFLOW:product_manager"},
|
||||
BlackboardFacts: map[string]string{},
|
||||
@@ -89,10 +89,10 @@ func TestEngine_HelpCapabilities(t *testing.T) {
|
||||
}
|
||||
|
||||
userCtx := &coordinator.UserProjectContext{
|
||||
User: coordinator.UserInfo{ID: "1", Name: "用户"},
|
||||
Project: coordinator.ProjectInfo{Name: "项目"},
|
||||
User: coordinator.UserInfo{ID: "1", Name: "用户"},
|
||||
Project: coordinator.ProjectInfo{Name: "项目"},
|
||||
AvailableActions: []string{"QUERY_PROGRESS", "SWITCH_WORKFLOW"},
|
||||
BlackboardFacts: map[string]string{},
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
|
||||
res, err := engine.ProcessIntent(context.Background(), recRes, userCtx)
|
||||
|
||||
@@ -4,11 +4,12 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/app/stageflow"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/kb"
|
||||
"chat-agent-system/internal/maturity"
|
||||
"chat-agent-system/internal/projectinstance"
|
||||
"chat-agent-system/internal/squad"
|
||||
"chat-agent-system/internal/storage"
|
||||
@@ -18,14 +19,14 @@ type countingBizdev struct {
|
||||
stageCalls int
|
||||
}
|
||||
|
||||
func (c *countingBizdev) ListTasks() []bizdev.TaskMeta { return nil }
|
||||
func (c *countingBizdev) ListStages() []bizdev.StageMeta { return nil }
|
||||
func (c *countingBizdev) ExecuteTask(_ context.Context, _ bizdev.TaskRunRequest) (*bizdev.TaskRunResult, error) {
|
||||
return &bizdev.TaskRunResult{}, nil
|
||||
func (c *countingBizdev) ListTasks() []stageflow.TaskMeta { return nil }
|
||||
func (c *countingBizdev) ListStages() []stageflow.StageMeta { return nil }
|
||||
func (c *countingBizdev) ExecuteTask(_ context.Context, _ stageflow.TaskRunRequest) (*stageflow.TaskRunResult, error) {
|
||||
return &stageflow.TaskRunResult{}, nil
|
||||
}
|
||||
func (c *countingBizdev) ExecuteStage(_ context.Context, _ bizdev.StageRunRequest) (*bizdev.StageRunResult, error) {
|
||||
func (c *countingBizdev) ExecuteStage(_ context.Context, _ stageflow.StageRunRequest) (*stageflow.StageRunResult, error) {
|
||||
c.stageCalls++
|
||||
return &bizdev.StageRunResult{StageTitle: "legacy"}, nil
|
||||
return &stageflow.StageRunResult{StageTitle: "legacy"}, nil
|
||||
}
|
||||
func (c *countingBizdev) InspectWorkspace(_ context.Context, _ string) (*squad.WorkspaceState, error) {
|
||||
return nil, nil
|
||||
@@ -58,14 +59,14 @@ func TestDialogueAdvanceStage_LiveInstanceDoesNotUseBizdev(t *testing.T) {
|
||||
engine.SetInstanceService(instSvc)
|
||||
|
||||
userCtx := &UserProjectContext{
|
||||
Project: ProjectInfo{ID: "55", CreatorUserID: 1, CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{ID: "55", CreatorUserID: 1, CurrentStage: maturity.StageV01_Triage},
|
||||
User: UserInfo{ID: "1", ProjectRole: "owner"},
|
||||
}
|
||||
recRes := &intent.IntentRecognitionResult{
|
||||
TopIntent: &intent.CandidateIntent{
|
||||
Intent: intent.IntentAdvanceStage,
|
||||
FilledSlots: map[string]string{
|
||||
intent.SlotTargetStage: string(bizdev.StageV05_Feasibility),
|
||||
intent.SlotTargetStage: string(maturity.StageV05_Feasibility),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/kb"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
func TestMemoryComposer_HierarchyAndPriority(t *testing.T) {
|
||||
@@ -33,7 +33,7 @@ func TestMemoryComposer_HierarchyAndPriority(t *testing.T) {
|
||||
Name: "超声切割止血系统",
|
||||
DeviceType: "有源手术器械",
|
||||
TargetMarket: "国内+CE",
|
||||
CurrentStage: bizdev.StageV01_Triage,
|
||||
CurrentStage: maturity.StageV01_Triage,
|
||||
CurrentWorkflow: "立项摸底",
|
||||
},
|
||||
TaskState: taskState,
|
||||
|
||||
@@ -6,25 +6,26 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/app/stageflow"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/kb"
|
||||
"chat-agent-system/internal/maturity"
|
||||
"chat-agent-system/internal/squad"
|
||||
"chat-agent-system/internal/storage"
|
||||
)
|
||||
|
||||
type pendingReplyBizdev struct {
|
||||
res *bizdev.TaskRunResult
|
||||
res *stageflow.TaskRunResult
|
||||
}
|
||||
|
||||
func (p *pendingReplyBizdev) ListTasks() []bizdev.TaskMeta { return nil }
|
||||
func (p *pendingReplyBizdev) ListStages() []bizdev.StageMeta { return nil }
|
||||
func (p *pendingReplyBizdev) ExecuteTask(_ context.Context, _ bizdev.TaskRunRequest) (*bizdev.TaskRunResult, error) {
|
||||
func (p *pendingReplyBizdev) ListTasks() []stageflow.TaskMeta { return nil }
|
||||
func (p *pendingReplyBizdev) ListStages() []stageflow.StageMeta { return nil }
|
||||
func (p *pendingReplyBizdev) ExecuteTask(_ context.Context, _ stageflow.TaskRunRequest) (*stageflow.TaskRunResult, error) {
|
||||
return p.res, nil
|
||||
}
|
||||
func (p *pendingReplyBizdev) ExecuteStage(_ context.Context, _ bizdev.StageRunRequest) (*bizdev.StageRunResult, error) {
|
||||
func (p *pendingReplyBizdev) ExecuteStage(_ context.Context, _ stageflow.StageRunRequest) (*stageflow.StageRunResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (p *pendingReplyBizdev) InspectWorkspace(_ context.Context, _ string) (*squad.WorkspaceState, error) {
|
||||
@@ -39,7 +40,7 @@ func (p *pendingReplyBizdev) DocGov() *docgov.GovernanceEngine { return ni
|
||||
func (p *pendingReplyBizdev) KB() *kb.Client { return nil }
|
||||
|
||||
func TestSyncTriggerTask_PendingConfirmation_NotSavedCompleted(t *testing.T) {
|
||||
pending := &bizdev.TaskRunResult{
|
||||
pending := &stageflow.TaskRunResult{
|
||||
Success: true,
|
||||
TaskKey: "intake",
|
||||
ArtifactTitle: "用户初始需求收集表",
|
||||
@@ -55,7 +56,7 @@ func TestSyncTriggerTask_PendingConfirmation_NotSavedCompleted(t *testing.T) {
|
||||
eng := NewCoordinatorEngine(&pendingReplyBizdev{res: pending})
|
||||
userCtx := &UserProjectContext{
|
||||
User: UserInfo{ID: "1", Name: "u", ProjectRole: "author"},
|
||||
Project: ProjectInfo{ID: "9", Name: "P", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{ID: "9", Name: "P", CurrentStage: maturity.StageV01_Triage},
|
||||
}
|
||||
cand := &intent.CandidateIntent{
|
||||
Intent: intent.IntentTriggerTask,
|
||||
@@ -78,7 +79,7 @@ func TestSyncTriggerTask_PendingConfirmation_NotSavedCompleted(t *testing.T) {
|
||||
if !strings.Contains(res.NaturalReply, "文档候选已生成") || !strings.Contains(res.NaturalReply, "待编制人确认") {
|
||||
t.Fatalf("sync reply missing pending wording: %s", res.NaturalReply)
|
||||
}
|
||||
if res.TaskStatus != bizdev.TaskStatusPendingAuthorConfirmation {
|
||||
if res.TaskStatus != stageflow.TaskStatusPendingAuthorConfirmation {
|
||||
t.Fatalf("TaskStatus=%q", res.TaskStatus)
|
||||
}
|
||||
if res.DocID != "doc_proj9_intake" || res.PendingAgentCandidateID != 99 || res.PendingChangeReportID != 12 {
|
||||
@@ -87,7 +88,7 @@ func TestSyncTriggerTask_PendingConfirmation_NotSavedCompleted(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncTriggerTask_Committed_KeepsSavedWording(t *testing.T) {
|
||||
ok := &bizdev.TaskRunResult{
|
||||
ok := &stageflow.TaskRunResult{
|
||||
Success: true,
|
||||
TaskKey: "intake",
|
||||
ArtifactTitle: "用户初始需求收集表",
|
||||
@@ -98,7 +99,7 @@ func TestSyncTriggerTask_Committed_KeepsSavedWording(t *testing.T) {
|
||||
eng := NewCoordinatorEngine(&pendingReplyBizdev{res: ok})
|
||||
userCtx := &UserProjectContext{
|
||||
User: UserInfo{ID: "1", ProjectRole: "author"},
|
||||
Project: ProjectInfo{ID: "1", Name: "P", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{ID: "1", Name: "P", CurrentStage: maturity.StageV01_Triage},
|
||||
}
|
||||
cand := &intent.CandidateIntent{
|
||||
Intent: intent.IntentTriggerTask,
|
||||
@@ -115,13 +116,13 @@ func TestSyncTriggerTask_Committed_KeepsSavedWording(t *testing.T) {
|
||||
if !strings.Contains(res.NaturalReply, "正文已保存") {
|
||||
t.Fatalf("committed sync reply should mention saved body: %s", res.NaturalReply)
|
||||
}
|
||||
if res.TaskStatus != bizdev.TaskStatusCompleted {
|
||||
if res.TaskStatus != stageflow.TaskStatusCompleted {
|
||||
t.Fatalf("TaskStatus=%q", res.TaskStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatTriggerTaskReply_PendingUsesCompletionSummary(t *testing.T) {
|
||||
pending := &bizdev.TaskRunResult{
|
||||
pending := &stageflow.TaskRunResult{
|
||||
Success: true,
|
||||
ArtifactTitle: "法规对齐报告",
|
||||
PendingAgentCandidateID: 1,
|
||||
@@ -129,7 +130,7 @@ func TestFormatTriggerTaskReply_PendingUsesCompletionSummary(t *testing.T) {
|
||||
DocRecord: &docgov.DocumentRecord{DocID: "doc_x"},
|
||||
}
|
||||
reply, status := formatTriggerTaskReply(pending, "/tmp/out")
|
||||
if status != bizdev.TaskStatusPendingAuthorConfirmation {
|
||||
if status != stageflow.TaskStatusPendingAuthorConfirmation {
|
||||
t.Fatalf("status=%q", status)
|
||||
}
|
||||
if strings.Contains(reply, "正文已保存") {
|
||||
|
||||
@@ -298,4 +298,3 @@ func sanitizeAdhocTaskKey(title string) string {
|
||||
}
|
||||
return "adhoc_" + key
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/intent"
|
||||
"chat-agent-system/internal/maturity"
|
||||
)
|
||||
|
||||
// ============================================================================
|
||||
@@ -109,8 +109,8 @@ func TestUpgradeFlow_AttachCooldownAndRedeem(t *testing.T) {
|
||||
engine := NewCoordinatorEngine(nil)
|
||||
newCtx := func() *UserProjectContext {
|
||||
return &UserProjectContext{
|
||||
User: UserInfo{Name: "张工", ProjectRole: "composer"},
|
||||
Project: ProjectInfo{Name: "掌上超声项目", CurrentStage: bizdev.StageV01_Triage},
|
||||
User: UserInfo{Name: "张工", ProjectRole: "composer"},
|
||||
Project: ProjectInfo{Name: "掌上超声项目", CurrentStage: maturity.StageV01_Triage},
|
||||
BlackboardFacts: map[string]string{},
|
||||
}
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func TestUpgradeFlow_AttachCooldownAndRedeem(t *testing.T) {
|
||||
// 1. 模糊分支命中复杂画像 → 初答 + 升级建议挂载
|
||||
rec := &intent.IntentRecognitionResult{
|
||||
RawInput: complexInput,
|
||||
Branch: intent.BranchAmbiguousFallback,
|
||||
Branch: intent.BranchAmbiguousFallback,
|
||||
TopIntent: &intent.CandidateIntent{Intent: intent.IntentCasualChat, Confidence: 0.2, Branch: intent.BranchAmbiguousFallback},
|
||||
}
|
||||
res, err := engine.ProcessIntent(context.Background(), rec, newCtx())
|
||||
@@ -187,11 +187,11 @@ func TestUpgradeFlow_NoHintForSimpleInputs(t *testing.T) {
|
||||
for _, input := range []string{"这个先放放,你觉得呢", "好的知道了", "今天天气不错"} {
|
||||
userCtx := &UserProjectContext{
|
||||
User: UserInfo{Name: "张工", ProjectRole: "composer"},
|
||||
Project: ProjectInfo{Name: "智能输注泵项目", CurrentStage: bizdev.StageV01_Triage},
|
||||
Project: ProjectInfo{Name: "智能输注泵项目", CurrentStage: maturity.StageV01_Triage},
|
||||
}
|
||||
rec := &intent.IntentRecognitionResult{
|
||||
RawInput: input,
|
||||
Branch: intent.BranchAmbiguousFallback,
|
||||
Branch: intent.BranchAmbiguousFallback,
|
||||
TopIntent: &intent.CandidateIntent{Intent: intent.IntentCasualChat, Confidence: 0.2, Branch: intent.BranchAmbiguousFallback},
|
||||
}
|
||||
res, err := engine.ProcessIntent(context.Background(), rec, userCtx)
|
||||
@@ -206,4 +206,3 @@ func TestUpgradeFlow_NoHintForSimpleInputs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user