Files
Agent-System/internal/sysadmin/features.go
T
weichen 45f21e84c7 feat(jevdecide): product shadow client with offline eval gates
Add typed jevdecide HTTP client (circuit, metrics) and coordinator
DecideAssist wiring behind JEV_DECIDE_MODE (default off). Offline eval
and synthetic soak evidence gate realtime/profile before assist rollout.
2026-09-23 17:40:40 +00:00

166 lines
8.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package sysadmin
import "os"
// Feature 功能开关视图。value / effectiveValue 是进程实际读到的配置,
// 不等于能力已经接入;是否可用看 implementationState 与 adapterReadiness。
type Feature struct {
Key string `json:"key"`
Label string `json:"label"`
Group string `json:"group"`
Value string `json:"value"`
ConfiguredValue string `json:"configuredValue"`
EffectiveValue string `json:"effectiveValue"`
ImplementationState string `json:"implementationState"`
AdapterReadiness string `json:"adapterReadiness"`
AdapterReason string `json:"adapterReason,omitempty"`
RolloutScope string `json:"rolloutScope"`
Source string `json:"source"`
RequiresRestart bool `json:"requiresRestart"`
Description string `json:"description"`
}
const (
implPlaceholder = "placeholder"
implDryRun = "dry_run"
implShadow = "shadow"
implLive = "live"
adapterReady = "ready"
adapterUnavailable = "unavailable"
adapterDegraded = "degraded"
rolloutEnvironment = "environment"
)
type featureMaturity struct {
state string
adapter string
reason string
}
// featureMaturityCatalog 是源码接线事实,不随环境变量翻转。
// 未列出的开关视为已接入的环境级能力;列出的项即使配置为 true 也保持此处状态。
var featureMaturityCatalog = map[string]featureMaturity{
"FAV_PUBLISHER_ENABLED": {
state: implDryRun, adapter: adapterUnavailable,
reason: "观察窗未授权,禁止 live",
},
"FAV_DEGRADED_READ": {
state: implDryRun, adapter: adapterUnavailable,
reason: "降级读保持关闭",
},
"MULTI_INTENT_PLAN_TIER": {
state: implLive, adapter: adapterDegraded,
reason: "I2 接线就绪:shadow 持久不可执行计划 + 项目 allowlist + 指标;默认仍 legacy,升档需 allowlist 与阈值验收",
},
"INTENT_PLAN_PROJECT_ALLOWLIST": {
state: implLive, adapter: adapterReady,
reason: "空值拒绝所有 elevated tier;* 放开全部;逗号分隔项目 ID",
},
"MULTI_INTENT_U9_SEGMENT": {
state: implLive, adapter: adapterReady,
reason: "HandleTurn 在规则无法分段且 elevated tier 时调用 PI proposer;失败 fail-closed;RulesCanDecide 跳过 LLM",
},
"MULTI_INTENT_U10_MUTATE": {
state: implLive, adapter: adapterReady,
reason: "project.fact.supplement 经 MutateOwner 写项目黑板(ctxmgr 端口);需 ExpectedResourceVersion",
},
"MULTI_INTENT_U11_DOCGOV": {
state: implLive, adapter: adapterDegraded,
reason: "document.claim / document.review.submit 接 docgov 引擎;其余 docgov key 仍 dry-run;项目 143 只读",
},
"MULTI_INTENT_U12_RUN_CONTROL": {
state: implLive, adapter: adapterDegraded,
reason: "workflow.run / run.resume 接 projectworkflow 与 taskrun;其余 run-control key 仍 dry-run",
},
"SEMANTIC_SUMMARY_SHADOW": {
state: implShadow, adapter: adapterDegraded,
reason: "影子组件默认关闭;dev/test schema 61 已含 chat_summaries。摘要请求已用 reasoning profile,pi-agent 经 bind-mount 的 pi-args.mjs 带 --no-tools。授权可见集 digest 仍空",
},
"SEMANTIC_SUMMARY_REPLACE": {
state: implPlaceholder, adapter: adapterUnavailable,
reason: "替换路径明确未接线,打开开关不会替换叙事",
},
"PI_CHANGE_REPORT_NARRATIVE": {
state: implShadow, adapter: adapterDegraded,
reason: "只读事实已含截断差异;reasoning/--no-tools 目标落盘与真实 MiniMax 链路已复测。开关默认关闭,待放量授权前保持 shadow",
},
}
type featureSpec struct {
key string // 环境变量名
label string
group string
fallback string // 组合根未提供生效值时的兜底
description string
}
// featureCatalog 覆盖 config.Config 主要开关与各业务包灰度 flag(宁全勿缺)。
// 生效值由组合根(app)解析后注入,避免本包反向依赖业务模块。
var featureCatalog = []featureSpec{
{key: "AGENT_BACKEND", label: "Agent 执行后端", group: "agent", fallback: "pi-agent", description: "对话与任务执行的 Agent 后端(stub / cursor / pi-agent)"},
{key: "MAX_CONCURRENT_AGENTS", label: "Agent 全局并发上限", group: "agent", fallback: "8", description: "保护 pi-agent / GPU / API 的并发闸"},
{key: "PI_AGENT_RUNNER_URL", label: "PI Runner 地址", group: "agent", fallback: "", description: "产品内 PI Agent Runner 服务地址;空表示未接入"},
{key: "ALLOW_IN_MEMORY", label: "允许内存降级模式", group: "system", fallback: "false", description: "数据库不可用时降级内存模式(仅限本地 Demo)"},
{key: "AUTH_REGISTRATION_ENABLED", label: "开放注册", group: "auth", fallback: "true", description: "是否允许用户自主注册"},
{key: "AUTH_REQUIRE_APPROVAL", label: "注册需审核", group: "auth", fallback: "false", description: "新注册用户是否需要管理员审核后激活"},
{key: "FAV_PUBLISHER_ENABLED", label: "FAV 发布器", group: "artifact-vault", fallback: "false", description: "Final Artifact Vault 后台发布器;默认关闭"},
{key: "FAV_DEGRADED_READ", label: "FAV 降级读", group: "artifact-vault", fallback: "false", description: "FAV 缺失时允许降级读取;默认关闭"},
{key: "INTENT_V2_SHADOW", label: "意图 V2 影子模式", group: "intent", fallback: "false", description: "V2 意图识别影子运行,仅观测不接管"},
{key: "JEV_DECIDE_MODE", label: "jev 决策模式", group: "jevdecide", fallback: "off", description: "产品侧 jev-service:off / shadow / assist;默认 off,失败回退规则"},
{key: "INTENT_V2_DECISION", label: "意图 V2 决策", group: "intent", fallback: "false", description: "V2 意图识别接管路由决策"},
{key: "INTENT_V2_DECISION_TIER", label: "意图 V2 决策档位", group: "intent", fallback: "none", description: "V2 灰度风险档位:none/query/generate/write_low/write_high/all"},
{key: "WORKFLOW_INTENTS_ENABLED", label: "工作流意图", group: "intent", fallback: "true", description: "识别工作流类意图"},
{key: "MULTI_INTENT_ENABLED", label: "多意图识别", group: "intent", fallback: "true", description: "单条消息多意图拆解"},
{key: "MULTI_INTENT_PLAN_TIER", label: "多意图计划档位", group: "intentflow", fallback: "legacy", description: "意图计划灰度:legacy/shadow/auto_read/confirm/full"},
{key: "INTENT_PLAN_PROJECT_ALLOWLIST", label: "多意图计划项目白名单", group: "intentflow", fallback: "", description: "elevated tier 项目 allowlist:空拒绝;* 全部;逗号分隔项目 ID"},
{key: "MULTI_INTENT_U9_SEGMENT", label: "U9 LLM 分段", group: "intentflow", fallback: "false", description: "LLM 意图分段提议"},
{key: "MULTI_INTENT_U10_MUTATE", label: "U10 变更适配器", group: "intentflow", fallback: "false", description: "低/中风险 mutate 动作适配器"},
{key: "MULTI_INTENT_U11_DOCGOV", label: "U11 文档治理适配器", group: "intentflow", fallback: "false", description: "docgov 动作适配器"},
{key: "MULTI_INTENT_U12_RUN_CONTROL", label: "U12 运行控制适配器", group: "intentflow", fallback: "false", description: "workflow/run-control 动作适配器"},
{key: "WORKFLOW_SCOPE_MODE", label: "工作流作用域裁决", group: "intent", fallback: "strict", description: "文档命中裁决:strict 命中他流即拦截;weighted 按工作流关系权重打分"},
{key: "SEMANTIC_SUMMARY_SHADOW", label: "语义摘要影子", group: "ctxmgr", fallback: "false", description: "上下文语义摘要影子生成"},
{key: "SEMANTIC_SUMMARY_REPLACE", label: "语义摘要替换", group: "ctxmgr", fallback: "false", description: "语义摘要替换确定性叙事(保留位,未接线)"},
{key: "PI_CHANGE_REPORT_NARRATIVE", label: "PI 变更报告叙事", group: "docrevision", fallback: "false", description: "变更报告 PI 叙事增强;默认仅确定性回退"},
}
// Features 返回功能开关快照;source 恒为 env,均需重启生效。
func (s *Service) Features() []Feature {
values := map[string]string{}
if s.featureValues != nil {
values = s.featureValues()
}
out := make([]Feature, 0, len(featureCatalog))
for _, spec := range featureCatalog {
value, ok := values[spec.key]
if !ok {
if env, set := os.LookupEnv(spec.key); set {
value = env
} else {
value = spec.fallback
}
}
maturity := featureMaturity{state: implLive, adapter: adapterReady}
if known, ok := featureMaturityCatalog[spec.key]; ok {
maturity = known
}
out = append(out, Feature{
Key: spec.key,
Label: spec.label,
Group: spec.group,
Value: value,
ConfiguredValue: value,
EffectiveValue: value,
ImplementationState: maturity.state,
AdapterReadiness: maturity.adapter,
AdapterReason: maturity.reason,
RolloutScope: rolloutEnvironment,
Source: "env",
RequiresRestart: true,
Description: spec.description,
})
}
return out
}