mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:00:43 +00:00
fix: preserve terminal session lifecycle state
This commit is contained in:
@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Agents/sessions: preserve terminal lifecycle state when final run metadata persists from a stale in-memory snapshot, preventing `main` sessions from staying stuck as running after completed or timed-out turns.
|
||||
- Status: show the `openai-codex` OAuth profile for `openai/gpt-*` sessions running through the native Codex runtime instead of reporting auth as unknown. (#76197) Thanks @mbelinky.
|
||||
- Plugins/externalization: keep diagnostics ClawHub packages and persisted bundled-plugin relocation on npm-first install metadata for launch, and omit Discord from the core package now that its external package is published. Thanks @vincentkoc.
|
||||
- Plugins/Codex: allow the official npm Codex plugin to install without the unsafe-install override, keep `/codex` command ownership, and cover the real npm Docker live path through managed `.openclaw/npm` dependencies plus uninstall failure proof.
|
||||
|
||||
@@ -388,6 +388,63 @@ describe("updateSessionStoreAfterAgentRun", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves terminal lifecycle state when caller has a stale running snapshot", async () => {
|
||||
await withTempSessionStore(async ({ storePath }) => {
|
||||
const cfg = {} as OpenClawConfig;
|
||||
const sessionKey = "agent:main:explicit:test-lifecycle-preserve";
|
||||
const sessionId = "test-lifecycle-preserve-session";
|
||||
const terminalEntry: SessionEntry = {
|
||||
sessionId,
|
||||
updatedAt: 2_000,
|
||||
status: "done",
|
||||
startedAt: 1_000,
|
||||
endedAt: 1_900,
|
||||
runtimeMs: 900,
|
||||
};
|
||||
await fs.writeFile(storePath, JSON.stringify({ [sessionKey]: terminalEntry }, null, 2));
|
||||
|
||||
const staleInMemory: Record<string, SessionEntry> = {
|
||||
[sessionKey]: {
|
||||
sessionId,
|
||||
updatedAt: 1_100,
|
||||
status: "running",
|
||||
startedAt: 1_000,
|
||||
},
|
||||
};
|
||||
|
||||
await updateSessionStoreAfterAgentRun({
|
||||
cfg,
|
||||
sessionId,
|
||||
sessionKey,
|
||||
storePath,
|
||||
sessionStore: staleInMemory,
|
||||
defaultProvider: "openai",
|
||||
defaultModel: "gpt-5.4",
|
||||
result: {
|
||||
payloads: [],
|
||||
meta: {
|
||||
aborted: false,
|
||||
agentMeta: {
|
||||
provider: "openai",
|
||||
model: "gpt-5.4",
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
});
|
||||
|
||||
const persisted = loadSessionStore(storePath, { skipCache: true })[sessionKey];
|
||||
expect(persisted).toMatchObject({
|
||||
status: "done",
|
||||
startedAt: 1_000,
|
||||
endedAt: 1_900,
|
||||
runtimeMs: 900,
|
||||
modelProvider: "openai",
|
||||
model: "gpt-5.4",
|
||||
});
|
||||
expect(staleInMemory[sessionKey]?.status).toBe("done");
|
||||
});
|
||||
});
|
||||
|
||||
it("persists latest systemPromptReport for downstream warning dedupe", async () => {
|
||||
await withTempSessionStore(async ({ storePath }) => {
|
||||
const sessionKey = "agent:codex:report:test-system-prompt-report";
|
||||
|
||||
@@ -36,6 +36,15 @@ function resolvePositiveInteger(value: number | undefined): number | undefined {
|
||||
return Math.floor(value);
|
||||
}
|
||||
|
||||
function removeLifecycleStateFromMetadataPatch(entry: SessionEntry): SessionEntry {
|
||||
const next = { ...entry };
|
||||
delete next.status;
|
||||
delete next.startedAt;
|
||||
delete next.endedAt;
|
||||
delete next.runtimeMs;
|
||||
return next;
|
||||
}
|
||||
|
||||
export async function updateSessionStoreAfterAgentRun(params: {
|
||||
cfg: OpenClawConfig;
|
||||
contextTokensOverride?: number;
|
||||
@@ -218,8 +227,9 @@ export async function updateSessionStoreAfterAgentRun(params: {
|
||||
if (compactionsThisRun > 0) {
|
||||
next.compactionCount = (entry.compactionCount ?? 0) + compactionsThisRun;
|
||||
}
|
||||
const metadataPatch = removeLifecycleStateFromMetadataPatch(next);
|
||||
const persisted = await updateSessionStore(storePath, (store) => {
|
||||
const merged = mergeSessionEntry(store[sessionKey], next);
|
||||
const merged = mergeSessionEntry(store[sessionKey], metadataPatch);
|
||||
store[sessionKey] = merged;
|
||||
return merged;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user