Skip to content

Commit 94789d2

Browse files
committed
fix(doctor): clear stale runtime override pins
1 parent aaf8516 commit 94789d2

4 files changed

Lines changed: 110 additions & 1 deletion

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
1+
import type { DoctorSessionRouteStateOwner } from "openclaw/plugin-sdk/runtime-doctor";
2+
13
export const legacyConfigRules = [];
4+
5+
export const sessionRouteStateOwners: DoctorSessionRouteStateOwner[] = [
6+
{
7+
id: "anthropic",
8+
label: "Anthropic",
9+
providerIds: ["anthropic", "claude-cli"],
10+
runtimeIds: ["claude-cli"],
11+
cliSessionKeys: ["claude-cli"],
12+
authProfilePrefixes: ["anthropic:", "claude-cli:"],
13+
},
14+
];
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { DoctorSessionRouteStateOwner } from "openclaw/plugin-sdk/runtime-doctor";
2+
3+
export const sessionRouteStateOwners: DoctorSessionRouteStateOwner[] = [
4+
{
5+
id: "google",
6+
label: "Google",
7+
providerIds: ["google", "google-gemini-cli", "google-vertex"],
8+
runtimeIds: ["google-gemini-cli"],
9+
cliSessionKeys: ["google-gemini-cli", "gemini-cli"],
10+
authProfilePrefixes: ["google:", "google-gemini-cli:", "google-vertex:", "gemini-cli:"],
11+
},
12+
];

