Auto-reply: honor compaction model for memory flush

This commit is contained in:
John Hagler 2026-03-20 12:03:40 -04:00
parent 4d8106eece
commit fa3e6fbbf0
3 changed files with 99 additions and 27 deletions

View File

@ -28,7 +28,7 @@ import type { VerboseLevel } from "../thinking.js";
import type { GetReplyOptions } from "../types.js";
import {
buildEmbeddedRunExecutionParams,
resolveModelFallbackOptions,
resolveCompactionModelFallbackOptions,
} from "./agent-runner-utils.js";
import {
hasAlreadyFlushedForCurrentCompaction,
@ -478,7 +478,7 @@ export async function runMemoryFlushIfNeeded(params: {
.join("\n\n");
try {
await runWithModelFallback({
...resolveModelFallbackOptions(params.followupRun.run),
...resolveCompactionModelFallbackOptions(params.followupRun.run),
runId: flushRunId,
run: async (provider, model, runOptions) => {
const { embeddedContext, senderContext, runBaseParams } = buildEmbeddedRunExecutionParams({

View File

@ -1,20 +1,11 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { FollowupRun } from "./queue.js";
const hoisted = vi.hoisted(() => {
const resolveRunModelFallbacksOverrideMock = vi.fn();
return { resolveRunModelFallbacksOverrideMock };
});
vi.mock("../../agents/agent-scope.js", () => ({
resolveRunModelFallbacksOverride: (...args: unknown[]) =>
hoisted.resolveRunModelFallbacksOverrideMock(...args),
}));
const {
buildThreadingToolContext,
buildEmbeddedRunBaseParams,
buildEmbeddedRunContexts,
resolveCompactionModelFallbackOptions,
resolveModelFallbackOptions,
resolveProviderScopedAuthProfile,
} = await import("./agent-runner-utils.js");
@ -45,20 +36,21 @@ function makeRun(overrides: Partial<FollowupRun["run"]> = {}): FollowupRun["run"
describe("agent-runner-utils", () => {
beforeEach(() => {
hoisted.resolveRunModelFallbacksOverrideMock.mockClear();
vi.restoreAllMocks();
});
it("resolves model fallback options from run context", () => {
hoisted.resolveRunModelFallbacksOverrideMock.mockReturnValue(["fallback-model"]);
const run = makeRun();
const run = makeRun({
sessionKey: "agent:agent-1:main",
config: {
agents: {
list: [{ id: "agent-1", model: { fallbacks: ["fallback-model"] } }],
},
},
});
const resolved = resolveModelFallbackOptions(run);
expect(hoisted.resolveRunModelFallbacksOverrideMock).toHaveBeenCalledWith({
cfg: run.config,
agentId: run.agentId,
sessionKey: run.sessionKey,
});
expect(resolved).toEqual({
cfg: run.config,
provider: run.provider,
@ -69,19 +61,73 @@ describe("agent-runner-utils", () => {
});
it("passes through missing agentId for helper-based fallback resolution", () => {
hoisted.resolveRunModelFallbacksOverrideMock.mockReturnValue(["fallback-model"]);
const run = makeRun({ agentId: undefined });
const run = makeRun({
agentId: undefined,
sessionKey: "agent:agent-2:main",
config: {
agents: {
list: [{ id: "agent-2", model: { fallbacks: ["fallback-model"] } }],
},
},
});
const resolved = resolveModelFallbackOptions(run);
expect(hoisted.resolveRunModelFallbacksOverrideMock).toHaveBeenCalledWith({
cfg: run.config,
agentId: undefined,
sessionKey: run.sessionKey,
});
expect(resolved.fallbacksOverride).toEqual(["fallback-model"]);
});
it("uses compaction model override for compaction-scoped fallback resolution", () => {
const run = makeRun({
sessionKey: "agent:agent-1:main",
config: {
agents: {
list: [{ id: "agent-1", model: { fallbacks: ["fallback-model"] } }],
defaults: {
compaction: {
model: "openrouter/anthropic/claude-sonnet-4-5",
},
},
},
},
});
const resolved = resolveCompactionModelFallbackOptions(run);
expect(resolved).toEqual({
cfg: run.config,
provider: "openrouter",
model: "anthropic/claude-sonnet-4-5",
agentDir: run.agentDir,
fallbacksOverride: ["fallback-model"],
});
});
it("keeps the primary provider when compaction model override omits a provider", () => {
const run = makeRun({
sessionKey: "agent:agent-1:main",
config: {
agents: {
list: [{ id: "agent-1", model: { fallbacks: ["fallback-model"] } }],
defaults: {
compaction: {
model: "claude-sonnet-4-5",
},
},
},
},
});
const resolved = resolveCompactionModelFallbackOptions(run);
expect(resolved).toEqual({
cfg: run.config,
provider: run.provider,
model: "claude-sonnet-4-5",
agentDir: run.agentDir,
fallbacksOverride: ["fallback-model"],
});
});
it("builds embedded run base params with auth profile and run metadata", () => {
const run = makeRun({ enforceFinalTag: true });
const authProfile = resolveProviderScopedAuthProfile({

View File

@ -168,6 +168,32 @@ export function resolveModelFallbackOptions(run: FollowupRun["run"]) {
};
}
export function resolveCompactionModelFallbackOptions(run: FollowupRun["run"]) {
const resolved = resolveModelFallbackOptions(run);
const override = run.config?.agents?.defaults?.compaction?.model?.trim();
if (!override) {
return resolved;
}
const slashIdx = override.indexOf("/");
if (slashIdx > 0) {
const provider = override.slice(0, slashIdx).trim();
const model = override.slice(slashIdx + 1).trim();
if (provider && model) {
return {
...resolved,
provider,
model,
};
}
}
return {
...resolved,
model: override,
};
}
export function buildEmbeddedRunBaseParams(params: {
run: FollowupRun["run"];
provider: string;