Route conversations through a squad entry when selected

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>
This commit is contained in:
2026-10-01 09:34:53 +00:00
co-authored by Cursor
parent 45b8a38710
commit 268f4a9abf
17 changed files with 1285 additions and 24 deletions
+2
View File
@@ -7,3 +7,5 @@
```
cd modules/backend && go test ./eval/ ./internal/quality/ -count=1
```
两种入口的切换由 `DecideSwitch` 判断:squad 分数不低于 direct,并且直通路径多出来的首字延迟 P50 不超过 3 秒。没有同一评测集上的实测分数时,结果是不切换,`runtime.entry` 默认保持 `direct`。
+45
View File
@@ -0,0 +1,45 @@
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。"
}
+27
View File
@@ -0,0 +1,27 @@
package eval
import (
"strings"
"testing"
"time"
)
func TestSwitchStaysDirectWithoutScores(t *testing.T) {
dec := DecideSwitch(nil, nil)
if dec.Met || !strings.Contains(Report(dec), "保持 direct") {
t.Fatalf("%+v %s", dec, Report(dec))
}
}
func TestSwitchRequiresScoreAndLatency(t *testing.T) {
direct := &EntryScore{Name: "direct", Score: 80, FirstTokenP50: time.Second}
slow := &EntryScore{Name: "squad", Score: 90, FirstTokenP50: 5 * time.Second}
if DecideSwitch(direct, slow).Met {
t.Fatal("extra latency above 3s must block the switch")
}
ok := &EntryScore{Name: "squad", Score: 80, FirstTokenP50: 3 * time.Second}
dec := DecideSwitch(direct, ok)
if !dec.Met || !strings.Contains(Report(dec), "改为 squad") {
t.Fatalf("%+v %s", dec, Report(dec))
}
}