mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
feat(config): add compaction.thinkingLevel to override thinking level during compaction (#98074)
* feat(config): add compaction.thinkingLevel to override thinking during compaction * fix: make compaction.thinkingLevel override inherited session thinking * fix: warn on compaction.thinkingLevel ignored by Codex native runtime * feat(config): add compaction thinking override Co-authored-by: wu.duozhen@xydigit.com <wu.duozhen@xydigit.com> * test(agents): remove duplicate compaction harness Co-authored-by: wu.duozhen@xydigit.com <wu.duozhen@xydigit.com> * test(plugin-sdk): account for thinking level export Co-authored-by: wu.duozhen@xydigit.com <wu.duozhen@xydigit.com> * chore: keep release note in PR metadata * chore: reconcile plugin SDK surface budgets --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
co-authored by
Peter Steinberger
parent
9fe92cf5ce
commit
e5b2ca3c6b
@@ -94,8 +94,8 @@ d340686cf814326b5a554a32cc5ca324a9e1254a933c4d9d8d1ada5ac7109a10 module/command
|
||||
a821f9cc4e6f9339399d99e73f58c3b00baf139aa9d85c22d73c89d8be5702d2 module/config-contracts
|
||||
20f3f8042de53e4eee61b64de9102c8c202b9299e6a29235647a4729f70145f2 module/config-mutation
|
||||
316949815affe623ac63951a5db580527f02663576dffa084f02768f612c0c1c module/config-runtime
|
||||
e0c0e99a4d797ba583a7d99e258530230ea61c66875bd6cf45843eb9211f4ff0 module/config-schema
|
||||
2efdb1e995106ed5843461b7706100838db80453afa7e27c2c14f9c10a5a1e62 module/config-types
|
||||
493fe6fcb0e4a50b19c1b9574a30e56f5a561212a63202eda82c1c6a2ec3c17a module/config-schema
|
||||
23fc4e2588ed7d182a80eccc1b364baebb4c5816819397f38d4e8a299c655622 module/config-types
|
||||
42d15153981cfe3adc1d5f91621434c56f07a9bd48c15ce34742f72dd040c142 module/context-visibility-runtime
|
||||
03636897fb99cb73e4d8620c8a0e0d72b4d52fc32bf94f525af2aa88c489c6c2 module/conversation-binding-runtime
|
||||
c1ea9510dfda047609a99d5d2cd1f1560f5d469a36e6b695766213d695c25b0f module/conversation-runtime
|
||||
@@ -225,7 +225,7 @@ c543747f32aebde42508e31606db325739f0c54fcc7cf683f68ac941c835f737 module/provide
|
||||
096f53f25cde2c3428b6ff042f1687c5a7c1b161a375ba97aefcdf2f1c38887f module/provider-setup
|
||||
413af0d4597c1bab45e2f1a260b520445a25b9d11abd46a98fdfb74c60ddd601 module/provider-stream
|
||||
ea8bd63655e983dacfd306fe77d0793097166228a2dabd9b7fc8e33252eb359f module/provider-stream-family
|
||||
cdcc81cbd0aff7e341cd7edeec77b02b55d0d27af03278d13ef07487aa8eeae7 module/provider-stream-shared
|
||||
dc720974ed8d5cfd98fb3bb2958630736883f38317ee4744ce0b4042fa4485d8 module/provider-stream-shared
|
||||
5a907292055c941ec7420163ea50e8bc90ead816b3c5867d94a23024d3b579e8 module/provider-tools
|
||||
8236935f56423a26aeb7219173c0c8c8c7aacb4a13d0d851f05bdf2d35790cd4 module/provider-transport-runtime
|
||||
009a594b19aa9f0d0c0c28f54968f807cad4b3ee40ec13c685367116d63aafdc module/provider-usage
|
||||
|
||||
@@ -618,6 +618,7 @@ Periodic heartbeat runs.
|
||||
compaction: {
|
||||
mode: "safeguard", // default | safeguard
|
||||
provider: "my-provider", // id of a registered compaction provider plugin (optional)
|
||||
thinkingLevel: "low", // optional compaction-only thinking override
|
||||
timeoutSeconds: 180,
|
||||
reserveTokensFloor: 24000,
|
||||
keepRecentTokens: 50000,
|
||||
@@ -649,6 +650,7 @@ Periodic heartbeat runs.
|
||||
|
||||
- `mode`: `default` or `safeguard` (chunked summarization for long histories). See [Compaction](/concepts/compaction).
|
||||
- `provider`: id of a registered compaction provider plugin. When set, the provider's `summarize()` is called instead of built-in LLM summarization. Falls back to built-in on failure. Setting a provider forces `mode: "safeguard"`. See [Compaction](/concepts/compaction).
|
||||
- `thinkingLevel`: optional thinking level used only for embedded OpenClaw compaction summaries (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `adaptive`, `max`, or `ultra`). It overrides the session's current thinking level and is clamped to the selected compaction model/runtime. Leave unset to inherit the session level. Native Codex app-server compaction ignores this setting because the native compact request has no per-operation thinking override; OpenClaw logs a warning when configured.
|
||||
- `timeoutSeconds`: maximum seconds allowed for a single compaction operation before OpenClaw aborts it. Default: `180`.
|
||||
- `reserveTokens`: token headroom kept available for model output and future tool results after compaction. When the model context window is known, OpenClaw caps the effective reserve so it cannot consume the prompt budget.
|
||||
- `reserveTokensFloor`: minimum reserve enforced by the embedded runtime. Set `0` to disable the floor. The floor remains subject to the active context-window cap.
|
||||
|
||||
@@ -203,6 +203,8 @@ More on limits: [/reference/token-use](/reference/token-use).
|
||||
|
||||
Compaction summarizes older conversation into a persisted `compaction` entry in the transcript and keeps recent messages intact. After compaction, future turns see the compaction summary plus messages after `firstKeptEntryId`. Compaction is **persistent**, unlike session pruning - see [/concepts/session-pruning](/concepts/session-pruning).
|
||||
|
||||
Embedded OpenClaw compaction inherits the session thinking level by default. Set `agents.defaults.compaction.thinkingLevel` to use a separate level for summary calls; the runtime clamps it to each concrete compaction model or fallback. Native Codex app-server compaction owns its compact request and cannot accept a per-compaction thinking override, so OpenClaw warns and leaves that setting to Codex.
|
||||
|
||||
AGENTS.md section reinjection after compaction is opt-in via `agents.defaults.compaction.postCompactionSections`; when unset or `[]`, OpenClaw does not append AGENTS.md excerpts on top of the compaction summary.
|
||||
|
||||
### Chunk boundaries and tool pairing
|
||||
|
||||
@@ -1554,6 +1554,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
compaction: {
|
||||
model: "openai/gpt-5.4",
|
||||
provider: "custom-summary",
|
||||
thinkingLevel: "ultra",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1566,7 +1567,11 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
{
|
||||
sessionId: "session-1",
|
||||
sessionKey: "agent:main:session-1",
|
||||
ignoredConfig: ["agents.defaults.compaction.model", "agents.defaults.compaction.provider"],
|
||||
ignoredConfig: [
|
||||
"agents.defaults.compaction.model",
|
||||
"agents.defaults.compaction.thinkingLevel",
|
||||
"agents.defaults.compaction.provider",
|
||||
],
|
||||
},
|
||||
);
|
||||
warn.mockRestore();
|
||||
|
||||
@@ -409,6 +409,9 @@ function readIgnoredCompactionOverridePaths(params: CompactEmbeddedAgentSessionP
|
||||
if (typeof entry.record.model === "string" && entry.record.model.trim()) {
|
||||
ignored.add(`${entry.path}.compaction.model`);
|
||||
}
|
||||
if (typeof entry.record.thinkingLevel === "string" && entry.record.thinkingLevel.trim()) {
|
||||
ignored.add(`${entry.path}.compaction.thinkingLevel`);
|
||||
}
|
||||
if (providerPath) {
|
||||
ignored.add(providerPath);
|
||||
}
|
||||
|
||||
@@ -114,8 +114,8 @@ const defaultPublicDeprecatedExportsByEntrypointBudget = Object.freeze({
|
||||
"approval-runtime": 1,
|
||||
"config-runtime": 123,
|
||||
"config-contracts": 1,
|
||||
// +1: unified implicit-mention config type.
|
||||
"config-types": 426,
|
||||
// +1 each: unified implicit-mention config and AgentThinkingLevel types.
|
||||
"config-types": 427,
|
||||
"config-schema": 3,
|
||||
"reply-dedupe": 1,
|
||||
"inbound-reply-dispatch": 26,
|
||||
@@ -277,9 +277,10 @@ export function readPluginSdkSurfaceBudgets(env = process.env) {
|
||||
// +3: bounded visible transcript cursor request, result, and reader.
|
||||
// +1: explicit AgentModelPolicyConfig shared with provider setup surfaces.
|
||||
// +1: AgentHarnessSessionSupersededError lets harness plugins stop stale-owner fallback.
|
||||
// +1: AgentThinkingLevel shared by default-turn and compaction config.
|
||||
// +9: shared ingress monitor factory and lifecycle/result contracts across
|
||||
// channel-outbound and its two deprecated compatibility barrels.
|
||||
8176,
|
||||
8177,
|
||||
env,
|
||||
),
|
||||
publicFunctionExports: readPluginSdkSurfaceBudgetEnv(
|
||||
@@ -345,7 +346,8 @@ export function readPluginSdkSurfaceBudgets(env = process.env) {
|
||||
// Harvest: retired dual-field plan payload builder -1; lower-only drift -8.
|
||||
// +1: AgentModelPolicyConfig mirrored by deprecated config-types.
|
||||
// +6: ingress monitor lifecycle/result contracts through deprecated channel barrels.
|
||||
3012,
|
||||
// +1: AgentThinkingLevel mirrored by deprecated config-types.
|
||||
3013,
|
||||
env,
|
||||
),
|
||||
publicWildcardReexports: readPluginSdkSurfaceBudgetEnv(
|
||||
|
||||
@@ -159,7 +159,6 @@ import {
|
||||
} from "../session-write-lock.js";
|
||||
import { createAgentSession, estimateTokens, SessionManager } from "../sessions/index.js";
|
||||
import { detectRuntimeShell } from "../shell-utils.js";
|
||||
import { resolveCandidateThinkingLevel } from "../thinking-runtime.js";
|
||||
import {
|
||||
filterProviderNormalizableTools,
|
||||
filterRuntimeCompatibleTools,
|
||||
@@ -187,6 +186,7 @@ import {
|
||||
} from "./compaction-hooks.js";
|
||||
import {
|
||||
resolveCompactionHarnessRuntime,
|
||||
resolveEmbeddedCompactionThinkingLevel,
|
||||
resolveEmbeddedCompactionTarget,
|
||||
} from "./compaction-runtime-context.js";
|
||||
import {
|
||||
@@ -508,22 +508,12 @@ export async function compactEmbeddedAgentSessionDirect(
|
||||
provider === primaryProvider ||
|
||||
provider === requestedPrimaryProvider;
|
||||
const authProfileId = preservesPrimaryAuth ? params.authProfileId : undefined;
|
||||
const candidateThinkLevel = resolveCandidateThinkingLevel({
|
||||
cfg: params.config,
|
||||
provider,
|
||||
modelId: model,
|
||||
level: params.thinkLevel,
|
||||
agentId: fallbackAgentId,
|
||||
sessionKey: fallbackSessionKey,
|
||||
agentRuntime: params.agentHarnessId,
|
||||
});
|
||||
return await compactEmbeddedAgentSessionDirectOnce({
|
||||
...params,
|
||||
provider,
|
||||
model,
|
||||
authProfileId,
|
||||
authProfileIdSource: preservesPrimaryAuth ? params.authProfileIdSource : undefined,
|
||||
thinkLevel: candidateThinkLevel,
|
||||
// The primary attempt retains its already prepared atomic plan. An
|
||||
// actual fallback may change route/auth class and must rebuild it.
|
||||
runtimeAuthPlan: isPrimaryCandidate ? params.runtimeAuthPlan : undefined,
|
||||
@@ -645,7 +635,15 @@ async function compactEmbeddedAgentSessionDirectOnce(
|
||||
agentHarnessRuntimeOverride: selectedHarnessRuntimeOverride,
|
||||
workspaceDir: resolvedWorkspace,
|
||||
});
|
||||
let thinkLevel: ThinkLevel = params.thinkLevel ?? "off";
|
||||
let thinkLevel = resolveEmbeddedCompactionThinkingLevel({
|
||||
config: params.config,
|
||||
provider,
|
||||
modelId,
|
||||
inheritedLevel: params.thinkLevel,
|
||||
agentId: runtimePolicyAgentId,
|
||||
sessionKey: runtimePolicySessionKey,
|
||||
agentRuntime: selectedHarnessRuntime,
|
||||
});
|
||||
const attemptedThinking = new Set<ThinkLevel>();
|
||||
const fail = (reason: string, err?: unknown): EmbeddedAgentCompactResult => {
|
||||
const failureReason = classifyCompactionReason(reason);
|
||||
|
||||
@@ -7,9 +7,53 @@ import { resetProcessRegistryForTests } from "../bash-process-registry.test-supp
|
||||
import {
|
||||
buildEmbeddedCompactionRuntimeContext,
|
||||
resolveCompactionHarnessRuntime,
|
||||
resolveEmbeddedCompactionThinkingLevel,
|
||||
resolveEmbeddedCompactionTarget,
|
||||
} from "./compaction-runtime-context.js";
|
||||
|
||||
describe("resolveEmbeddedCompactionThinkingLevel", () => {
|
||||
it("lets the compaction override replace the inherited session level", () => {
|
||||
expect(
|
||||
resolveEmbeddedCompactionThinkingLevel({
|
||||
config: {
|
||||
agents: { defaults: { compaction: { thinkingLevel: "low" } } },
|
||||
},
|
||||
provider: "demo",
|
||||
modelId: "demo-model",
|
||||
inheritedLevel: "high",
|
||||
}),
|
||||
).toBe("low");
|
||||
});
|
||||
|
||||
it("revalidates an unsupported configured level for the actual candidate", () => {
|
||||
expect(
|
||||
resolveEmbeddedCompactionThinkingLevel({
|
||||
config: {
|
||||
agents: { defaults: { compaction: { thinkingLevel: "ultra" } } },
|
||||
},
|
||||
provider: "demo",
|
||||
modelId: "demo-model",
|
||||
}),
|
||||
).toBe("high");
|
||||
});
|
||||
|
||||
it("inherits the session level and otherwise defaults to off", () => {
|
||||
expect(
|
||||
resolveEmbeddedCompactionThinkingLevel({
|
||||
provider: "demo",
|
||||
modelId: "demo-model",
|
||||
inheritedLevel: "medium",
|
||||
}),
|
||||
).toBe("medium");
|
||||
expect(
|
||||
resolveEmbeddedCompactionThinkingLevel({
|
||||
provider: "demo",
|
||||
modelId: "demo-model",
|
||||
}),
|
||||
).toBe("off");
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildEmbeddedCompactionRuntimeContext", () => {
|
||||
afterEach(() => {
|
||||
resetProcessRegistryForTests();
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import { resolveSelectedOpenAIRuntimeProvider } from "../openai-routing.js";
|
||||
import { agentRuntimeAuthPlanMatchesTarget } from "../runtime-plan/prepare-auth.js";
|
||||
import type { AgentRuntimeAuthPlan, AgentRuntimePlan } from "../runtime-plan/types.js";
|
||||
import { resolveCandidateThinkingLevel } from "../thinking-runtime.js";
|
||||
|
||||
type EmbeddedCompactionRuntimeContext = {
|
||||
sessionKey?: string;
|
||||
@@ -57,6 +58,37 @@ type EmbeddedCompactionRuntimeContext = {
|
||||
activeProcessSessions?: ActiveProcessSessionReference[];
|
||||
};
|
||||
|
||||
/** Resolve the configured compaction override against the actual model/runtime candidate. */
|
||||
export function resolveEmbeddedCompactionThinkingLevel(params: {
|
||||
config?: OpenClawConfig;
|
||||
provider: string;
|
||||
modelId: string;
|
||||
inheritedLevel?: ThinkLevel;
|
||||
agentId?: string;
|
||||
sessionKey?: string;
|
||||
agentRuntime?: string | null;
|
||||
}): ThinkLevel {
|
||||
const requestedLevel =
|
||||
params.config?.agents?.defaults?.compaction?.thinkingLevel ?? params.inheritedLevel;
|
||||
if (!requestedLevel) {
|
||||
return "off";
|
||||
}
|
||||
// A compaction model override or fallback can change the supported level set.
|
||||
// Revalidate the immutable request for every concrete candidate instead of
|
||||
// carrying a level clamped for an earlier model into a later attempt.
|
||||
return (
|
||||
resolveCandidateThinkingLevel({
|
||||
cfg: params.config,
|
||||
provider: params.provider,
|
||||
modelId: params.modelId,
|
||||
level: requestedLevel,
|
||||
agentId: params.agentId,
|
||||
sessionKey: params.sessionKey,
|
||||
agentRuntime: params.agentRuntime,
|
||||
}) ?? "off"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the effective compaction target from config, falling back to the
|
||||
* caller-supplied provider/model and optionally applying runtime defaults.
|
||||
|
||||
@@ -94,4 +94,11 @@ describe("config compaction settings", () => {
|
||||
|
||||
expect(compaction?.qualityGuard?.maxRetries).toBe(99);
|
||||
});
|
||||
|
||||
it.each(["off", "low", "adaptive", "max", "ultra"] as const)(
|
||||
"preserves compaction thinkingLevel=%s during materialization",
|
||||
(thinkingLevel) => {
|
||||
expect(materializeCompactionConfig({ thinkingLevel })?.thinkingLevel).toBe(thinkingLevel);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -128,6 +128,8 @@ export const AGENT_FIELD_HELP: Record<string, string> = {
|
||||
'Compaction strategy mode: "default" uses baseline behavior, while "safeguard" applies stricter guardrails to preserve recent context. Keep "default" unless you observe aggressive history loss near limit boundaries.',
|
||||
"agents.defaults.compaction.provider":
|
||||
"Id of a registered compaction provider plugin used for summarization. When set and the provider is registered, its summarize() method is called instead of the built-in summarizeInStages pipeline. Falls back to built-in on provider failure. Leave unset to use the default built-in summarization.",
|
||||
"agents.defaults.compaction.thinkingLevel":
|
||||
'Optional thinking level used only for embedded OpenClaw compaction summaries: "off", "minimal", "low", "medium", "high", "xhigh", "adaptive", "max", or "ultra". It overrides the session level and is clamped to the actual compaction model/runtime; leave unset to inherit the session level. Native Codex app-server compaction ignores this setting because its compact request has no per-operation thinking override, and OpenClaw logs a warning.',
|
||||
"agents.defaults.compaction.reserveTokens":
|
||||
"Token headroom reserved for reply generation and tool output after compaction runs. Use higher reserves for verbose/tool-heavy sessions, and lower reserves when maximizing retained history matters more. When the active model context window is known, the effective reserve is capped to preserve usable prompt space.",
|
||||
"agents.defaults.compaction.keepRecentTokens":
|
||||
|
||||
@@ -407,6 +407,7 @@ export const TARGET_KEYS = [
|
||||
"agents.defaults.compaction",
|
||||
"agents.defaults.compaction.mode",
|
||||
"agents.defaults.compaction.provider",
|
||||
"agents.defaults.compaction.thinkingLevel",
|
||||
"agents.defaults.compaction.reserveTokens",
|
||||
"agents.defaults.compaction.keepRecentTokens",
|
||||
"agents.defaults.compaction.reserveTokensFloor",
|
||||
@@ -474,6 +475,17 @@ export const ENUM_EXPECTATIONS: Record<string, string[]> = {
|
||||
"cli.banner.taglineMode": ['"random"', '"default"', '"off"'],
|
||||
"update.channel": ['"stable"', '"extended-stable"', '"beta"', '"dev"'],
|
||||
"agents.defaults.compaction.mode": ['"default"', '"safeguard"'],
|
||||
"agents.defaults.compaction.thinkingLevel": [
|
||||
'"off"',
|
||||
'"minimal"',
|
||||
'"low"',
|
||||
'"medium"',
|
||||
'"high"',
|
||||
'"xhigh"',
|
||||
'"adaptive"',
|
||||
'"max"',
|
||||
'"ultra"',
|
||||
],
|
||||
"agents.defaults.compaction.identifierPolicy": ['"strict"', '"off"', '"custom"'],
|
||||
};
|
||||
|
||||
|
||||
@@ -440,6 +440,13 @@ describe("config help copy quality", () => {
|
||||
expect(mode.includes('"default"')).toBe(true);
|
||||
expect(mode.includes('"safeguard"')).toBe(true);
|
||||
|
||||
const thinkingLevel = expectDefined(
|
||||
FIELD_HELP["agents.defaults.compaction.thinkingLevel"],
|
||||
'FIELD_HELP["agents.defaults.compaction.thinkingLevel"] test invariant',
|
||||
);
|
||||
expect(/session level|inherit/i.test(thinkingLevel)).toBe(true);
|
||||
expect(/Codex app-server|no per-operation thinking override/i.test(thinkingLevel)).toBe(true);
|
||||
|
||||
const historyShare = expectDefined(
|
||||
FIELD_HELP["agents.defaults.compaction.maxHistoryShare"],
|
||||
'FIELD_HELP["agents.defaults.compaction.maxHistoryShare"] test invariant',
|
||||
|
||||
@@ -730,6 +730,7 @@ export const FIELD_LABELS: Record<string, string> = {
|
||||
"agents.defaults.compaction": "Compaction",
|
||||
"agents.defaults.compaction.mode": "Compaction Mode",
|
||||
"agents.defaults.compaction.provider": "Compaction Provider",
|
||||
"agents.defaults.compaction.thinkingLevel": "Compaction Thinking Level",
|
||||
"agents.defaults.compaction.reserveTokens": "Compaction Reserve Tokens",
|
||||
"agents.defaults.compaction.keepRecentTokens": "Compaction Keep Recent Tokens",
|
||||
"agents.defaults.compaction.reserveTokensFloor": "Compaction Reserve Token Floor",
|
||||
|
||||
@@ -24,6 +24,17 @@ export type EmbeddedAgentExecutionContract = "default" | "strict-agentic";
|
||||
export type SubagentDelegationMode = "suggest" | "prefer";
|
||||
/** Image compression/detail preference used before sending image inputs to models. */
|
||||
export type AgentImageQualityPreference = "auto" | "efficient" | "balanced" | "high";
|
||||
/** Canonical thinking levels accepted by agent defaults and compaction overrides. */
|
||||
export type AgentThinkingLevel =
|
||||
| "off"
|
||||
| "minimal"
|
||||
| "low"
|
||||
| "medium"
|
||||
| "high"
|
||||
| "xhigh"
|
||||
| "adaptive"
|
||||
| "max"
|
||||
| "ultra";
|
||||
|
||||
export type Gpt5PromptOverlayConfig = {
|
||||
/** Friendly interaction-style layer for GPT-5-family models (default: friendly). */
|
||||
@@ -361,16 +372,7 @@ export type AgentDefaultsConfig = {
|
||||
/** Vector memory search configuration (per-agent overrides supported). */
|
||||
memorySearch?: MemorySearchConfig;
|
||||
/** Default thinking level when no /think directive is present. */
|
||||
thinkingDefault?:
|
||||
| "off"
|
||||
| "minimal"
|
||||
| "low"
|
||||
| "medium"
|
||||
| "high"
|
||||
| "xhigh"
|
||||
| "adaptive"
|
||||
| "max"
|
||||
| "ultra";
|
||||
thinkingDefault?: AgentThinkingLevel;
|
||||
/** Default verbose level when no /verbose directive is present. */
|
||||
verboseDefault?: "off" | "on" | "full";
|
||||
/**
|
||||
@@ -528,6 +530,8 @@ export type AgentCompactionMidTurnPrecheckConfig = {
|
||||
export type AgentCompactionConfig = {
|
||||
/** Compaction summarization mode. */
|
||||
mode?: AgentCompactionMode;
|
||||
/** Override the session thinking level for embedded OpenClaw compaction summaries. */
|
||||
thinkingLevel?: AgentThinkingLevel;
|
||||
/** Embedded OpenClaw reserve target before floor and context-window caps. */
|
||||
reserveTokens?: number;
|
||||
/** Embedded OpenClaw keepRecentTokens budget used for cut-point selection. */
|
||||
|
||||
@@ -344,6 +344,28 @@ describe("agent defaults schema", () => {
|
||||
expect(result.compaction?.maxActiveTranscriptBytes).toBe("20mb");
|
||||
});
|
||||
|
||||
it.each([
|
||||
"off",
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"adaptive",
|
||||
"max",
|
||||
"ultra",
|
||||
] as const)("accepts compaction.thinkingLevel=%s", (thinkingLevel) => {
|
||||
const result = AgentDefaultsSchema.parse({ compaction: { thinkingLevel } })!;
|
||||
expect(result.compaction?.thinkingLevel).toBe(thinkingLevel);
|
||||
});
|
||||
|
||||
it("rejects an unknown compaction thinking level", () => {
|
||||
expectSchemaFailurePath(
|
||||
AgentDefaultsSchema.safeParse({ compaction: { thinkingLevel: "extreme" } }),
|
||||
"compaction.thinkingLevel",
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects unsafe byte-size strings in compaction defaults", () => {
|
||||
const unsafe = String(Number.MAX_SAFE_INTEGER + 1);
|
||||
expect(
|
||||
|
||||
@@ -34,6 +34,18 @@ const OptionalBootstrapFileNameSchema = z.enum([
|
||||
"IDENTITY.md",
|
||||
]);
|
||||
|
||||
const AgentThinkingLevelSchema = z.enum([
|
||||
"off",
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"adaptive",
|
||||
"max",
|
||||
"ultra",
|
||||
]);
|
||||
|
||||
const EmbeddedAgentConfigSchema = z
|
||||
.object({
|
||||
projectSettingsPolicy: z
|
||||
@@ -162,6 +174,7 @@ export const AgentDefaultsSchema = z
|
||||
.object({
|
||||
mode: z.union([z.literal("default"), z.literal("safeguard")]).optional(),
|
||||
provider: z.string().optional(),
|
||||
thinkingLevel: AgentThinkingLevelSchema.optional(),
|
||||
reserveTokens: z.number().int().nonnegative().optional(),
|
||||
keepRecentTokens: z.number().int().positive().optional(),
|
||||
reserveTokensFloor: z.number().int().nonnegative().optional(),
|
||||
@@ -208,19 +221,7 @@ export const AgentDefaultsSchema = z
|
||||
.optional(),
|
||||
runRetries: AgentRunRetriesConfigSchema.optional(),
|
||||
embeddedAgent: EmbeddedAgentConfigSchema.optional(),
|
||||
thinkingDefault: z
|
||||
.union([
|
||||
z.literal("off"),
|
||||
z.literal("minimal"),
|
||||
z.literal("low"),
|
||||
z.literal("medium"),
|
||||
z.literal("high"),
|
||||
z.literal("xhigh"),
|
||||
z.literal("adaptive"),
|
||||
z.literal("max"),
|
||||
z.literal("ultra"),
|
||||
])
|
||||
.optional(),
|
||||
thinkingDefault: AgentThinkingLevelSchema.optional(),
|
||||
verboseDefault: z.union([z.literal("off"), z.literal("on"), z.literal("full")]).optional(),
|
||||
toolProgressDetail: z.union([z.literal("explain"), z.literal("raw")]).optional(),
|
||||
reasoningDefault: z.union([z.literal("off"), z.literal("on"), z.literal("stream")]).optional(),
|
||||
|
||||
Reference in New Issue
Block a user