feat(intercept): 模型兜底审批单独计量 token 并在配置页展示
兜底审批(LLM judge)调模型判定漏网命令,其 token 消耗此前无法单独查看: usage 行要么无 worker 归属、要么被并进复用的模型 profile 桶里。 - llmrec 增加 WithWorker 上下文覆盖,reviewer 调用前标注 worker='judge', 让审批调用的计量行可被单独筛出(复用现有 llm_usage.worker 列,无需迁移)。 - db.JudgeUsageStats 返回累计总量 + 近 N 天每日序列(WHERE worker='judge')。 - 新增 GET /api/intercept/judge/usage。 - 配置页「模型兜底审批」开关下方新增用量卡片:调用次数 / 输入 / 输出 / 缓存读写 五项统计 + 近 30 天每日消耗迷你柱图 + 刷新。
This commit is contained in:
1 parent
d0033724a6
commit
86729b65dc
8 files changed
+242
-1
No files matched your search
@@ -17,6 +17,7 @@ import (
|
||||
)
|
||||
|
||||
type taskIDContextKey struct{}
|
||||
type workerContextKey struct{}
|
||||
|
||||
// WithTaskID attaches the owning task registry id to an LLM call. Session ids
|
||||
// are based on exploration ids, which are not interchangeable with task ids.
|
||||
@@ -37,6 +38,28 @@ func TaskIDFrom(ctx context.Context) string {
|
||||
return strings.TrimSpace(taskID)
|
||||
}
|
||||
|
||||
// WithWorker overrides the agent-lane ("worker") label for an LLM call. The lane
|
||||
// is normally parsed from the transcript session id (exp<N>-<role>); calls made
|
||||
// outside the engine's worker/planner sessions — e.g. the intercept fallback judge
|
||||
// — carry no such session, so they attach their lane explicitly here. This lets the
|
||||
// usage ledger single out that spend (worker='judge') for the config page.
|
||||
func WithWorker(ctx context.Context, worker string) context.Context {
|
||||
worker = strings.TrimSpace(worker)
|
||||
if worker == "" {
|
||||
return ctx
|
||||
}
|
||||
return context.WithValue(ctx, workerContextKey{}, worker)
|
||||
}
|
||||
|
||||
// workerFrom returns the explicit lane override, or "" when none is set.
|
||||
func workerFrom(ctx context.Context) string {
|
||||
if ctx == nil {
|
||||
return ""
|
||||
}
|
||||
worker, _ := ctx.Value(workerContextKey{}).(string)
|
||||
return strings.TrimSpace(worker)
|
||||
}
|
||||
|
||||
// Recorder wraps an llm.Provider and records every completion call.
|
||||
type Recorder struct {
|
||||
inner llm.Provider
|
||||
@@ -101,6 +124,9 @@ func (r *Recorder) Stream(ctx context.Context, req llm.CompletionRequest) iter.S
|
||||
start := time.Now()
|
||||
session := transcript.SessionIDFrom(ctx)
|
||||
parsedID, worker := parseSession(session)
|
||||
if ov := workerFrom(ctx); ov != "" {
|
||||
worker = ov
|
||||
}
|
||||
expID := db.ParseExpID(parsedID)
|
||||
taskID := TaskIDFrom(ctx)
|
||||
if taskID == "" {
|
||||
@@ -198,6 +224,9 @@ func (r *Recorder) Complete(ctx context.Context, req llm.CompletionRequest) (llm
|
||||
start := time.Now()
|
||||
session := transcript.SessionIDFrom(ctx)
|
||||
parsedID, worker := parseSession(session)
|
||||
if ov := workerFrom(ctx); ov != "" {
|
||||
worker = ov
|
||||
}
|
||||
expID := db.ParseExpID(parsedID)
|
||||
taskID := TaskIDFrom(ctx)
|
||||
if taskID == "" {
|
||||
|
||||
Reference in new issue
Block a user