Why: Squad steps previously ran without tools, and the product had no way to make the squad the conversation entry without losing streaming, cards, or the deliverable guard. Evidence: go test ./... -count=1 passed, including streaming, cardflow, false-deliverable rejection, tool allowlist, model routing, usage, cancel, and turn and tool budgets. Impact: runtime.entry defaults to direct. squad uses one kernel step for simple work and the leader for the rest. squad_orchestrate is hidden in that mode. The default is not switched. Refs: deliverable-quality-system B3-B5 Co-authored-by: Cursor <cursoragent@cursor.com>
46 lines
1.6 KiB
Go
46 lines
1.6 KiB
Go
package eval
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// EntryScore 是一种入口在同一评测集上的结果。
|
|
type EntryScore struct {
|
|
Name string
|
|
Score int
|
|
FirstTokenP50 time.Duration
|
|
}
|
|
|
|
// SwitchDecision 判断能不能把默认入口改成 squad。
|
|
// 两条都要满足:squad 分数不低于 direct,直通路径多出来的首字延迟 P50 不超过 3 秒。
|
|
type SwitchDecision struct {
|
|
Met bool
|
|
Reason string
|
|
}
|
|
|
|
func DecideSwitch(direct, squad *EntryScore) SwitchDecision {
|
|
if direct == nil || squad == nil {
|
|
return SwitchDecision{Met: false, Reason: "还没有两种入口在同一评测集上的实测分数,默认保持 direct"}
|
|
}
|
|
extra := squad.FirstTokenP50 - direct.FirstTokenP50
|
|
if extra < 0 {
|
|
extra = 0
|
|
}
|
|
if squad.Score < direct.Score {
|
|
return SwitchDecision{Met: false, Reason: fmt.Sprintf("squad 分数 %d 低于 direct %d", squad.Score, direct.Score)}
|
|
}
|
|
if extra > 3*time.Second {
|
|
return SwitchDecision{Met: false, Reason: fmt.Sprintf("直通路径额外首字延迟 %s,超过 3 秒", extra)}
|
|
}
|
|
return SwitchDecision{Met: true, Reason: fmt.Sprintf("squad %d 不低于 direct %d,额外首字延迟 %s", squad.Score, direct.Score, extra)}
|
|
}
|
|
|
|
// Report 写成可以附在切换 PR 上的短报告。未达标时明确保持 direct。
|
|
func Report(dec SwitchDecision) string {
|
|
if dec.Met {
|
|
return "切换条件已满足:" + dec.Reason + "。可以把 runtime.entry 的默认值改为 squad,并保留 direct 作为回退。合入前需要产品确认。"
|
|
}
|
|
return "切换条件未满足:" + dec.Reason + "。runtime.entry 默认值保持 direct。"
|
|
}
|