fix(active-memory): skip colon-containing session-store channels to prevent crash with QQ c2c agent IDs (#77402)

Summary:
- The PR filters colon-containing store-derived Active Memory channel values before embedded recall resolution, adds a QQ c2c regression test, and records the user-facing changelog entry.
- Reproducibility: yes. Source inspection on current main shows a stored colon-containing `lastChannel` or `ch ... come the strong embedded recall channel, and the downstream bundled-plugin directory validator rejects `:`.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fixup! fix(active-memory): add changelog contributor credit (clawswee…
- PR branch already contained follow-up commit before automerge: fix(active-memory): skip colon-containing session-store channels

Validation:
- ClawSweeper review passed for head 4bf00dd6ac.
- Required merge gates passed before the squash merge.

Prepared head SHA: 4bf00dd6ac
Review: https://github.com/openclaw/openclaw/pull/77402#issuecomment-4372618783

Co-authored-by: HCL <chenglunhu@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
This commit is contained in:
hcl
2026-05-05 02:37:05 +08:00
committed by GitHub
parent 417660b662
commit dff437a1cb
3 changed files with 37 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ Docs: https://docs.openclaw.ai
### Changes
- Plugins/active-memory: skip session-store channel entries that contain `:` when resolving the recall subagent's channel, so QQ c2c agent IDs (e.g. `c2c:10D4F7C2…`) and other scoped conversation IDs do not reach bundled-plugin `dirName` validation and crash the recall run. The same guard already applied to explicit `channelId` params (#76704); this extends it to store-derived channels. (#77396) Thanks @hclsys.
- Models/auth: add `openclaw models auth list [--provider <id>] [--json]` so users can inspect saved per-agent auth profiles without dumping secrets or hitting the old “too many arguments” path. Thanks @vincentkoc.
- Control UI/header: show the active agent name in dashboard breadcrumbs without adding the current session key, keeping non-chat views oriented without crowding the topbar.
- Control UI/cron: make the New Job sidebar collapsible so the jobs list can reclaim space while keeping the form one click away. Thanks @BunsDev.

View File

@@ -2753,6 +2753,33 @@ describe("active-memory plugin", () => {
});
});
it("skips colon-containing session-store channels for embedded recall (#77396)", async () => {
hoisted.sessionStore["agent:main:qqbot:direct:12345"] = {
sessionId: "session-a",
updatedAt: 25,
channel: "c2c:10D4F7C2",
origin: {
provider: "qqbot",
},
};
await hooks.before_prompt_build(
{ prompt: "what wings should i order? scoped stored channel", messages: [] },
{
agentId: "main",
trigger: "user",
sessionKey: "agent:main:qqbot:direct:12345",
messageProvider: "qqbot",
channelId: "qqbot",
},
);
expect(runEmbeddedPiAgent.mock.calls.at(-1)?.[0]).toMatchObject({
messageChannel: "qqbot",
messageProvider: "qqbot",
});
});
it("preserves an explicit real channel hint over a stale stored wrapper channel", async () => {
hoisted.sessionStore["agent:main:telegram:direct:12345"] = {
sessionId: "session-a",

View File

@@ -560,9 +560,17 @@ function resolveRecallRunChannelContext(params: {
store,
sessionKey: resolvedSessionKey,
}).existing;
const strongEntryChannel =
const rawStrongEntryChannel =
normalizeOptionalString(sessionEntry?.lastChannel) ??
normalizeOptionalString(sessionEntry?.channel);
// Channel IDs containing ":" are scoped conversation IDs (e.g. QQ c2c
// "c2c:10D4F7C2..."), not runnable channel names. The same guard that
// applies to explicit channelId (#76704) must also apply to channels
// read from the session store (#77396).
const strongEntryChannel =
rawStrongEntryChannel && !rawStrongEntryChannel.includes(":")
? rawStrongEntryChannel
: undefined;
const weakEntryChannel = normalizeOptionalString(sessionEntry?.origin?.provider);
return resolveReturnValue({
resolvedChannel: strongEntryChannel ?? weakEntryChannel,