fix: set default compaction reserveTokensFloor to 50000 (#1154)

This commit is contained in:
paisley
2026-07-10 18:04:59 +08:00
committed by GitHub
parent d7671a42e6
commit bcec47f600
6 changed files with 71 additions and 8 deletions
+1 -1
View File
@@ -129,7 +129,7 @@ Skills ページでは OpenClaw の複数ソース(管理ディレクトリ、
開発者モードでは、専用の Image Generation ページで、独立した OpenAI 互換の画像生成エンドポイント(Base URL、API キー、`gpt-image-2` などのモデル名)を設定でき、画像生成だけ専用の `/v1/images/generations` サービスを使い、チャットは通常の OpenAI Provider のまま継続できます。
OpenAI-compatible ゲートウェイを **Custom プロバイダー** で使う場合、**設定 → AI Providers → Provider 編集** でカスタム `User-Agent` を設定でき、互換性が必要なエンドポイントで有効です。
プロバイダーの編集や切り替え時、ClawX は `input: ["text", "image"]` など既存のモデル単位の能力メタデータを保持します。新しく選択した Custom プロバイダーのモデルには OpenClaw onboarding と同等の画像入力推論を適用し、不明なモデルはテキスト専用として扱います。
Custom プロバイダーのモデル行には明示的な `contextWindow` も書き込まれ(モデルファミリーから推定、例:`gpt-5.x` → 272k)、旧バージョンで保存された行は起動時に自動補完されます。これにより OpenClaw は長いセッションを "Context overflow" エラーになる前に圧縮できます。compaction 未設定の場合は `agents.defaults.compaction.mode = "safeguard"` が既定値として設定されますが、ユーザーが自分で設定したモデル行や圧縮設定が変更されることはありません。
Custom プロバイダーのモデル行には明示的な `contextWindow` も書き込まれ(モデルファミリーから推定、例:`gpt-5.x` → 272k)、旧バージョンで保存された行は起動時に自動補完されます。これにより OpenClaw は長いセッションを "Context overflow" エラーになる前に圧縮できます。compaction 未設定の場合は `agents.defaults.compaction.mode = "safeguard"``reserveTokensFloor = 50000` が既定値として設定されますが、ユーザーが自分で設定したモデル行や圧縮設定が変更されることはありません`reserveTokensFloor` が未設定の場合のみ補完されることがあります)
互換ゲートウェイで `/models` が認証以外の理由で使えない場合、ClawX は API キー検証時に軽量な `/chat/completions` または `/responses` プローブへ自動フォールバックします。
### 🌙 アダプティブテーマ
+1 -1
View File
@@ -129,7 +129,7 @@ Connect to multiple AI providers (OpenAI, Anthropic, and more) with credentials
In developer mode, the dedicated Image Generation page supports an independent OpenAI-compatible image-generation endpoint (Base URL, API key, and model name such as `gpt-image-2`) so image generation can use a dedicated `/v1/images/generations` service while chat continues using the normal OpenAI provider.
For **Custom** providers used with OpenAI-compatible gateways, you can set a custom `User-Agent` in **Settings → AI Providers → Edit Provider** for compatibility-sensitive endpoints.
When you edit or switch providers, ClawX preserves existing per-model capability metadata such as `input: ["text", "image"]`. Newly selected Custom-provider models use OpenClaw onboarding-compatible image-input inference, with unknown models defaulting to text-only.
Custom-provider model rows also receive an explicit `contextWindow` (inferred from the model family, e.g. `gpt-5.x` → 272k), and rows saved by older versions are backfilled on startup, so OpenClaw can compact long sessions before they fail with "Context overflow" errors. When you have no compaction config, ClawX seeds `agents.defaults.compaction.mode = "safeguard"`; rows or configs you authored yourself are never modified.
Custom-provider model rows also receive an explicit `contextWindow` (inferred from the model family, e.g. `gpt-5.x` → 272k), and rows saved by older versions are backfilled on startup, so OpenClaw can compact long sessions before they fail with "Context overflow" errors. When you have no compaction config, ClawX seeds `agents.defaults.compaction.mode = "safeguard"` and `reserveTokensFloor = 50000`; rows or configs you authored yourself are never modified (except a missing `reserveTokensFloor` may be backfilled).
When a compatible gateway rejects `/models` for non-auth reasons, ClawX automatically falls back to a lightweight `/chat/completions` or `/responses` probe during API key validation.
### 🌙 Adaptive Theming
+1 -1
View File
@@ -130,7 +130,7 @@ Skills 页面可展示来自多个 OpenClaw 来源的技能(托管目录、wor
在开发者模式下,独立的“图像生成”页面支持配置 OpenAI 兼容生图端点(Base URL、API Key 和模型名,例如 `gpt-image-2`),生图请求会走专用的 `/v1/images/generations` 服务,聊天仍继续使用正常的 OpenAI Provider。
如果你通过 **自定义(CustomProvider** 对接 OpenAI-compatible 网关,可以在 **设置 → AI Providers → 编辑 Provider** 中配置自定义 `User-Agent`,以提高兼容性。
编辑或切换 Provider 时,ClawX 会保留已有的模型级能力元数据,例如 `input: ["text", "image"]`。新选择的自定义 Provider 模型会使用与 OpenClaw onboarding 一致的图片输入能力推断;未知模型默认按纯文本模型处理。
自定义 Provider 的模型行还会写入显式的 `contextWindow`(按模型系列推断,例如 `gpt-5.x` → 272k),旧版本保存的模型行会在启动时自动回填,使 OpenClaw 能在长会话超限前主动压缩上下文,避免出现 "Context overflow" 报错。当你没有配置 compaction 时,ClawX 会默认写入 `agents.defaults.compaction.mode = "safeguard"`;你手动配置过的模型行或压缩配置永远不会被修改
自定义 Provider 的模型行还会写入显式的 `contextWindow`(按模型系列推断,例如 `gpt-5.x` → 272k),旧版本保存的模型行会在启动时自动回填,使 OpenClaw 能在长会话超限前主动压缩上下文,避免出现 "Context overflow" 报错。当你没有配置 compaction 时,ClawX 会默认写入 `agents.defaults.compaction.mode = "safeguard"``reserveTokensFloor = 50000`;你手动配置过的模型行或压缩配置永远不会被修改(仅可能回填缺失的 `reserveTokensFloor`
如果兼容网关的 `/models` 因非鉴权原因不可用,ClawX 会在校验 API Key 时自动降级为轻量的 `/chat/completions``/responses` 探测。
### 🌙 自适应主题
+38 -2
View File
@@ -523,6 +523,8 @@ async function discoverAgentIds(): Promise<string[]> {
const OPENCLAW_CONFIG_PATH = join(homedir(), '.openclaw', 'openclaw.json');
const FEISHU_PLUGIN_ID_CANDIDATES = ['openclaw-lark', 'feishu-openclaw-plugin'] as const;
const VALID_COMPACTION_MODES = new Set(['default', 'safeguard']);
/** Matches OpenClaw's 200k+ context-window recommendation (see computeContextAwareReserveTokensFloor). */
const DEFAULT_COMPACTION_RESERVE_TOKENS_FLOOR = 50_000;
const BUILTIN_CHANNEL_IDS = new Set([
'discord',
'telegram',
@@ -862,7 +864,38 @@ function ensureCompactionSafeguardDefault(config: Record<string, unknown>): bool
: {});
if (defaults.compaction !== undefined) return false;
defaults.compaction = { mode: 'safeguard' };
defaults.compaction = {
mode: 'safeguard',
reserveTokensFloor: DEFAULT_COMPACTION_RESERVE_TOKENS_FLOOR,
};
agents.defaults = defaults;
config.agents = agents;
return true;
}
/**
* Backfill `reserveTokensFloor` on compaction configs that ClawX or OpenClaw
* seeded without one. OpenClaw's built-in default (20k) is too low once
* contextWindow backfill activates safeguard compaction on 200k+ models.
*/
function backfillCompactionReserveTokensFloor(config: Record<string, unknown>): boolean {
const agents = (config.agents && typeof config.agents === 'object'
? config.agents as Record<string, unknown>
: null);
if (!agents) return false;
const defaults = (agents.defaults && typeof agents.defaults === 'object'
? agents.defaults as Record<string, unknown>
: null);
if (!defaults) return false;
const compaction = (defaults.compaction && typeof defaults.compaction === 'object'
? defaults.compaction as Record<string, unknown>
: null);
if (!compaction || compaction.reserveTokensFloor !== undefined) return false;
compaction.reserveTokensFloor = DEFAULT_COMPACTION_RESERVE_TOKENS_FLOOR;
defaults.compaction = compaction;
agents.defaults = defaults;
config.agents = agents;
return true;
@@ -2673,7 +2706,10 @@ export async function batchSyncConfigFields(token: string): Promise<void> {
// ── Compaction safeguard default ──
if (ensureCompactionSafeguardDefault(config)) {
modified = true;
console.log('[batch-sync] Seeded agents.defaults.compaction.mode=safeguard');
console.log(`[batch-sync] Seeded agents.defaults.compaction.mode=safeguard reserveTokensFloor=${DEFAULT_COMPACTION_RESERVE_TOKENS_FLOOR}`);
} else if (backfillCompactionReserveTokensFloor(config)) {
modified = true;
console.log(`[batch-sync] Backfilled agents.defaults.compaction.reserveTokensFloor=${DEFAULT_COMPACTION_RESERVE_TOKENS_FLOOR}`);
}
// ── Memory search default ──
@@ -3,7 +3,7 @@ id: custom-provider-context-window-defaults
title: Explicit contextWindow defaults and compaction safeguard for custom providers
scenario: gateway-backend-communication
taskType: runtime-bridge
intent: Give custom-provider model rows an explicit contextWindow (inferred by model family) and seed agents.defaults.compaction.mode=safeguard so OpenClaw can compact long sessions before they fail with "Context overflow: prompt too large for the model".
intent: Give custom-provider model rows an explicit contextWindow (inferred by model family) and seed agents.defaults.compaction.mode=safeguard with reserveTokensFloor=50000 so OpenClaw can compact long sessions before they fail with "Context overflow: prompt too large for the model".
touchedAreas:
- harness/specs/tasks/custom-provider-context-window-defaults.md
- harness/specs/rules/provider-model-metadata-preservation.md
@@ -33,7 +33,7 @@ requiredTests:
acceptance:
- New custom-provider model rows written by explicit provider sync include an inferred contextWindow matching the model-family table in model-capabilities.
- The startup batch sync backfills contextWindow only on models.providers.custom-* rows lacking both contextWindow and contextTokens; registry and non-custom providers are never touched.
- agents.defaults.compaction is seeded to { mode: "safeguard" } only when no compaction config exists; explicit compaction config is preserved verbatim.
- agents.defaults.compaction is seeded to { mode: "safeguard", reserveTokensFloor: 50000 } only when no compaction config exists; explicit compaction config is preserved verbatim except missing reserveTokensFloor may be backfilled.
- Renderer transport boundaries remain unchanged.
- Focused tests, harness validation, communication replay, and communication compare pass.
docs:
@@ -58,6 +58,9 @@ for the model. Try /reset (or /new) ...". Users also had no
rows during the startup batch config sync.
- Seed `agents.defaults.compaction.mode = "safeguard"` when the user has no
compaction config.
- Seed `agents.defaults.compaction.reserveTokensFloor = 50000` alongside
safeguard mode (and backfill when an existing compaction config lacks a floor)
so auto-compaction has enough buffer for 200k+ context models.
- Add regression tests and translated documentation.
## Out Of Scope
+25 -1
View File
@@ -2355,7 +2355,31 @@ describe('batchSyncConfigFields', () => {
const config = await readOpenClawJson();
const defaults = ((config.agents as Record<string, unknown>).defaults as Record<string, unknown>);
expect(defaults.compaction).toEqual({ mode: 'safeguard' });
expect(defaults.compaction).toEqual({
mode: 'safeguard',
reserveTokensFloor: 50_000,
});
});
it('backfills reserveTokensFloor on safeguard compaction seeded without a floor', async () => {
await writeOpenClawJson({
gateway: { auth: { mode: 'token', token: 'old' } },
agents: {
defaults: {
compaction: { mode: 'safeguard' },
},
},
});
const { batchSyncConfigFields } = await import('@electron/utils/openclaw-auth');
await batchSyncConfigFields('new-token');
const config = await readOpenClawJson();
const defaults = ((config.agents as Record<string, unknown>).defaults as Record<string, unknown>);
expect(defaults.compaction).toEqual({
mode: 'safeguard',
reserveTokensFloor: 50_000,
});
});
it('does not touch an explicit compaction config', async () => {