diff --git a/src/agents/tools/sessions-helpers.ts b/src/agents/tools/sessions-helpers.ts index fb40de14d252..984feefed15e 100644 --- a/src/agents/tools/sessions-helpers.ts +++ b/src/agents/tools/sessions-helpers.ts @@ -23,6 +23,7 @@ export { import { normalizeOptionalString, type FastMode } from "@openclaw/normalization-core/string-coerce"; import { getRuntimeConfig } from "../../config/config.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import { parseRawSessionConversationRef } from "../../sessions/session-key-utils.js"; import type { FastModeSource } from "../../shared/fast-mode.js"; /** Coarse session category used by session list/status tools. */ @@ -157,11 +158,5 @@ export function deriveChannel(params: { if (lastChannel) { return lastChannel; } - const parts = params.key.split(":").filter(Boolean); - const scope = parts.at(1); - const keyChannel = parts.at(0); - if (parts.length >= 3 && keyChannel && (scope === "group" || scope === "channel")) { - return keyChannel; - } - return "unknown"; + return parseRawSessionConversationRef(params.key)?.channel ?? "unknown"; } diff --git a/src/agents/tools/sessions-list-tool.test.ts b/src/agents/tools/sessions-list-tool.test.ts index 6cc8f46fdbea..64608e79540f 100644 --- a/src/agents/tools/sessions-list-tool.test.ts +++ b/src/agents/tools/sessions-list-tool.test.ts @@ -44,6 +44,7 @@ vi.mock("./sessions-helpers.js", async (importActual) => { type SessionsListDetails = { sessions?: Array<{ + channel?: string; deliveryContext?: { accountId?: string; channel?: string; @@ -202,6 +203,57 @@ describe("sessions-list-tool", () => { }); }); + it("derives channels only from structurally valid group session keys", async () => { + mocks.gatewayCall.mockImplementation(async (opts: unknown) => { + const request = opts as { method?: string }; + if (request.method === "sessions.list") { + return { + path: "/tmp/sessions.json", + sessions: [ + { + key: "agent:main:slack:channel:C123:thread:1710000000.000100", + kind: "group", + sessionId: "sess-slack-thread", + }, + { + key: "discord:group:ops", + kind: "group", + sessionId: "sess-discord-group", + }, + { + key: "agent:main:matrix:channel:!room:[2001:db8::1]", + kind: "group", + sessionId: "sess-matrix-room", + }, + { + key: "agent:main:agent:plugin:slack:channel:C123", + kind: "group", + sessionId: "sess-nested-agent", + }, + { + key: "agent::slack:channel:C123", + kind: "group", + sessionId: "sess-malformed-agent", + }, + ], + }; + } + return {}; + }); + const tool = createSessionsListTool({ config: {} as never }); + + const result = await tool.execute("call-agent-scoped-channel", {}); + const details = getSessionsListDetails(result); + + expect(details.sessions?.map((session) => session.channel)).toEqual([ + "slack", + "discord", + "matrix", + "unknown", + "unknown", + ]); + }); + it("keeps live session setting metadata in sessions_list results", async () => { mocks.gatewayCall.mockImplementation(async (opts: unknown) => { const request = opts as { method?: string };