feat(config,runtime): 上下文预算按模型窗口推导 + usage/缓存可观测 + sidecar 存全文(T1)
- 窗口声明:models.json 组级 contextWindow + env LLM_CONTEXT_WINDOW(per-group materialize 播种,0 不写盘、负数报错)。 - 预算三态:CONTEXT_MAX_TOKENS 未设置 ⇒ 按窗口推导;>0 显式覆盖;0|负 关闭压缩(不变)。推导 budget = min(窗口×比例, 窗口−输出保留),比例默认 2/3(CONTEXT_BUDGET_RATIO,1M ⇒ 699050 tokens ≈ 683Ki);输出保留 = max(32768, 该组 maxTokens) 且封顶窗口/2(防配置矛盾时退化成 1 token);窗口未声明 ⇒ 回落 131072 + 恰好一条 WARN。接线在组合根 wire_context.go(唯一决策点)。 - usage/缓存可观测(此前**完全不可观测**):Response 增 CacheHit/CacheMiss/Reasoning tokens + CacheHitRate;解析 OpenAI 兼容(prompt_cache_hit_tokens/prompt_cache_miss_tokens/cached_tokens/reasoning_tokens)与 anthropic(cache_read_input_tokens/cache_creation_input_tokens)两种形状;记录点在适配器 record(换入口不丢成本日志),日志无凭据;单次输入 ≥预算 90% 记 WARN(不阻断)。 - 根治清单「续读」假承诺:抽取期不再按注入预算截断(sidecar 存全文,只受 MaxSidecarBytes=8 MiB 安全上限,ExtractorVersion v1→v2 旧 sidecar 失效重抽);注入预算改在装配期生效 ⇒ ref.Chars/Truncated 是注入侧事实、游标真是继续读的起点;document-read 的 limit 上限改为独立具名常量。 - 顺手修越界:config.go 505 行(超 500)拆出 llm.go。 - 主会话独立验收:隔离 worktree(HEAD + 本切片 39 文件,排除在途 gateway)build/vet 绿、全树 59 包 0 FAIL、linux+darwin 交叉编译绿;变异独立复现(比例改 0.25 ⇒ 推导用例红 262144 vs 699050)。
This commit is contained in:
1 parent
5b2b385524
commit
72b95df22b
39 files changed
+2496
-377
No files matched your search
@@ -360,46 +360,6 @@ func TestDocumentReadTool_TextExcludesMetadataLine(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestDocumentReadTool_ManifestCursorAndCSVSummary 钉住与上游的两处成对契约:
|
||||
// - CSV 的摘要行属于正文坐标系(offset 0 = 摘要行开头),与装配期注入的正文一致;
|
||||
// - 清单行给的续读游标(= 已注入字符数)可以原样传进来:读到末尾不报错,并如实标注
|
||||
// 抽取期的截断(extractTruncated)—— 抽取期预算之外的内容**不在 sidecar 里**
|
||||
// (design/24 §9.6 第 3 条),这条事实必须让模型看得见。
|
||||
func TestDocumentReadTool_ManifestCursorAndCSVSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
fx := newDocReadFixture(t)
|
||||
tool := fx.tool(t)
|
||||
|
||||
csv := docName(".csv")
|
||||
_, injectedCSV := fx.extract(t, csv, "a,b\n1,2\n3,4\n")
|
||||
if !strings.HasPrefix(injectedCSV, "[CSV") {
|
||||
t.Fatalf("CSV 夹具应当带摘要行:%q", injectedCSV)
|
||||
}
|
||||
gotCSV, err := callDocRead(t, tool, map[string]any{"name": csv})
|
||||
if err != nil {
|
||||
t.Fatalf("读 CSV: %v", err)
|
||||
}
|
||||
if gotCSV.Text != injectedCSV {
|
||||
t.Fatalf("CSV text = %q, want 含摘要行的注入正文 %q", gotCSV.Text, injectedCSV)
|
||||
}
|
||||
|
||||
big := docName(".txt")
|
||||
ref, _ := fx.extract(t, big, strings.Repeat("宽", documents.MaxExtractChars+10))
|
||||
if !ref.Truncated || ref.Chars != documents.MaxExtractChars {
|
||||
t.Fatalf("夹具前提:ref = %+v, want 抽取期已截断到 %d 字符", ref, documents.MaxExtractChars)
|
||||
}
|
||||
atCursor, err := callDocRead(t, tool, map[string]any{"name": big, "offset": ref.Chars})
|
||||
if err != nil {
|
||||
t.Fatalf("按清单游标读取: %v", err)
|
||||
}
|
||||
if atCursor.TotalChars != ref.Chars || atCursor.Text != "" || atCursor.Truncated || atCursor.NextOffset != 0 {
|
||||
t.Fatalf("按清单游标读取 = %+v, want 读到抽取正文末尾(totalChars %d)", atCursor, ref.Chars)
|
||||
}
|
||||
if !atCursor.ExtractTruncated {
|
||||
t.Fatal("抽取期的截断事实没有如实回给模型(extractTruncated=false)")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDocumentReadTool_OwnerOnlyByDefault 钉住⑤:工具以**默认最严**的可达性标记注册
|
||||
// (tool_policies 无行 = 两者皆 false = owner-only),因此群聊/陌生人会话在默认策略下既
|
||||
// 看不到也调不到它(design/24 §5 红线)。注册走的是既有工具同一条路径
|
||||
|
||||
Reference in new issue
Block a user