mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-13 18:26:04 +00:00
fix(agents): resolve bound route agent for inbound sessions (#95118)
This commit is contained in:
@@ -301,6 +301,7 @@ export function resolveSessionAgentIds(params: {
|
||||
sessionKey?: string;
|
||||
config?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
fallbackAgentId?: string;
|
||||
}): {
|
||||
defaultAgentId: string;
|
||||
sessionAgentId: string;
|
||||
@@ -308,11 +309,14 @@ export function resolveSessionAgentIds(params: {
|
||||
const defaultAgentId = resolveDefaultAgentId(params.config ?? {});
|
||||
const explicitAgentIdRaw = normalizeLowercaseStringOrEmpty(params.agentId);
|
||||
const explicitAgentId = explicitAgentIdRaw ? normalizeAgentId(explicitAgentIdRaw) : null;
|
||||
const fallbackAgentIdRaw = normalizeLowercaseStringOrEmpty(params.fallbackAgentId);
|
||||
const fallbackAgentId = fallbackAgentIdRaw ? normalizeAgentId(fallbackAgentIdRaw) : null;
|
||||
const sessionKey = params.sessionKey?.trim();
|
||||
const normalizedSessionKey = sessionKey ? normalizeLowercaseStringOrEmpty(sessionKey) : undefined;
|
||||
const parsed = normalizedSessionKey ? parseAgentSessionKey(normalizedSessionKey) : null;
|
||||
const sessionAgentId =
|
||||
explicitAgentId ?? (parsed?.agentId ? normalizeAgentId(parsed.agentId) : defaultAgentId);
|
||||
explicitAgentId ??
|
||||
(parsed?.agentId ? normalizeAgentId(parsed.agentId) : (fallbackAgentId ?? defaultAgentId));
|
||||
return { defaultAgentId, sessionAgentId };
|
||||
}
|
||||
|
||||
@@ -320,6 +324,7 @@ export function resolveSessionAgentId(params: {
|
||||
sessionKey?: string;
|
||||
config?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
fallbackAgentId?: string;
|
||||
}): string {
|
||||
return resolveSessionAgentIds(params).sessionAgentId;
|
||||
}
|
||||
|
||||
@@ -68,4 +68,32 @@ describe("resolveSessionAgentIds", () => {
|
||||
});
|
||||
expect(sessionAgentId).toBe("main");
|
||||
});
|
||||
|
||||
it("uses fallbackAgentId for unscoped channel session keys", () => {
|
||||
const { sessionAgentId } = resolveSessionAgentIds({
|
||||
sessionKey: "feishu:direct:ou_user1",
|
||||
fallbackAgentId: "main",
|
||||
config: cfg,
|
||||
});
|
||||
expect(sessionAgentId).toBe("main");
|
||||
});
|
||||
|
||||
it("prefers session-key agent over fallbackAgentId", () => {
|
||||
const { sessionAgentId } = resolveSessionAgentIds({
|
||||
sessionKey: "agent:beta:feishu:direct:ou_user1",
|
||||
fallbackAgentId: "main",
|
||||
config: cfg,
|
||||
});
|
||||
expect(sessionAgentId).toBe("beta");
|
||||
});
|
||||
|
||||
it("prefers explicit agentId over fallbackAgentId", () => {
|
||||
const { sessionAgentId } = resolveSessionAgentIds({
|
||||
sessionKey: "feishu:direct:ou_user1",
|
||||
agentId: "beta",
|
||||
fallbackAgentId: "main",
|
||||
config: cfg,
|
||||
});
|
||||
expect(sessionAgentId).toBe("beta");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -394,7 +394,7 @@ const resolveSessionStoreLookup = (
|
||||
if (!sessionKey) {
|
||||
return {};
|
||||
}
|
||||
const agentId = resolveSessionAgentId({ sessionKey, config: cfg, agentId: ctx.AgentId });
|
||||
const agentId = resolveSessionAgentId({ sessionKey, config: cfg, fallbackAgentId: ctx.AgentId });
|
||||
const storePath = resolveStorePath(cfg.session?.store, { agentId });
|
||||
try {
|
||||
const store = loadSessionStore(storePath);
|
||||
@@ -1275,7 +1275,7 @@ export async function dispatchReplyFromConfig(
|
||||
const sessionAgentId = resolveSessionAgentId({
|
||||
sessionKey: acpDispatchSessionKey,
|
||||
config: cfg,
|
||||
agentId: ctx.AgentId,
|
||||
fallbackAgentId: ctx.AgentId,
|
||||
});
|
||||
const sessionAgentCfg = resolveAgentConfig(cfg, sessionAgentId);
|
||||
const verboseProgress = createShouldEmitVerboseProgress({
|
||||
|
||||
@@ -284,7 +284,7 @@ export async function getReplyFromConfig(
|
||||
agentId: resolveSessionAgentId({
|
||||
sessionKey: resolvedAgentSessionKey,
|
||||
config: cfg,
|
||||
agentId: finalized.AgentId,
|
||||
fallbackAgentId: finalized.AgentId,
|
||||
}),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -265,6 +265,7 @@ export async function initSessionState(params: {
|
||||
const agentId = resolveSessionAgentId({
|
||||
sessionKey: sessionCtxForState.SessionKey,
|
||||
config: cfg,
|
||||
fallbackAgentId: sessionCtxForState.AgentId,
|
||||
});
|
||||
const groupResolution = resolveGroupSessionKey(sessionCtxForState) ?? undefined;
|
||||
const resetTriggers = sessionCfg?.resetTriggers?.length
|
||||
|
||||
@@ -137,6 +137,7 @@ describe("buildChannelInboundEventContext", () => {
|
||||
From: "test:user:u1",
|
||||
To: "test:room:room-1",
|
||||
SessionKey: "agent:main:test:group:room-1",
|
||||
AgentId: "main",
|
||||
AccountId: "acct",
|
||||
ParentSessionKey: "agent:main:test:group",
|
||||
ModelParentSessionKey: "agent:main:test:model",
|
||||
@@ -211,6 +212,20 @@ describe("buildChannelInboundEventContext", () => {
|
||||
expect(ctx.CommandAuthorized).toBe(false);
|
||||
});
|
||||
|
||||
it("carries the routed agent for unscoped session keys", async () => {
|
||||
const ctx = buildChannelInboundEventContext(
|
||||
createBaseContextParams({
|
||||
route: {
|
||||
agentId: "bound-agent",
|
||||
routeSessionKey: "feishu:direct:ou_user1",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(ctx.AgentId).toBe("bound-agent");
|
||||
expect(ctx.SessionKey).toBe("feishu:direct:ou_user1");
|
||||
});
|
||||
|
||||
it("carries room event semantics into the finalized context", async () => {
|
||||
const ctx = buildChannelInboundEventContext(
|
||||
createBaseContextParams({
|
||||
|
||||
@@ -484,6 +484,7 @@ export function buildChannelInboundEventContext(
|
||||
From: params.from,
|
||||
To: params.reply.to,
|
||||
SessionKey: params.route.dispatchSessionKey ?? params.route.routeSessionKey,
|
||||
AgentId: params.route.agentId,
|
||||
AccountId: params.route.accountId ?? params.accountId,
|
||||
ParentSessionKey: params.route.parentSessionKey,
|
||||
ModelParentSessionKey: params.route.modelParentSessionKey,
|
||||
|
||||
Reference in New Issue
Block a user