mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:10:45 +00:00
fix: resolve issue #75452
This commit is contained in:
@@ -38,6 +38,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Control UI/chat: show inline feedback when local slash-command dispatch is unavailable or fails unexpectedly instead of clearing the composer silently. Fixes #52105. Thanks @MooreQiao.
|
||||
- Memory/markdown: replace CRLF managed blocks in place and collapse duplicate marker blocks without rewriting unmanaged markdown, so Dreaming and Memory Wiki files self-heal from repeated generated sections. Fixes #75491; supersedes #75495, #75810, and #76008. Thanks @asaenokkostya-coder, @ottodeng, @everettjf, and @lrg913427-dot.
|
||||
- Agents/tools: return critical tool-loop circuit-breaker stops as blocked tool results instead of thrown tool failures, so models see the guardrail and stop retrying the same call. Thanks @rayraiser.
|
||||
- Agents/sessions: preserve pre-existing runtime model and context window after heartbeat turns so a per-run heartbeat model override does not bleed into shared-session status. Fixes #75452. Thanks @zhang-guiping.
|
||||
- Model commands: clarify direct and inline `/model` acknowledgements for non-default selections as session-scoped. Thanks @addu2612.
|
||||
- Doctor/gateway: stop warning that non-existent, unconfigured user-bin directories are required in the Gateway service PATH. Fixes #76017. Thanks @xiphis.
|
||||
- TUI/chat: skip full provider model normalization during context-window warmup while preserving provider-owned context metadata, avoiding cold-start stalls with large model registries. Thanks @547895019.
|
||||
|
||||
@@ -931,6 +931,55 @@ describe("updateSessionStoreAfterAgentRun", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("leaves contextTokens unset when entry has prior model but no contextTokens (heartbeat bleed guard)", async () => {
|
||||
await withTempSessionStore(async ({ storePath }) => {
|
||||
const cfg = {} as OpenClawConfig;
|
||||
const sessionKey = "agent:main:explicit:test-heartbeat-no-context-tokens";
|
||||
const sessionId = "test-heartbeat-no-context-tokens-session";
|
||||
const sessionStore: Record<string, SessionEntry> = {
|
||||
[sessionKey]: {
|
||||
sessionId,
|
||||
updatedAt: 1,
|
||||
modelProvider: "anthropic",
|
||||
model: "claude-opus-4-6",
|
||||
// contextTokens intentionally missing — older session without cached context
|
||||
},
|
||||
};
|
||||
await fs.writeFile(storePath, JSON.stringify(sessionStore, null, 2));
|
||||
|
||||
// Heartbeat turn uses a different, smaller model
|
||||
const result: EmbeddedPiRunResult = {
|
||||
meta: {
|
||||
durationMs: 500,
|
||||
agentMeta: {
|
||||
sessionId,
|
||||
provider: "ollama",
|
||||
model: "llama3.2:1b",
|
||||
contextTokens: 128_000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await updateSessionStoreAfterAgentRun({
|
||||
cfg,
|
||||
sessionId,
|
||||
sessionKey,
|
||||
storePath,
|
||||
sessionStore,
|
||||
defaultProvider: "anthropic",
|
||||
defaultModel: "claude-opus-4-6",
|
||||
result,
|
||||
preserveRuntimeModel: true,
|
||||
});
|
||||
|
||||
// Runtime model should be preserved
|
||||
expect(sessionStore[sessionKey]?.model).toBe("claude-opus-4-6");
|
||||
expect(sessionStore[sessionKey]?.modelProvider).toBe("anthropic");
|
||||
// contextTokens should NOT bleed from the heartbeat run's smaller window
|
||||
expect(sessionStore[sessionKey]?.contextTokens).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to run model when preserveRuntimeModel is true but entry has no prior runtime model", async () => {
|
||||
await withTempSessionStore(async ({ storePath }) => {
|
||||
const cfg = {} as OpenClawConfig;
|
||||
|
||||
@@ -120,7 +120,15 @@ export async function updateSessionStoreAfterAgentRun(params: {
|
||||
// Keep the pre-existing runtime model and context window so a background
|
||||
// heartbeat turn using a different model does not bleed into the main
|
||||
// session's perceived state.
|
||||
next.contextTokens = entry.contextTokens ?? contextTokens;
|
||||
if (entry.model) {
|
||||
// Prior runtime model exists: preserve its contextTokens. When missing,
|
||||
// leave contextTokens unset rather than falling back to the heartbeat
|
||||
// run's context window; status derives it from the preserved model.
|
||||
next.contextTokens = entry.contextTokens;
|
||||
} else {
|
||||
// No prior runtime model: heartbeat establishes initial state.
|
||||
next.contextTokens = entry.contextTokens ?? contextTokens;
|
||||
}
|
||||
setSessionRuntimeModel(next, {
|
||||
provider: entry.modelProvider ?? providerUsed,
|
||||
model: entry.model ?? modelUsed,
|
||||
|
||||
Reference in New Issue
Block a user