mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-14 10:41:23 +00:00
fix(active-memory): remove built-in fallback model (#65047)
* fix(active-memory): remove built-in fallback model * fix(active-memory): tighten fallback cleanup
This commit is contained in:
@@ -111,7 +111,7 @@ What this means:
|
||||
- `config.agents: ["main"]` opts only the `main` agent into active memory
|
||||
- `config.allowedChatTypes: ["direct"]` keeps active memory on for direct-message style sessions only by default
|
||||
- if `config.model` is unset, active memory inherits the current session model first
|
||||
- `config.modelFallbackPolicy: "default-remote"` keeps the built-in remote fallback as the default when no explicit or inherited model is available
|
||||
- `config.modelFallback` optionally provides your own fallback provider/model for recall
|
||||
- `config.promptStyle: "balanced"` uses the default general-purpose prompt style for `recent` mode
|
||||
- active memory still runs only on eligible interactive persistent chat sessions
|
||||
|
||||
@@ -335,26 +335,22 @@ If `config.model` is unset, Active Memory tries to resolve a model in this order
|
||||
explicit plugin model
|
||||
-> current session model
|
||||
-> agent primary model
|
||||
-> optional built-in remote fallback
|
||||
-> optional configured fallback model
|
||||
```
|
||||
|
||||
`config.modelFallbackPolicy` controls the last step.
|
||||
`config.modelFallback` controls the configured fallback step.
|
||||
|
||||
Default:
|
||||
Optional custom fallback:
|
||||
|
||||
```json5
|
||||
modelFallbackPolicy: "default-remote"
|
||||
modelFallback: "google/gemini-3-flash"
|
||||
```
|
||||
|
||||
Other option:
|
||||
If no explicit, inherited, or configured fallback model resolves, Active Memory
|
||||
skips recall for that turn.
|
||||
|
||||
```json5
|
||||
modelFallbackPolicy: "resolved-only"
|
||||
```
|
||||
|
||||
Use `resolved-only` if you want Active Memory to skip recall instead of falling
|
||||
back to the built-in remote default when no explicit or inherited model is
|
||||
available.
|
||||
`config.modelFallbackPolicy` is retained only as a deprecated compatibility
|
||||
field for older configs. It no longer changes runtime behavior.
|
||||
|
||||
## Advanced escape hatches
|
||||
|
||||
|
||||
@@ -771,12 +771,12 @@ describe("active-memory plugin", () => {
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("uses config.modelFallback before the built-in default fallback", async () => {
|
||||
it("uses config.modelFallback when no session or agent model resolves", async () => {
|
||||
api.config = {};
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
modelFallback: "google/gemini-3-flash",
|
||||
modelFallbackPolicy: "resolved-only",
|
||||
modelFallbackPolicy: "default-remote",
|
||||
};
|
||||
await plugin.register(api as unknown as OpenClawPluginApi);
|
||||
|
||||
@@ -794,6 +794,9 @@ describe("active-memory plugin", () => {
|
||||
provider: "google",
|
||||
model: "gemini-3-flash-preview",
|
||||
});
|
||||
expect(api.logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("config.modelFallbackPolicy is deprecated"),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not use a built-in fallback model even when default-remote is configured", async () => {
|
||||
|
||||
@@ -238,6 +238,11 @@ function normalizePromptConfigText(value: unknown): string | undefined {
|
||||
return text ? text : undefined;
|
||||
}
|
||||
|
||||
function hasDeprecatedModelFallbackPolicy(pluginConfig: unknown): boolean {
|
||||
const raw = asRecord(pluginConfig);
|
||||
return raw ? Object.hasOwn(raw, "modelFallbackPolicy") : false;
|
||||
}
|
||||
|
||||
function resolveSafeTranscriptDir(baseSessionsDir: string, transcriptDir: string): string {
|
||||
const normalized = transcriptDir.trim();
|
||||
if (!normalized || normalized.includes(":") || path.isAbsolute(normalized)) {
|
||||
@@ -1217,35 +1222,22 @@ function getModelRef(
|
||||
modelProviderId?: string;
|
||||
modelId?: string;
|
||||
},
|
||||
): {
|
||||
modelRef?: {
|
||||
provider: string;
|
||||
model: string;
|
||||
};
|
||||
source: "plugin-model" | "session-model" | "agent-primary" | "config-fallback" | "none";
|
||||
} {
|
||||
): { provider: string; model: string } | undefined {
|
||||
const currentRunModel =
|
||||
ctx?.modelProviderId && ctx?.modelId ? `${ctx.modelProviderId}/${ctx.modelId}` : undefined;
|
||||
const agentPrimaryModel = resolveAgentEffectiveModelPrimary(api.config, agentId);
|
||||
const candidates: Array<{
|
||||
source: "plugin-model" | "session-model" | "agent-primary" | "config-fallback";
|
||||
value?: string;
|
||||
}> = [
|
||||
{ source: "plugin-model", value: config.model },
|
||||
{ source: "session-model", value: currentRunModel },
|
||||
{ source: "agent-primary", value: agentPrimaryModel },
|
||||
{ source: "config-fallback", value: config.modelFallback },
|
||||
const candidates = [
|
||||
config.model,
|
||||
currentRunModel,
|
||||
resolveAgentEffectiveModelPrimary(api.config, agentId),
|
||||
config.modelFallback,
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
const parsed = parseModelCandidate(candidate.value);
|
||||
const parsed = parseModelCandidate(candidate);
|
||||
if (parsed) {
|
||||
return {
|
||||
modelRef: parsed,
|
||||
source: candidate.source,
|
||||
};
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
return { source: "none" };
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function runRecallSubagent(params: {
|
||||
@@ -1263,7 +1255,7 @@ async function runRecallSubagent(params: {
|
||||
}): Promise<{ rawReply: string; transcriptPath?: string }> {
|
||||
const workspaceDir = resolveAgentWorkspaceDir(params.api.config, params.agentId);
|
||||
const agentDir = resolveAgentDir(params.api.config, params.agentId);
|
||||
const { modelRef } = getModelRef(params.api, params.agentId, params.config, {
|
||||
const modelRef = getModelRef(params.api, params.agentId, params.config, {
|
||||
modelProviderId: params.currentModelProviderId,
|
||||
modelId: params.currentModelId,
|
||||
});
|
||||
@@ -1507,11 +1499,20 @@ export default definePluginEntry({
|
||||
description: "Proactively surfaces relevant memory before eligible conversational replies.",
|
||||
register(api: OpenClawPluginApi) {
|
||||
let config = normalizePluginConfig(api.pluginConfig);
|
||||
const warnDeprecatedModelFallbackPolicy = (pluginConfig: unknown) => {
|
||||
if (hasDeprecatedModelFallbackPolicy(pluginConfig)) {
|
||||
api.logger.warn?.(
|
||||
"active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior; set config.modelFallback explicitly if you want a fallback model",
|
||||
);
|
||||
}
|
||||
};
|
||||
warnDeprecatedModelFallbackPolicy(api.pluginConfig);
|
||||
const refreshLiveConfigFromRuntime = () => {
|
||||
config = normalizePluginConfig(
|
||||
const livePluginConfig =
|
||||
resolveActiveMemoryPluginConfigFromConfig(api.runtime.config.loadConfig()) ??
|
||||
api.pluginConfig,
|
||||
);
|
||||
api.pluginConfig;
|
||||
config = normalizePluginConfig(livePluginConfig);
|
||||
warnDeprecatedModelFallbackPolicy(livePluginConfig);
|
||||
};
|
||||
api.registerCommand({
|
||||
name: "active-memory",
|
||||
|
||||
Reference in New Issue
Block a user