fix(compaction): resolve model override in runtime context for all context engines

The compaction.model config override was only resolved inside
compactEmbeddedPiSessionDirect (compact.ts), which is only reached
by the legacy context engine. Custom context engines with their own
compact() implementation never saw the override, causing overflow and
timeout recovery to use the session's default model instead.

Move the override resolution into buildEmbeddedCompactionRuntimeContext
so the runtime context always carries the correct compaction model
regardless of which context engine handles the compact() call.

Fixes #56649

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
oliviareid-svg 2026-03-29 10:01:13 +08:00 committed by Josh Lehman
parent 78d1120a41
commit 7546bccaa3
No known key found for this signature in database
GPG Key ID: D141B425AC7F876B
1 changed files with 48 additions and 3 deletions

View File

@ -27,6 +27,45 @@ export type EmbeddedCompactionRuntimeContext = {
ownerNumbers?: string[];
};
/**
* Resolve the compaction model override from config, falling back to the
* caller-supplied provider/model. This ensures the runtime context always
* carries the correct compaction model regardless of which context engine
* handles the actual compact() call.
*/
function resolveCompactionModel(params: {
config?: OpenClawConfig;
provider?: string | null;
modelId?: string | null;
authProfileId?: string | null;
}): { provider: string | undefined; model: string | undefined; authProfileId: string | undefined } {
const override = params.config?.agents?.defaults?.compaction?.model?.trim();
if (!override) {
return {
provider: params.provider ?? undefined,
model: params.modelId ?? undefined,
authProfileId: params.authProfileId ?? undefined,
};
}
const slashIdx = override.indexOf("/");
if (slashIdx > 0) {
const overrideProvider = override.slice(0, slashIdx).trim();
const overrideModel = override.slice(slashIdx + 1).trim() || undefined;
// When switching provider via override, drop the primary auth profile to
// avoid sending the wrong credentials.
const authProfileId =
overrideProvider !== (params.provider ?? "")?.trim()
? undefined
: (params.authProfileId ?? undefined);
return { provider: overrideProvider, model: overrideModel, authProfileId };
}
return {
provider: params.provider ?? undefined,
model: override,
authProfileId: params.authProfileId ?? undefined,
};
}
export function buildEmbeddedCompactionRuntimeContext(params: {
sessionKey?: string | null;
messageChannel?: string | null;
@ -50,6 +89,12 @@ export function buildEmbeddedCompactionRuntimeContext(params: {
extraSystemPrompt?: string;
ownerNumbers?: string[];
}): EmbeddedCompactionRuntimeContext {
const resolved = resolveCompactionModel({
config: params.config,
provider: params.provider,
modelId: params.modelId,
authProfileId: params.authProfileId,
});
return {
sessionKey: params.sessionKey ?? undefined,
messageChannel: params.messageChannel ?? undefined,
@ -58,15 +103,15 @@ export function buildEmbeddedCompactionRuntimeContext(params: {
currentChannelId: params.currentChannelId ?? undefined,
currentThreadTs: params.currentThreadTs ?? undefined,
currentMessageId: params.currentMessageId ?? undefined,
authProfileId: params.authProfileId ?? undefined,
authProfileId: resolved.authProfileId,
workspaceDir: params.workspaceDir,
agentDir: params.agentDir,
config: params.config,
skillsSnapshot: params.skillsSnapshot,
senderIsOwner: params.senderIsOwner,
senderId: params.senderId ?? undefined,
provider: params.provider ?? undefined,
model: params.modelId ?? undefined,
provider: resolved.provider,
model: resolved.model,
thinkLevel: params.thinkLevel,
reasoningLevel: params.reasoningLevel,
bashElevated: params.bashElevated,