mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix(replay): mark local compaction calls
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/compact/compact-basic/README.md
|
||||
README.md: 0c7b009255dc2d41dc81cf2c7ff745e02ef28b9a
|
||||
README.zh.md: 4af584a059c99725882afd6206bdf9c984c7d4e3
|
||||
README.md: d1c1dfb509ae0750e1237532a829a35de5084c5e
|
||||
README.zh.md: a78887daad04d534ffed9cbd0357b76bdd908f5e
|
||||
|
||||
@@ -21,7 +21,7 @@ This backend owns the compaction policy:
|
||||
- **Overflow recovery** — provider-confirmed overflow needs no capacity metadata: it bypasses normal pressure and retention, prunes, then attempts one maximal balanced head reduction while leaving the newest indivisible unit. Retry is authorized whenever `surface.replaceGeneration` advances, including when pruning lands before later summary work throws. No replacement, an exhausted target-specific cap, cancellation, or an unknown/noncanonical error preserves the original provider failure.
|
||||
- **Failure handling** — a live unmatched `compact/start` is the durable lock. An unmatched marker before a newer `session/end-seed` is stale evidence from a prior lifecycle and does not block; one after that boundary reports `busy`. Summary and changed-span failures close with an error and leave the conversation surface untouched, though the attempt remains in the log. A failed close deliberately leaves a blocking orphan. Operational pressure failures warn and continue, while overflow-recovery failure preserves the original provider error only when no earlier replacement advanced the surface. Cancellation remains authoritative after cleanup and durability.
|
||||
|
||||
The protected `summarize()` method is the sole subclass hook. A template- or remote-summarizer subclass can override it while pressure, retention, provenance, shrink validation, and shadowed-token accounting stay on `ctx.tokenMeter`. The hook returns the safe summary plus the complete provider output, call envelope, and usage when available (`{ summary, rawOutput?, provider, model, maxTokens?, usage? }`); the transaction preserves those fields on `compact/summary`.
|
||||
The protected `summarize()` method is the sole subclass hook. A template- or remote-summarizer subclass can override it while pressure, retention, provenance, shrink validation, and shadowed-token accounting stay on `ctx.tokenMeter`. The hook returns the safe summary plus the complete provider output, call envelope, and usage when available (`{ summary, rawOutput?, llmStreamCall?, provider, model, maxTokens?, usage? }`); `llmStreamCall: true` means producing that result consumed exactly one call through this context's `ctx.llm.stream()`, while `rawOutput` alone does not identify the call path. The transaction preserves those fields on `compact/summary`.
|
||||
|
||||
## Config (`BasicCompactConfig`)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
- **溢出恢复**:提供方已确认的溢出不需容量元数据。它会绕过常规压力与保留,执行剪枝,再尝试一次最大平衡头部缩减,并留下最新不可分单元。只要 `surface.replaceGeneration` 前进,就允许重试,包括剪枝在后续摘要工作抛出异常前已落地的情况。如果没有替换、目标特定上限已耗尽、已取消,或遇到未知/非规范错误,则保留原始提供方失败。
|
||||
- **失败处理**:活动的未匹配 `compact/start` 是持久锁。位于较新 `session/end-seed` 之前的未匹配标记,是先前生命周期留下的陈旧证据,不会阻塞;位于该边界之后的标记报告 `busy`。摘要和 span 变更失败会以错误闭合,并保持会话表层不变,但日志中仍保留该尝试。闭合失败会有意留下阻塞性的未匹配标记。压力检查中的运行故障会发出警告并继续;只有此前没有替换推进表层时,溢出恢复失败才保留原始提供方错误。完成清理与持久化后,取消仍具有最终决定权。
|
||||
|
||||
受保护的 `summarize()` 方法是唯一的子类钩子。基于模板或远程摘要器的子类可以覆盖该方法,同时压力、保留、溯源、缩减验证与已遮蔽 token 计量仍由 `ctx.tokenMeter` 负责。钩子返回安全摘要,以及完整提供方输出、调用 envelope 和可用时的 usage(`{ summary, rawOutput?, provider, model, maxTokens?, usage? }`);事务会在 `compact/summary` 上保留这些字段。
|
||||
受保护的 `summarize()` 方法是唯一的子类钩子。基于模板或远程摘要器的子类可以覆盖该方法,同时压力、保留、溯源、缩减验证与已遮蔽 token 计量仍由 `ctx.tokenMeter` 负责。钩子返回安全摘要,以及完整提供方输出、调用 envelope 和可用时的 usage(`{ summary, rawOutput?, llmStreamCall?, provider, model, maxTokens?, usage? }`);`llmStreamCall: true` 表示生成该结果时恰好通过此上下文的 `ctx.llm.stream()` 发起了一次调用,而单有 `rawOutput` 并不能判定调用路径。事务会在 `compact/summary` 上保留这些字段。
|
||||
|
||||
## 配置(`BasicCompactConfig`)
|
||||
|
||||
|
||||
@@ -416,6 +416,7 @@ function commitCompactionBody(
|
||||
shadowedTokenCount,
|
||||
summary,
|
||||
rawOutput,
|
||||
llmStreamCall,
|
||||
provider,
|
||||
model,
|
||||
maxTokens,
|
||||
@@ -425,6 +426,7 @@ function commitCompactionBody(
|
||||
const summaryEvent = session.append('compact/summary', {
|
||||
summary,
|
||||
...rawOutput === undefined ? {} : { rawOutput },
|
||||
...llmStreamCall === undefined ? {} : { llmStreamCall },
|
||||
shadowedRange: { start, end },
|
||||
shadowedSeqs: [...shadowedSeqs],
|
||||
shadowedTokenCount,
|
||||
|
||||
@@ -87,8 +87,16 @@ export interface SummarizationInput {
|
||||
/** Safe summary content plus the exact auxiliary call envelope recorded in provenance. */
|
||||
export interface SummaryResult {
|
||||
summary: ContentBlock[]
|
||||
/** Complete provider output before the text-only summary projection. */
|
||||
/**
|
||||
* Complete provider output before the text-only summary projection; this
|
||||
* alone does not identify the call path.
|
||||
*/
|
||||
rawOutput?: ContentBlock[]
|
||||
/**
|
||||
* Present only when producing the summary consumed exactly one call through
|
||||
* this context's `ctx.llm.stream()`.
|
||||
*/
|
||||
llmStreamCall?: true
|
||||
provider: string
|
||||
model: string
|
||||
maxTokens?: number
|
||||
@@ -162,6 +170,7 @@ export async function summarizeWithLlm(
|
||||
return {
|
||||
summary,
|
||||
rawOutput,
|
||||
llmStreamCall: true,
|
||||
provider: options.provider,
|
||||
model: options.model,
|
||||
maxTokens: config.maxTokens,
|
||||
|
||||
@@ -868,6 +868,7 @@ describe('compaction region transaction', () => {
|
||||
rawOutput: compact.rawOutput,
|
||||
usage: compact.usage,
|
||||
})
|
||||
expect(summary?.data).not.toHaveProperty('llmStreamCall')
|
||||
const head = session.deriveMessages()[0]!
|
||||
expect(head.content[0]?.type).toBe('text')
|
||||
expect(head.content[0]?.type === 'text' ? head.content[0].text : '').toContain('<compacted-summary>')
|
||||
@@ -1187,6 +1188,7 @@ describe('default one-shot summarizer', () => {
|
||||
{ type: 'text', text: 'public summary' },
|
||||
{ type: 'tool-call', id: CallId('unexpected'), name: 'x', arguments: '{}' },
|
||||
],
|
||||
llmStreamCall: true,
|
||||
provider: MODEL,
|
||||
model: MODEL,
|
||||
maxTokens: 321,
|
||||
@@ -1300,6 +1302,7 @@ describe('default one-shot summarizer', () => {
|
||||
await compact.compactRegion(nodes[0]!, nodes[3]!, agent(session, MODEL), SIGNAL)
|
||||
expect(session.events.findLast(event => event.type === 'compact/summary')?.data).toMatchObject({
|
||||
summary: [{ type: 'text', text: 'routed summary' }],
|
||||
llmStreamCall: true,
|
||||
provider: 'routed-summary-provider',
|
||||
model: 'routed-summary-model',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user