Skip to content

Commit 3ad3a90

Browse files
SidSid-Qinshakkernerd
authored
fix(gateway): include disk-scanned agent IDs in listConfiguredAgentIds (#32831)
Merged via squash. Prepared head SHA: 2aa58f6 Co-authored-by: Sid-Qin <[email protected]> Co-authored-by: shakkernerd <[email protected]> Reviewed-by: @shakkernerd
1 parent b02a076 commit 3ad3a90

File tree

3 files changed

+71
-21
lines changed

3 files changed

+71
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai
1515

1616
- Docs/security hardening guidance: document Docker `DOCKER-USER` + UFW policy and add cross-linking from Docker install docs for VPS/public-host setups. (#27613) thanks @dorukardahan.
1717
- Docs/tool-loop detection config keys: align `docs/tools/loop-detection.md` examples and field names with the current `tools.loopDetection` schema to prevent copy-paste validation failures from outdated keys. (#33182) Thanks @Mylszd.
18+
- Gateway/session agent discovery: include disk-scanned agent IDs in `listConfiguredAgentIds` even when `agents.list` is configured, so disk-only/ACP agent sessions remain visible in gateway session aggregation and listings. (#32831) thanks @Sid-Qin.
1819
- Discord/inbound debouncer: skip bot-own MESSAGE_CREATE events before they reach the debounce queue to avoid self-triggered slowdowns in busy servers. Thanks @thewilloftheshadow.
1920
- Discord/Agent-scoped media roots: pass `mediaLocalRoots` through Discord monitor reply delivery (message + component interaction paths) so local media attachments honor per-agent workspace roots instead of falling back to default global roots. Thanks @thewilloftheshadow.
2021
- Discord/slash command handling: intercept text-based slash commands in channels, register plugin commands as native, and send fallback acknowledgments for empty slash runs so interactions do not hang. Thanks @thewilloftheshadow.

src/gateway/session-utils.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import path from "node:path";
44
import { describe, expect, test } from "vitest";
55
import type { OpenClawConfig } from "../config/config.js";
66
import type { SessionEntry } from "../config/sessions.js";
7+
import { withStateDirEnv } from "../test-helpers/state-dir-env.js";
78
import {
89
capArrayByJsonBytes,
910
classifySessionKey,
1011
deriveSessionTitle,
1112
listAgentsForGateway,
1213
listSessionsFromStore,
14+
loadCombinedSessionStoreForGateway,
1315
parseGroupKey,
1416
pruneLegacyStoreKeys,
1517
resolveGatewaySessionStoreTarget,
@@ -310,6 +312,21 @@ describe("gateway session utils", () => {
310312
`data:image/png;base64,${Buffer.from("avatar").toString("base64")}`,
311313
);
312314
});
315+
316+
test("listAgentsForGateway keeps explicit agents.list scope over disk-only agents (scope boundary)", async () => {
317+
await withStateDirEnv("openclaw-agent-list-scope-", async ({ stateDir }) => {
318+
fs.mkdirSync(path.join(stateDir, "agents", "main"), { recursive: true });
319+
fs.mkdirSync(path.join(stateDir, "agents", "codex"), { recursive: true });
320+
321+
const cfg = {
322+
session: { mainKey: "main" },
323+
agents: { list: [{ id: "main", default: true }] },
324+
} as OpenClawConfig;
325+
326+
const { agents } = listAgentsForGateway(cfg);
327+
expect(agents.map((agent) => agent.id)).toEqual(["main"]);
328+
});
329+
});
313330
});
314331

315332
describe("resolveSessionModelRef", () => {
@@ -746,3 +763,45 @@ describe("listSessionsFromStore search", () => {
746763
expect(missing?.totalTokensFresh).toBe(false);
747764
});
748765
});
766+
767+
describe("loadCombinedSessionStoreForGateway includes disk-only agents (#32804)", () => {
768+
test("ACP agent sessions are visible even when agents.list is configured", async () => {
769+
await withStateDirEnv("openclaw-acp-vis-", async ({ stateDir }) => {
770+
const agentsDir = path.join(stateDir, "agents");
771+
const mainDir = path.join(agentsDir, "main", "sessions");
772+
const codexDir = path.join(agentsDir, "codex", "sessions");
773+
fs.mkdirSync(mainDir, { recursive: true });
774+
fs.mkdirSync(codexDir, { recursive: true });
775+
776+
fs.writeFileSync(
777+
path.join(mainDir, "sessions.json"),
778+
JSON.stringify({
779+
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
780+
}),
781+
"utf8",
782+
);
783+
784+
fs.writeFileSync(
785+
path.join(codexDir, "sessions.json"),
786+
JSON.stringify({
787+
"agent:codex:acp-task": { sessionId: "s-codex", updatedAt: 200 },
788+
}),
789+
"utf8",
790+
);
791+
792+
const cfg = {
793+
session: {
794+
mainKey: "main",
795+
store: path.join(stateDir, "agents", "{agentId}", "sessions", "sessions.json"),
796+
},
797+
agents: {
798+
list: [{ id: "main", default: true }],
799+
},
800+
} as OpenClawConfig;
801+
802+
const { store } = loadCombinedSessionStoreForGateway(cfg);
803+
expect(store["agent:main:main"]).toBeDefined();
804+
expect(store["agent:codex:acp-task"]).toBeDefined();
805+
});
806+
});
807+
});

src/gateway/session-utils.ts

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -310,35 +310,25 @@ function listExistingAgentIdsFromDisk(): string[] {
310310
}
311311

312312
function listConfiguredAgentIds(cfg: OpenClawConfig): string[] {
313-
const agents = cfg.agents?.list ?? [];
314-
if (agents.length > 0) {
315-
const ids = new Set<string>();
316-
for (const entry of agents) {
317-
if (entry?.id) {
318-
ids.add(normalizeAgentId(entry.id));
319-
}
320-
}
321-
const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
322-
ids.add(defaultId);
323-
const sorted = Array.from(ids).filter(Boolean);
324-
sorted.sort((a, b) => a.localeCompare(b));
325-
return sorted.includes(defaultId)
326-
? [defaultId, ...sorted.filter((id) => id !== defaultId)]
327-
: sorted;
328-
}
329-
330313
const ids = new Set<string>();
331314
const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
332315
ids.add(defaultId);
316+
317+
for (const entry of cfg.agents?.list ?? []) {
318+
if (entry?.id) {
319+
ids.add(normalizeAgentId(entry.id));
320+
}
321+
}
322+
333323
for (const id of listExistingAgentIdsFromDisk()) {
334324
ids.add(id);
335325
}
326+
336327
const sorted = Array.from(ids).filter(Boolean);
337328
sorted.sort((a, b) => a.localeCompare(b));
338-
if (sorted.includes(defaultId)) {
339-
return [defaultId, ...sorted.filter((id) => id !== defaultId)];
340-
}
341-
return sorted;
329+
return sorted.includes(defaultId)
330+
? [defaultId, ...sorted.filter((id) => id !== defaultId)]
331+
: sorted;
342332
}
343333

344334
export function listAgentsForGateway(cfg: OpenClawConfig): {

0 commit comments

Comments
 (0)