# @whatsmore-nf/dsh-context-steward

[English](README.md) | 中文

DeepSeek Harness 插件：把固定容量的上下文窗口当作稀缺的“认知资源”来做调度——
在硬性 token 预算内优先保障智能体对“当前关键决策”的注意力带宽，按价值密度分级压缩，
对已完成的阶段做记忆巩固，并维护结构化“事实金库”，让被驱逐的源文本仍可被召回。

它以 Cordis `Service` 形态发布，注册为 `ctx.contextSteward`，使用 schemastery 声明
`static Config` 与 `static inject`，与官方 Harness 插件（如 `@deepseek-ai/dsh-compaction-basic`）保持同一形态。

## 与官方 compaction 的关系

官方 `dsh-compaction-*` 负责压缩“会话正文本身”；本插件是互补层：负责对“注入的记忆”做
认知资源调度——去重聚合、分级压缩、阶段巩固、关键决策带宽保障、事实召回——再把压缩快照
注入模型可见上下文。两者可并存运行。

## 安装

通过 Harness 插件 CLI（与官方插件一致）：

```sh
dsh plugin --profile web add @whatsmore-nf/dsh-context-steward@latest
```

或直接通过 npm：

```sh
npm install @whatsmore-nf/dsh-context-steward
```

插件以 `@deepseek-ai/cordis`、`@deepseek-ai/dsh-agent`、`@deepseek-ai/dsh-llm`、
`@deepseek-ai/dsh-session` 为 peer 依赖；Harness profile 已自带这些运行时。

## 加载

在 `cordis.yml` / `cordis.patch.yml` 的 bundle 中加入一行：

```yaml
- id: dsh-context-steward
  name: '@whatsmore-nf/dsh-context-steward'
  config:
    capacity: 8000
    enabled: true
    inject: true
```

加载后注册 `ctx.contextSteward` 服务，并自动订阅 Harness 生命周期事件（见[事件](#事件)）。

## 配置（`ContextStewardConfig`）

全部字段可选，缺省时使用下表默认值。未知键、类型错误、越界的比例参数会导致插件加载失败
（`resolveConfig` 严格校验，与官方插件一致）。

| 键 | 默认值 | 含义 |
|---|---|---|
| `capacity` | `4000` | 注入的压缩上下文 token 预算（固定带宽上限）。 |
| `reserved` | `0` | 系统保留 tokens，不计入可压缩区。 |
| `decisionGuarantee` | `floor(capacity × 0.35)` | 关键决策注意力带宽下限：保护决策时工作集最多占用的 tokens。 |
| `halfLifeMs` | `600000` | 时间衰减半衰期（10 分钟）。 |
| `adaptiveRecency` | `true` | 根据决策节奏自适应半衰期。 |
| `minAdaptiveHalfLifeMs` | `10000` | 自适应半衰期下限。 |
| `maxAdaptiveHalfLifeMs` | `3600000` | 自适应半衰期上限。 |
| `adaptiveThresholds` | `true` | 根据抖动自调优升降级阈值。 |
| `churnWindowMs` | `60000` | 阈值自调优的抖动观察窗口。 |
| `tuneStep` | `0.03` | 阈值自调优步长。 |
| `demoteThreshold` | `0.35` | 分数低于此值的工作项降级到冷池。 |
| `promoteThreshold` | `0.55` | 分数高于此值的冷池项提升回工作集。 |
| `workingRenderRatio` | `0.5` | 工作集占渲染预算的比例。 |
| `maxProtectedDecisions` | `4` | 全保真保留的关键决策快照数（超出部分决策老化）。 |
| `coldCompactScore` | `0.4` | 冷池分级压缩的最低分数门槛。 |
| `rehydrateThreshold` | `0.6` | 存档回灌工作集的分数门槛。 |
| `dedupe` | `true` | 重复观测聚合为 `重复×N` 记录。 |
| `consolidate` | `true` | 已完成的阶段巩固为一条结构化摘要。 |
| `renderBudget` | 可用容量 | 渲染注入上下文的 token 上限。 |
| `maxItemChars` | `6000` | 单条 tool/observation 源文本截断上限（完整原文保留在金库）。 |
| `reclaimPeekLimit` | `16` | 价值密度回收的候选窥视条数。 |
| `enabled` | `true` | `false` 时只注册服务、不监听事件。 |
| `inject` | `true` | 启用压缩快照注入（仍受 `injectThresholdRatio` 门控）。 |
| `injectThresholdRatio` | `0.8` | 仅当实测会话压力 `totalTokens >= floor(窗口 × 比例)` 时才注入压缩快照——与官方 compaction 的 `thresholdRatio` 触发语义一致；低于阈值时插件只做不可见的内存书签，不干扰正常推理。 |
| `injectContextWindow` | `0` | 上下文窗口显式覆盖（tokens）。`0` = 自动取路由模型适配器上报的 `contextWindow`；解析不到且未覆盖时保守跳过注入。 |

## 使用

### Service 形态（Harness 内）

```ts
import type { Context } from '@deepseek-ai/cordis'
import ContextSteward from '@whatsmore-nf/dsh-context-steward'

export const name = 'context-steward'
export const inject = ['sessions']

export function apply(ctx: Context): void {
  const plugin = ctx.plugin(ContextSteward, { capacity: 8000 })
  // 可选：接入 LLM 语义摘要（pre-step 空闲期异步预热压缩，压缩质量从启发式升级为结构化摘要）
  // plugin.asyncSummarize = async (content, depth) => await llm.complete(
  //   buildCompactionPrompt({ context: [content] }), { maxTokens: depth >= 3 ? 160 : 80 },
  // )
}
```

服务以 `ctx.contextSteward` 暴露；按会话取独立调度器：
`ctx.contextSteward.scheduler(session)`。

### standalone 形态（演示 / 单测，无需 Harness 运行时）

```ts
import { createContextStewardPlugin } from '@whatsmore-nf/dsh-context-steward'

const plugin = createContextStewardPlugin({ capacity: 8000 })
plugin.hooks.onAppend?.({ id: 'u1', kind: 'user', content: '目标是部署服务', timestamp: 0 })
plugin.hooks.onDecision?.({ goal: '部署服务', currentStep: '选型', attentionFocus: ['部署', '服务'] })
const prompt = plugin.hooks.onBeforePrompt?.() // 注入压缩后的上下文
```

### 调度器核心

`CognitiveResourceScheduler` 独立导出：`ingest()`、`checkpoint()`、`setPhase()`、
`consolidatePhase()`、`compiledContext()`、`query()`、`exportArchive()`、
`exportState()` / `restoreState()` —— 完整签名见类型声明。

## 事件

`enabled` 为 `true` 时订阅：

| 事件 | 作用 |
|---|---|
| `session/event` | 把模型可见的 user/assistant/tool 事件接入调度器（去重、分级压缩、事实抽取、带宽记账）。跳过本插件自注入的压缩上下文。 |
| `agent/pre-step` | 把即将进行的步骤视为关键决策：注意力重排，然后注入压缩快照。 |
| `agent/request-error` | `CONTEXT_WINDOW_EXCEEDED` 失败时把超窗作为 observation 喂给调度器，让下一轮快照感知到失败。 |
| `agent/disposed` | 导出存档、打印收尾指标并释放会话状态。 |

## License

MIT
