惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
人人都是产品经理
人人都是产品经理
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
GbyAI
GbyAI
博客园 - 司徒正美
美团技术团队
Vercel News
Vercel News
IT之家
IT之家
U
Unit 42
Y
Y Combinator Blog
罗磊的独立博客
Microsoft Security Blog
Microsoft Security Blog
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
V
Visual Studio Blog
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MyScale Blog
MyScale Blog
博客园 - 叶小钗
A
About on SuperTechFans
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
B
Blog RSS Feed

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix #69443: [Bug] Subagent RPC callback to WeChat session...
zhangguiping · 2026-06-15 · via Recent Commits to openclaw:main
Original file line numberDiff line numberDiff line change

@@ -30,6 +30,7 @@ Docs: https://docs.openclaw.ai

3030

- Memory, state, diagnostics, and config: split header-too-large embedding batches, keep QMD memory search enabled in transient mode, avoid SQLite WAL on NFS volumes, preserve recovery scheduling outside stuck-session warning backoff, and keep shell environment fallbacks contained in config write tests. (#92650, #92618, #92639, #91247, #92752) Thanks @mushuiyu886, @TurboTheTurtle, @849261680, and @gnanam1990.

3131

- UI/mobile/TUI: preserve dashboard session parent lineage, WebChat backscroll, reset soft command args, sidebar session picker interactivity, collapsed workspace files, resolved `/model` confirmation refs, and stale foreground iOS Gateway reconnects. (#90658, #92622, #91353, #92705, #92779, #92773, #92552) Thanks @luoyanglang, @TurboTheTurtle, @zhouhe-xydt, @NianJiuZst, @shakkernerd, @NarahariRaghava, and @Solvely-Colin.

3232

- Release and test reliability: extend slow Gateway/full-suite watchdogs, split local full-suite shards when throttled, stabilize plugin auth marker fixtures, avoid brittle provider-ref error text, and keep QA Lab bootstrap selection assertions aligned with flow-only scenarios. (#92652)

33+

- Agent routing: route subagent RPC callbacks addressed to an agent-shaped `--to` target to the correct session key instead of falling back to the main session, so WeChat (and other channel) session-key callbacks reach the intended subagent session. (#90231) Thanks @zhangguiping-xydt.

3334
3435

## 2026.6.6

3536
Original file line numberDiff line numberDiff line change

@@ -615,7 +615,13 @@ async function prepareAgentCommandExecution(opts: AgentCommandOpts, runtime: Run

615615

throw new Error("Message (--message) is required");

616616

}

617617

const rawExplicitSessionKey = opts.sessionKey?.trim();

618-

if (!opts.to && !opts.sessionId && !rawExplicitSessionKey && !opts.agentId) {

618+

const requestedSessionId = opts.sessionId?.trim() || undefined;

619+

const rawTo = opts.to?.trim();

620+

const toSessionKey =

621+

!rawExplicitSessionKey && !requestedSessionId && classifySessionKeyShape(rawTo) === "agent"

622+

? rawTo

623+

: undefined;

624+

if (!opts.to && !requestedSessionId && !rawExplicitSessionKey && !opts.agentId) {

619625

throw new Error(

620626

"Pass --to <E.164>, --session-key, --session-id, or --agent to choose a session",

621627

);

@@ -647,12 +653,14 @@ async function prepareAgentCommandExecution(opts: AgentCommandOpts, runtime: Run

647653

classifySessionKeyShape(rawExplicitSessionKey) === "legacy_or_alias" &&

648654

!isUnscopedSessionKeySentinel(rawExplicitSessionKey),

649655

);

650-

const explicitSessionKey = resolveExplicitAgentCommandSessionKey({

651-

rawExplicitSessionKey,

652-

agentIdOverride,

653-

shouldScopeDefaultAgentKey,

654-

cfg,

655-

});

656+

const explicitSessionKey =

657+

toSessionKey ??

658+

resolveExplicitAgentCommandSessionKey({

659+

rawExplicitSessionKey,

660+

agentIdOverride,

661+

shouldScopeDefaultAgentKey,

662+

cfg,

663+

});

656664

if (explicitSessionKey && classifySessionKeyShape(explicitSessionKey) === "malformed_agent") {

657665

throw new Error(

658666

`Invalid --session-key "${explicitSessionKey}". Agent-prefixed session keys must use agent:<agent-id>:<session-key>.`,

@@ -698,10 +706,13 @@ async function prepareAgentCommandExecution(opts: AgentCommandOpts, runtime: Run

698706

});

699707

const runTimeoutOverrideMs = hasExplicitTimeoutOption ? timeoutMs : undefined;

700708
709+

const commandOpts = toSessionKey

710+

? { ...opts, to: undefined, sessionKey: explicitSessionKey }

711+

: opts;

701712

const sessionResolution = resolveSession({

702713

cfg,

703-

to: opts.to,

704-

sessionId: opts.sessionId,

714+

to: commandOpts.to,

715+

sessionId: commandOpts.sessionId,

705716

sessionKey: explicitSessionKey,

706717

agentId: agentIdOverride,

707718

clone: false,

@@ -791,6 +802,7 @@ async function prepareAgentCommandExecution(opts: AgentCommandOpts, runtime: Run

791802

opts.transcriptMessage ?? resolveInternalEventTranscriptBody(message, opts.internalEvents);

792803
793804

return {

805+

opts: commandOpts,

794806

body,

795807

transcriptBody,

796808

cfg,

@@ -826,15 +838,17 @@ async function prepareAgentCommandExecution(opts: AgentCommandOpts, runtime: Run

826838

}

827839
828840

async function agentCommandInternal(

829-

opts: AgentCommandOpts,

841+

initialOpts: AgentCommandOpts,

830842

runtime: RuntimeEnv = defaultRuntime,

831843

deps?: CliDeps,

832844

) {

833845

const resolvedDeps = await resolveAgentCommandDeps(deps);

834-

const isRawModelRun = opts.modelRun === true || opts.promptMode === "none";

835-

const suppressVisibleSessionEffects = opts.sessionEffects === "internal";

836-

const preserveUserFacingSessionModelState = opts.preserveUserFacingSessionModelState === true;

837-

const prepared = await prepareAgentCommandExecution(opts, runtime);

846+

const isRawModelRun = initialOpts.modelRun === true || initialOpts.promptMode === "none";

847+

const suppressVisibleSessionEffects = initialOpts.sessionEffects === "internal";

848+

const preserveUserFacingSessionModelState =

849+

initialOpts.preserveUserFacingSessionModelState === true;

850+

const prepared = await prepareAgentCommandExecution(initialOpts, runtime);

851+

const opts = prepared.opts;

838852

const {

839853

body,

840854

transcriptBody,

Original file line numberDiff line numberDiff line change

@@ -29,6 +29,7 @@ import type { SessionEntry } from "../../config/sessions/types.js";

2929

import type { OpenClawConfig } from "../../config/types.openclaw.js";

3030

import {

3131

buildAgentMainSessionKey,

32+

classifySessionKeyShape,

3233

DEFAULT_AGENT_ID,

3334

isUnscopedSessionKeySentinel,

3435

normalizeAgentId,

@@ -252,8 +253,14 @@ export function resolveSessionKeyForRequest(opts: {

252253

const defaultAgentId = normalizeAgentId(resolveDefaultAgentId(opts.cfg));

253254

const requestedAgentId = opts.agentId?.trim() ? normalizeAgentId(opts.agentId) : undefined;

254255

const requestedSessionId = opts.sessionId?.trim() || undefined;

256+

const requestedSessionKey = opts.sessionKey?.trim() || undefined;

257+

const toSessionKey =

258+

!requestedSessionKey && !requestedSessionId && classifySessionKeyShape(opts.to) === "agent"

259+

? opts.to?.trim()

260+

: undefined;

255261

const explicitSessionKey =

256-

opts.sessionKey?.trim() ||

262+

requestedSessionKey ||

263+

toSessionKey ||

257264

(!requestedSessionId

258265

? resolveExplicitAgentSessionKey({

259266

cfg: opts.cfg,

Original file line numberDiff line numberDiff line change

@@ -349,6 +349,23 @@ describe("agentCliCommand", () => {

349349

});

350350

});

351351
352+

it("uses an agent-scoped --to value as the gateway session selector", async () => {

353+

await withTempStore(async () => {

354+

const sessionKey = "agent:main:openclaw-weixin:direct:o9cq802hhmfc@im.wechat";

355+

mockGatewaySuccessReply();

356+
357+

await agentCliCommand({ message: "hi", to: sessionKey }, runtime);

358+
359+

expect(callGateway).toHaveBeenCalledTimes(1);

360+

const request = requireRecord(requireFirstCallArg(callGateway, "gateway"), "gateway request");

361+

const params = requireRecord(request.params, "gateway request params");

362+

expect(params.sessionKey).toBe(sessionKey);

363+

expect(params.to).toBeUndefined();

364+

expect(agentCommand).not.toHaveBeenCalled();

365+

expect(loadAgentSessionModuleMock).not.toHaveBeenCalled();

366+

});

367+

});

368+
352369

it("retries gateway dispatch with shell env fallback only when credentials need it", async () => {

353370

await withTempStore(async ({ store }) => {

354371

const fastConfig = {

Original file line numberDiff line numberDiff line change

@@ -290,6 +290,14 @@ function validateExplicitSessionKeyForDispatch(

290290
291291

async function normalizeSessionKeyOptsForDispatch(opts: AgentCliOpts): Promise<AgentCliOpts> {

292292

const rawSessionKey = opts.sessionKey?.trim();

293+

const rawTo = opts.to?.trim();

294+

if (!rawSessionKey && !opts.sessionId?.trim() && classifySessionKeyShape(rawTo) === "agent") {

295+

return {

296+

...opts,

297+

to: undefined,

298+

sessionKey: rawTo,

299+

};

300+

}

293301

const isLegacySessionKey =

294302

rawSessionKey && classifySessionKeyShape(rawSessionKey) === "legacy_or_alias";

295303

const agentIdRaw = opts.agent?.trim();

Original file line numberDiff line numberDiff line change

@@ -7,6 +7,7 @@ import "./agent-command.test-mocks.js";

77

import { testing as acpManagerTesting } from "../acp/control-plane/manager.js";

88

import * as authProfileStoreModule from "../agents/auth-profiles/store.js";

99

import * as attemptExecutionRuntime from "../agents/command/attempt-execution.runtime.js";

10+

import { deliverAgentCommandResult } from "../agents/command/delivery.runtime.js";

1011

import { runEmbeddedAgent } from "../agents/embedded-agent.js";

1112

import { loadManifestModelCatalog, loadModelCatalog } from "../agents/model-catalog.js";

1213

import * as modelSelectionModule from "../agents/model-selection.js";

@@ -1281,6 +1282,49 @@ describe("agentCommand", () => {

12811282

});

12821283

});

12831284
1285+

it("rejects agent-scoped to session selectors that conflict with the requested agent", async () => {

1286+

await withTempHome(async (home) => {

1287+

const store = path.join(home, "sessions.json");

1288+

const sessionKey = "agent:main:openclaw-weixin:direct:o9cq802hhmfc@im.wechat";

1289+

writeSessionStoreSeed(store, {

1290+

[sessionKey]: { sessionId: "wechat-session", updatedAt: Date.now() },

1291+

});

1292+

mockConfig(home, store, undefined, undefined, [{ id: "main" }, { id: "work" }]);

1293+
1294+

await expect(

1295+

agentCommand({ message: "hi", agentId: "work", to: sessionKey }, runtime),

1296+

).rejects.toThrow('Agent id "work" does not match session key agent "main".');

1297+

expect(runEmbeddedAgent).not.toHaveBeenCalled();

1298+

});

1299+

});

1300+
1301+

it("does not forward agent-scoped to session selectors as delivery targets", async () => {

1302+

await withTempHome(async (home) => {

1303+

const store = path.join(home, "sessions.json");

1304+

const sessionKey = "agent:main:openclaw-weixin:direct:o9cq802hhmfc@im.wechat";

1305+

writeSessionStoreSeed(store, {

1306+

[sessionKey]: {

1307+

sessionId: "wechat-session",

1308+

updatedAt: Date.now(),

1309+

lastChannel: "telegram",

1310+

lastTo: "+1555",

1311+

},

1312+

});

1313+

mockConfig(home, store);

1314+
1315+

await agentCommand(

1316+

{ message: "hi", to: sessionKey, deliver: true, channel: "telegram" },

1317+

runtime,

1318+

);

1319+
1320+

const deliveryCall = vi.mocked(deliverAgentCommandResult).mock.calls.at(-1)?.[0] as

1321+

| { opts?: { to?: string }; sessionEntry?: { lastTo?: string } }

1322+

| undefined;

1323+

expect(deliveryCall?.opts?.to).toBeUndefined();

1324+

expect(deliveryCall?.sessionEntry?.lastTo).toBe("+1555");

1325+

});

1326+

});

1327+
12841328

it("scopes bare explicit session keys to the default agent for embedded runs", async () => {

12851329

await withTempHome(async (home) => {

12861330

const store = path.join(home, "sessions.json");

Original file line numberDiff line numberDiff line change

@@ -85,6 +85,21 @@ describe("resolveSessionKeyForRequest", () => {

8585

expect(result.sessionKey).toBe("agent:main:main");

8686

});

8787
88+

it("uses an agent-scoped --to value as the requested session key", () => {

89+

const sessionKey = "agent:main:openclaw-weixin:direct:o9cq802hhmfc@im.wechat";

90+

mocks.resolveStorePath.mockReturnValue(MAIN_STORE_PATH);

91+

mocks.loadSessionStore.mockReturnValue({

92+

[sessionKey]: { sessionId: "wechat-session", updatedAt: 0 },

93+

});

94+
95+

const result = resolveSessionKeyForRequest({

96+

cfg: baseCfg,

97+

to: sessionKey,

98+

});

99+
100+

expect(result.sessionKey).toBe(sessionKey);

101+

});

102+
88103

it("uses the configured default agent store for new --to sessions", () => {

89104

setupMainAndMybotStorePaths();

90105

mockStoresByPath({