src/commands/doctor-session-state-providers.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { describe, expect, it } from "vitest";
2+
import type { SessionEntry } from "../config/sessions.js";
23
import {
34
applySessionRouteStateRepair,
45
resolveConfiguredDoctorSessionStateRoute,
@@ -15,6 +16,15 @@ const codexOwner = {
1516
authProfilePrefixes: ["codex:", "codex-cli:", "openai-codex:"],
1617
};
1718

19+
const anthropicOwner = {
20+
id: "anthropic",
21+
label: "Anthropic",
22+
providerIds: ["anthropic", "claude-cli"],
23+
runtimeIds: ["claude-cli"],
24+
cliSessionKeys: ["claude-cli"],
25+
authProfilePrefixes: ["anthropic:", "claude-cli:"],
26+
};
27+
1828
describe("doctor session state provider routes", () => {
1929
it("skips plugin route-state scans for unrelated recovery metadata", () => {
2030
expect(
@@ -103,6 +113,7 @@ describe("doctor session state provider routes", () => {
103113
fallbackNoticeActiveModel: "openai-codex/gpt-5.4",
104114
fallbackNoticeReason: "rate-limit",
105115
agentHarnessId: "codex",
116+
agentRuntimeOverride: "codex-cli",
106117
authProfileOverride: "openai-codex:default",
107118
authProfileOverrideSource: "auto",
108119
authProfileOverrideCompactionCount: 2,
@@ -162,6 +173,7 @@ describe("doctor session state provider routes", () => {
162173
expect(entry.contextTokens).toBeUndefined();
163174
expect(entry.systemPromptReport).toBeUndefined();
164175
expect(entry.agentHarnessId).toBeUndefined();
176+
expect(entry.agentRuntimeOverride).toBeUndefined();
165177
expect(entry.authProfileOverride).toBeUndefined();
166178
expect(entry.authProfileOverrideSource).toBeUndefined();
167179
expect(entry.authProfileOverrideCompactionCount).toBeUndefined();
@@ -263,4 +275,70 @@ describe("doctor session state provider routes", () => {
263275

264276
expect(scan).toEqual({ repairs: [], manualReview: [] });
265277
});
278+
279+
it("clears stale runtime override-only pins when the owner is no longer configured", () => {
280+
const sessionKey = "agent:main:telegram:direct:claude-stale";
281+
const entry: SessionEntry & Record<string, unknown> = {
282+
sessionId: "sess-stale-claude-cli",
283+
updatedAt: 1,
284+
agentRuntimeOverride: "claude-cli",
285+
};
286+
287+
expect(storeMayContainPluginSessionRouteState({ [sessionKey]: entry })).toBe(true);
288+
289+
const scan = scanSessionRouteStateOwners({
290+
owners: [anthropicOwner],
291+
store: { [sessionKey]: entry },
292+
routes: {
293+
[sessionKey]: {
294+
defaultProvider: "openai",
295+
configuredModelRefs: ["openai/gpt-5.5"],
296+
runtime: "pi",
297+
},
298+
},
299+
});
300+
301+
expect(scan).toEqual({
302+
manualReview: [],
303+
repairs: [
304+
{
305+
key: sessionKey,
306+
ownerId: "anthropic",
307+
ownerLabel: "Anthropic",
308+
cliSessionKeys: ["claude-cli"],
309+
reasons: ["pinned runtime"],
310+
},
311+
],
312+
});
313+
314+
expect(applySessionRouteStateRepair({ entry, repair: scan.repairs[0], now: 456 })).toBe(true);
315+
expect(entry).toStrictEqual({
316+
sessionId: "sess-stale-claude-cli",
317+
updatedAt: 456,
318+
});
319+
});
320+
321+
it("keeps runtime override-only pins when the owner runtime is still configured", () => {
322+
const sessionKey = "agent:main:telegram:direct:claude-current";
323+
const entry: Record<string, unknown> = {
324+
sessionId: "sess-current-claude-cli",
325+
updatedAt: 1,
326+
agentRuntimeOverride: "claude-cli",
327+
};
328+
329+
const scan = scanSessionRouteStateOwners({
330+
owners: [anthropicOwner],
331+
store: { [sessionKey]: entry },
332+
routes: {
333+
[sessionKey]: {
334+
defaultProvider: "anthropic",
335+
configuredModelRefs: ["anthropic/claude-sonnet-4-6"],
336+
runtime: "claude-cli",
337+
},
338+
},
339+
});
340+
341+
expect(scan).toEqual({ repairs: [], manualReview: [] });
342+
expect(entry.agentRuntimeOverride).toBe("claude-cli");
343+
});
266344
});

src/commands/doctor-session-state-providers.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function entryMayContainPluginSessionRouteState(entry: SessionEntry): boolean {
114114
normalizeString(record.modelProvider) !== undefined ||
115115
normalizeString(record.model) !== undefined ||
116116
normalizeString(record.agentHarnessId) !== undefined ||
117+
normalizeString(record.agentRuntimeOverride) !== undefined ||
117118
record.cliSessionBindings !== undefined ||
118119
record.cliSessionIds !== undefined ||
119120
normalizeString(record.authProfileOverride) !== undefined ||
@@ -285,7 +286,11 @@ function scanEntryForOwner(params: {
285286
addReason(reasons, "runtime model state");
286287
}
287288
const harnessId = normalizeString(params.entry.agentHarnessId);
288-
if (harnessId && runtimeIds.has(normalizeProviderId(harnessId))) {
289+
const runtimeOverride = normalizeString(params.entry.agentRuntimeOverride);
290+
if (
291+
(harnessId && runtimeIds.has(normalizeProviderId(harnessId))) ||
292+
(runtimeOverride && runtimeIds.has(normalizeProviderId(runtimeOverride)))
293+
) {
289294
addReason(reasons, "pinned runtime");
290295
}
291296
if (hasOwnedCliSession({ entry: params.entry, cliSessionKeys })) {
@@ -397,6 +402,7 @@ export function applySessionRouteStateRepair(params: {
397402
}
398403
if (params.repair.reasons.includes("pinned runtime")) {
399404
clear("agentHarnessId");
405+
clear("agentRuntimeOverride");
400406
}
401407
if (params.repair.reasons.includes("CLI session binding")) {
402408
changed =

0 commit comments

Comments
 (0)