Add env-based feature flags (intent_v2_shadow/decision, multi_intent, workflow_intents), V1/V2 shadow diff reporting, expectation_plus_new plan building, ranked-frame L2 conflict gate, and coordinator sequential query plan execution with confirm-step deferral. Co-authored-by: Cursor <cursoragent@cursor.com>
112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
package intent
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// V2DecisionTier 灰度切换的风险档位(由低到高逐步启用 V2 路由)
|
|
type V2DecisionTier string
|
|
|
|
const (
|
|
V2TierNone V2DecisionTier = "none"
|
|
V2TierQuery V2DecisionTier = "query"
|
|
V2TierGenerate V2DecisionTier = "generate"
|
|
V2TierWriteLow V2DecisionTier = "write_low"
|
|
V2TierWriteHigh V2DecisionTier = "write_high"
|
|
V2TierAll V2DecisionTier = "all"
|
|
)
|
|
|
|
// FeatureFlags Phase 5 意图识别灰度开关(环境变量覆盖,默认保守)
|
|
type FeatureFlags struct {
|
|
IntentV2Shadow bool
|
|
IntentV2Decision bool
|
|
V2DecisionTier V2DecisionTier
|
|
WorkflowIntentsEnabled bool
|
|
MultiIntentEnabled bool
|
|
SemanticFallbackEnabled bool
|
|
}
|
|
|
|
var (
|
|
flagsMu sync.RWMutex
|
|
activeFlags = defaultFeatureFlags()
|
|
)
|
|
|
|
func defaultFeatureFlags() FeatureFlags {
|
|
return FeatureFlags{
|
|
IntentV2Shadow: envBool("INTENT_V2_SHADOW", false),
|
|
IntentV2Decision: envBool("INTENT_V2_DECISION", false),
|
|
V2DecisionTier: parseV2DecisionTier(os.Getenv("INTENT_V2_DECISION_TIER")),
|
|
WorkflowIntentsEnabled: envBool("WORKFLOW_INTENTS_ENABLED", true),
|
|
MultiIntentEnabled: envBool("MULTI_INTENT_ENABLED", true),
|
|
SemanticFallbackEnabled: envBool("SEMANTIC_FALLBACK_ENABLED", false),
|
|
}
|
|
}
|
|
|
|
func parseV2DecisionTier(raw string) V2DecisionTier {
|
|
switch strings.ToLower(strings.TrimSpace(raw)) {
|
|
case "", "none":
|
|
return V2TierNone
|
|
case "query":
|
|
return V2TierQuery
|
|
case "generate":
|
|
return V2TierGenerate
|
|
case "write_low", "write-low", "low_write":
|
|
return V2TierWriteLow
|
|
case "write_high", "write-high", "high_write":
|
|
return V2TierWriteHigh
|
|
case "all":
|
|
return V2TierAll
|
|
default:
|
|
return V2TierQuery
|
|
}
|
|
}
|
|
|
|
func envBool(key string, def bool) bool {
|
|
v := strings.TrimSpace(os.Getenv(key))
|
|
if v == "" {
|
|
return def
|
|
}
|
|
return v == "1" || strings.EqualFold(v, "true") || strings.EqualFold(v, "yes")
|
|
}
|
|
|
|
// CurrentFeatureFlags 返回当前生效的功能开关
|
|
func CurrentFeatureFlags() FeatureFlags {
|
|
flagsMu.RLock()
|
|
defer flagsMu.RUnlock()
|
|
return activeFlags
|
|
}
|
|
|
|
// SetFeatureFlagsForTest 测试专用:临时覆盖开关
|
|
func SetFeatureFlagsForTest(f FeatureFlags) {
|
|
flagsMu.Lock()
|
|
activeFlags = f
|
|
flagsMu.Unlock()
|
|
}
|
|
|
|
// ResetFeatureFlagsForTest 测试专用:恢复默认
|
|
func ResetFeatureFlagsForTest() {
|
|
flagsMu.Lock()
|
|
activeFlags = defaultFeatureFlags()
|
|
flagsMu.Unlock()
|
|
}
|
|
|
|
// tierAllowsRisk 判断当前灰度档位是否允许该风险等级的 V2 路由
|
|
func tierAllowsRisk(tier V2DecisionTier, risk RiskLevel) bool {
|
|
switch tier {
|
|
case V2TierNone:
|
|
return false
|
|
case V2TierQuery:
|
|
return risk == RiskLow
|
|
case V2TierGenerate:
|
|
return risk == RiskLow || risk == RiskMedium
|
|
case V2TierWriteLow:
|
|
return risk != RiskHigh
|
|
case V2TierWriteHigh, V2TierAll:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|