Add dialoguectx packaging, conflictresolve adjudication with HITL routing, workspace context/dialogue/ injection (default on), and goose 00071.
98 lines
3.9 KiB
Go
98 lines
3.9 KiB
Go
package dialoguectx_test
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"chat-agent-system/internal/ctxmgr"
|
|
"chat-agent-system/internal/dialoguectx"
|
|
"chat-agent-system/internal/replyexport"
|
|
)
|
|
|
|
func TestInjectionEnabledDefaultOn(t *testing.T) {
|
|
t.Setenv("DIALOGUE_CTX_INJECTION", "")
|
|
if !dialoguectx.InjectionEnabled() {
|
|
t.Fatal("expected default on")
|
|
}
|
|
t.Setenv("DIALOGUE_CTX_INJECTION", "off")
|
|
if dialoguectx.InjectionEnabled() {
|
|
t.Fatal("expected off")
|
|
}
|
|
}
|
|
|
|
func TestCollectFromRecordsCleansAndEnriches(t *testing.T) {
|
|
now := time.Date(2026, 9, 24, 15, 0, 0, 0, time.UTC)
|
|
recs := []ctxmgr.ChatMessageRecord{
|
|
{ID: 1, SessionID: "s1", UserID: 7, Role: "user", Content: "你好", CreatedAt: now, DayKey: "2026-09-24"},
|
|
{ID: 2, SessionID: "s1", UserID: 7, Role: "user", Content: "器械类型:眼科OCT", CreatedAt: now.Add(time.Minute), DayKey: "2026-09-24"},
|
|
{ID: 3, SessionID: "s1", UserID: 0, Role: "assistant", Content: "状态更新中", ContentKind: string(replyexport.KindStatusUpdate), ExportPolicy: string(replyexport.PolicyNone), CreatedAt: now.Add(2 * time.Minute), DayKey: "2026-09-24"},
|
|
{ID: 4, SessionID: "s1", UserID: 7, Role: "user", Content: "[private] 草稿备注", CreatedAt: now.Add(3 * time.Minute), DayKey: "2026-09-24"},
|
|
{ID: 5, SessionID: "s1", UserID: 0, Role: "assistant", Content: "已记录眼科OCT分类建议", ContentKind: string(replyexport.KindDocumentText), ExportPolicy: string(replyexport.PolicyFull), CreatedAt: now.Add(4 * time.Minute), DayKey: "2026-09-24"},
|
|
{ID: 6, SessionID: "s1", UserID: 8, Role: "user", Content: "目标市场:国内III类", CreatedAt: now.Add(5 * time.Minute), DayKey: "2026-09-24", Metadata: map[string]any{"stage_key": "other"}},
|
|
}
|
|
enrich := map[int64]struct {
|
|
Name, SystemRole, ProjectRole, DocDuty string
|
|
}{
|
|
7: {Name: "张工", SystemRole: "engineer", ProjectRole: "member"},
|
|
8: {Name: "李工", SystemRole: "engineer", ProjectRole: "member"},
|
|
}
|
|
// CollectFromRecords takes unexported speakerMeta — use public path via package rebuild:
|
|
// call through exported helper by duplicating via CollectAndPackage memory is heavy;
|
|
// instead test packaging via Inject test shim in same package.
|
|
_ = enrich
|
|
_ = os.Getenv
|
|
pkg, err := dialoguectx.CollectFromRecords(recs, dialoguectx.CollectOptions{
|
|
ProjectID: 1, MaxDays: 7, MaxTurns: 80, Now: now.Add(time.Hour), AllowedStageKey: "",
|
|
}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pkg.TurnCount < 2 {
|
|
t.Fatalf("expected cleaned turns, got %d (noise=%d private=%d)", pkg.TurnCount, pkg.ExcludedNoise, pkg.ExcludedPrivate)
|
|
}
|
|
if pkg.ExcludedPrivate < 1 {
|
|
t.Fatalf("expected private exclusion")
|
|
}
|
|
if pkg.ExcludedNoise < 1 {
|
|
t.Fatalf("expected noise exclusion for greeting/status")
|
|
}
|
|
if !strings.Contains(pkg.TurnsMD, "器械类型") {
|
|
t.Fatalf("turns missing content: %s", pkg.TurnsMD)
|
|
}
|
|
foundDevice := false
|
|
for _, f := range pkg.Facts {
|
|
if f.Key == "device_type" && strings.Contains(f.Value, "眼科OCT") {
|
|
foundDevice = true
|
|
}
|
|
}
|
|
if !foundDevice {
|
|
t.Fatalf("expected device_type fact, got %#v", pkg.Facts)
|
|
}
|
|
snip := dialoguectx.RenderAssistantSnippet(pkg)
|
|
if !strings.Contains(snip, "项目成员协同近况") {
|
|
t.Fatalf("snippet missing header: %s", snip)
|
|
}
|
|
}
|
|
|
|
func TestStageFilterExcludes(t *testing.T) {
|
|
now := time.Now()
|
|
recs := []ctxmgr.ChatMessageRecord{
|
|
{ID: 1, Role: "user", Content: "当前阶段事实:预算一千万", CreatedAt: now, Metadata: map[string]any{"stage_key": "rd_proposal"}},
|
|
{ID: 2, Role: "user", Content: "其他阶段事实:预算两千万", CreatedAt: now, Metadata: map[string]any{"stage_key": "system_reqs"}},
|
|
}
|
|
pkg, err := dialoguectx.CollectFromRecords(recs, dialoguectx.CollectOptions{
|
|
ProjectID: 1, MaxDays: 7, Now: now.Add(time.Minute), AllowedStageKey: "rd_proposal",
|
|
}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pkg.ExcludedNoAccess != 1 {
|
|
t.Fatalf("expected 1 stage exclusion, got %d", pkg.ExcludedNoAccess)
|
|
}
|
|
if pkg.TurnCount != 1 {
|
|
t.Fatalf("expected 1 turn, got %d", pkg.TurnCount)
|
|
}
|
|
}
|