fix(agents): resolve bound route agent for inbound sessions (#95118) · openclaw/openclaw@a0ed427
849261680
·
2026-06-23
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -301,25 +301,30 @@ export function resolveSessionAgentIds(params: {
|
301 | 301 | sessionKey?: string; |
302 | 302 | config?: OpenClawConfig; |
303 | 303 | agentId?: string; |
| 304 | +fallbackAgentId?: string; |
304 | 305 | }): { |
305 | 306 | defaultAgentId: string; |
306 | 307 | sessionAgentId: string; |
307 | 308 | } { |
308 | 309 | const defaultAgentId = resolveDefaultAgentId(params.config ?? {}); |
309 | 310 | const explicitAgentIdRaw = normalizeLowercaseStringOrEmpty(params.agentId); |
310 | 311 | const explicitAgentId = explicitAgentIdRaw ? normalizeAgentId(explicitAgentIdRaw) : null; |
| 312 | +const fallbackAgentIdRaw = normalizeLowercaseStringOrEmpty(params.fallbackAgentId); |
| 313 | +const fallbackAgentId = fallbackAgentIdRaw ? normalizeAgentId(fallbackAgentIdRaw) : null; |
311 | 314 | const sessionKey = params.sessionKey?.trim(); |
312 | 315 | const normalizedSessionKey = sessionKey ? normalizeLowercaseStringOrEmpty(sessionKey) : undefined; |
313 | 316 | const parsed = normalizedSessionKey ? parseAgentSessionKey(normalizedSessionKey) : null; |
314 | 317 | const sessionAgentId = |
315 | | -explicitAgentId ?? (parsed?.agentId ? normalizeAgentId(parsed.agentId) : defaultAgentId); |
| 318 | +explicitAgentId ?? |
| 319 | +(parsed?.agentId ? normalizeAgentId(parsed.agentId) : (fallbackAgentId ?? defaultAgentId)); |
316 | 320 | return { defaultAgentId, sessionAgentId }; |
317 | 321 | } |
318 | 322 | |
319 | 323 | export function resolveSessionAgentId(params: { |
320 | 324 | sessionKey?: string; |
321 | 325 | config?: OpenClawConfig; |
322 | 326 | agentId?: string; |
| 327 | +fallbackAgentId?: string; |
323 | 328 | }): string { |
324 | 329 | return resolveSessionAgentIds(params).sessionAgentId; |
325 | 330 | } |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -68,4 +68,32 @@ describe("resolveSessionAgentIds", () => {
|
68 | 68 | }); |
69 | 69 | expect(sessionAgentId).toBe("main"); |
70 | 70 | }); |
| 71 | + |
| 72 | +it("uses fallbackAgentId for unscoped channel session keys", () => { |
| 73 | +const { sessionAgentId } = resolveSessionAgentIds({ |
| 74 | +sessionKey: "feishu:direct:ou_user1", |
| 75 | +fallbackAgentId: "main", |
| 76 | +config: cfg, |
| 77 | +}); |
| 78 | +expect(sessionAgentId).toBe("main"); |
| 79 | +}); |
| 80 | + |
| 81 | +it("prefers session-key agent over fallbackAgentId", () => { |
| 82 | +const { sessionAgentId } = resolveSessionAgentIds({ |
| 83 | +sessionKey: "agent:beta:feishu:direct:ou_user1", |
| 84 | +fallbackAgentId: "main", |
| 85 | +config: cfg, |
| 86 | +}); |
| 87 | +expect(sessionAgentId).toBe("beta"); |
| 88 | +}); |
| 89 | + |
| 90 | +it("prefers explicit agentId over fallbackAgentId", () => { |
| 91 | +const { sessionAgentId } = resolveSessionAgentIds({ |
| 92 | +sessionKey: "feishu:direct:ou_user1", |
| 93 | +agentId: "beta", |
| 94 | +fallbackAgentId: "main", |
| 95 | +config: cfg, |
| 96 | +}); |
| 97 | +expect(sessionAgentId).toBe("beta"); |
| 98 | +}); |
71 | 99 | }); |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -394,7 +394,7 @@ const resolveSessionStoreLookup = (
|
394 | 394 | if (!sessionKey) { |
395 | 395 | return {}; |
396 | 396 | } |
397 | | -const agentId = resolveSessionAgentId({ sessionKey, config: cfg, agentId: ctx.AgentId }); |
| 397 | +const agentId = resolveSessionAgentId({ sessionKey, config: cfg, fallbackAgentId: ctx.AgentId }); |
398 | 398 | const storePath = resolveStorePath(cfg.session?.store, { agentId }); |
399 | 399 | try { |
400 | 400 | const store = loadSessionStore(storePath); |
@@ -1275,7 +1275,7 @@ export async function dispatchReplyFromConfig(
|
1275 | 1275 | const sessionAgentId = resolveSessionAgentId({ |
1276 | 1276 | sessionKey: acpDispatchSessionKey, |
1277 | 1277 | config: cfg, |
1278 | | -agentId: ctx.AgentId, |
| 1278 | +fallbackAgentId: ctx.AgentId, |
1279 | 1279 | }); |
1280 | 1280 | const sessionAgentCfg = resolveAgentConfig(cfg, sessionAgentId); |
1281 | 1281 | const verboseProgress = createShouldEmitVerboseProgress({ |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -284,7 +284,7 @@ export async function getReplyFromConfig(
|
284 | 284 | agentId: resolveSessionAgentId({ |
285 | 285 | sessionKey: resolvedAgentSessionKey, |
286 | 286 | config: cfg, |
287 | | -agentId: finalized.AgentId, |
| 287 | +fallbackAgentId: finalized.AgentId, |
288 | 288 | }), |
289 | 289 | }; |
290 | 290 | }, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -265,6 +265,7 @@ export async function initSessionState(params: {
|
265 | 265 | const agentId = resolveSessionAgentId({ |
266 | 266 | sessionKey: sessionCtxForState.SessionKey, |
267 | 267 | config: cfg, |
| 268 | +fallbackAgentId: sessionCtxForState.AgentId, |
268 | 269 | }); |
269 | 270 | const groupResolution = resolveGroupSessionKey(sessionCtxForState) ?? undefined; |
270 | 271 | const resetTriggers = sessionCfg?.resetTriggers?.length |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -137,6 +137,7 @@ describe("buildChannelInboundEventContext", () => {
|
137 | 137 | From: "test:user:u1", |
138 | 138 | To: "test:room:room-1", |
139 | 139 | SessionKey: "agent:main:test:group:room-1", |
| 140 | +AgentId: "main", |
140 | 141 | AccountId: "acct", |
141 | 142 | ParentSessionKey: "agent:main:test:group", |
142 | 143 | ModelParentSessionKey: "agent:main:test:model", |
@@ -211,6 +212,20 @@ describe("buildChannelInboundEventContext", () => {
|
211 | 212 | expect(ctx.CommandAuthorized).toBe(false); |
212 | 213 | }); |
213 | 214 | |
| 215 | +it("carries the routed agent for unscoped session keys", async () => { |
| 216 | +const ctx = buildChannelInboundEventContext( |
| 217 | +createBaseContextParams({ |
| 218 | +route: { |
| 219 | +agentId: "bound-agent", |
| 220 | +routeSessionKey: "feishu:direct:ou_user1", |
| 221 | +}, |
| 222 | +}), |
| 223 | +); |
| 224 | + |
| 225 | +expect(ctx.AgentId).toBe("bound-agent"); |
| 226 | +expect(ctx.SessionKey).toBe("feishu:direct:ou_user1"); |
| 227 | +}); |
| 228 | + |
214 | 229 | it("carries room event semantics into the finalized context", async () => { |
215 | 230 | const ctx = buildChannelInboundEventContext( |
216 | 231 | createBaseContextParams({ |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -484,6 +484,7 @@ export function buildChannelInboundEventContext(
|
484 | 484 | From: params.from, |
485 | 485 | To: params.reply.to, |
486 | 486 | SessionKey: params.route.dispatchSessionKey ?? params.route.routeSessionKey, |
| 487 | +AgentId: params.route.agentId, |
487 | 488 | AccountId: params.route.accountId ?? params.accountId, |
488 | 489 | ParentSessionKey: params.route.parentSessionKey, |
489 | 490 | ModelParentSessionKey: params.route.modelParentSessionKey, |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。