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
+17
-11
@@ -252,6 +252,12 @@ func (a *app) wireRuntime() error {
|
||||
approver := audit.NewApprover(a.log)
|
||||
approvalGate := a.buildApprovalGate(approver)
|
||||
|
||||
// 上下文溢出压缩:预算按模型窗口推导(CONTEXT_MAX_TOKENS 未设置时;
|
||||
// 显式 >0 = 覆盖、0/负 = 关闭),推导与「窗口未声明」的 WARN 都在
|
||||
// wire_context.go 一处完成。Compactor 不注入,由 loop 选用内置的结构化
|
||||
// compactor(离线、不调模型),并按同一份注入预算估算文档部件的代价。
|
||||
ctxBudget := a.contextBudget(envPath)
|
||||
|
||||
a.loop = loop.New(loop.Options{
|
||||
Agent: defaultAgent,
|
||||
Agents: agents,
|
||||
@@ -277,17 +283,17 @@ func (a *app) wireRuntime() error {
|
||||
PersonaKnowledgeFor: a.personaKnowledgeFor(envPath),
|
||||
Timezone: a.cfg.Timezone,
|
||||
MaxRounds: defaultMaxRounds,
|
||||
// 上下文溢出压缩:预算取自 CONTEXT_MAX_TOKENS(非正 = 关闭,
|
||||
// 与接线前一致),默认启用(见 wire_context.go)。Compactor 不注入,
|
||||
// 由 loop 选用内置的结构化 compactor(离线、不调模型)。
|
||||
MaxContextTokens: a.contextBudget(),
|
||||
WorkingMemory: memory.NewWorkingMemory(0),
|
||||
OnStream: a.streamChunk,
|
||||
Vision: visionResolver,
|
||||
DocumentResolver: docResolver,
|
||||
Thinking: thinking,
|
||||
ReasoningEffort: reasoningEffort,
|
||||
ThinkingShowToUser: thinkingShow,
|
||||
MaxContextTokens: ctxBudget.Budget.Tokens,
|
||||
// 单份附件的注入预算随推导出的上下文预算走(T1 §7.2):1M 窗口下大附件
|
||||
// 才真的进得来,而清单行的续读游标也因此真的是继续读的起点。
|
||||
DocumentMaxInjectChars: ctxBudget.DocumentInjectChars,
|
||||
WorkingMemory: memory.NewWorkingMemory(0),
|
||||
OnStream: a.streamChunk,
|
||||
Vision: visionResolver,
|
||||
DocumentResolver: docResolver,
|
||||
Thinking: thinking,
|
||||
ReasoningEffort: reasoningEffort,
|
||||
ThinkingShowToUser: thinkingShow,
|
||||
// 按调用(而非整批)准入:敏感与否取决于该次调用的参数
|
||||
// (file 的 read 自主、write 代审),见 toolAdmissionHooks。
|
||||
Hooks: a.toolAdmissionHooks(approvalGate),
|
||||
|
||||
Reference in new issue
Block a user