fix: scope session id routing to requested agent

This commit is contained in:
Frank Yang
2026-04-24 15:30:49 +08:00
parent 67d8afe1dd
commit ead7c97c3b
5 changed files with 37 additions and 1 deletions

View File

@@ -41,6 +41,7 @@ Docs: https://docs.openclaw.ai
- Plugins/onboarding: record local plugin install source metadata without duplicating raw absolute local paths in persisted `plugins.installs`, while preserving linked load-path cleanup. (#70970) Thanks @vincentkoc.
- Browser/tool: tell agents not to pass per-call `timeoutMs` on existing-session type, evaluate, and other Chrome MCP actions that reject timeout overrides.
- Codex/GPT-5.4: harden fallback, auth-profile, tool-schema, and replay edge cases across native and embedded runtime paths. (#70743) Thanks @100yenadmin.
- Agents/CLI: keep `--agent` plus `--session-id` lookup scoped to the requested agent store, so explicit agent resumes cannot select another agent's session. (#70985) Thanks @frankekn.
- Voice-call/Telnyx: preserve inbound/outbound callback metadata and read transcription text from Telnyx's current `transcription_data` payload.
- Codex harness: send verbose tool progress to chat channels for native app-server runs, matching the Pi harness `/verbose on` and `/verbose full` behavior. (#70966) Thanks @jalehman.
- Codex models: fetch paginated Codex app-server model catalogs, mark truncated `/codex models` output, and keep ChatGPT OAuth defaults on the `openai-codex/gpt-5.5` route instead of the OpenAI API-key route.

View File

@@ -58,6 +58,7 @@ function collectSessionIdMatchesForRequest(opts: {
storePath: string;
storeAgentId?: string;
sessionId: string;
searchOtherAgentStores: boolean;
}): SessionIdMatchSet {
const matches: Array<[string, SessionEntry]> = [];
const primaryStoreMatches: Array<[string, SessionEntry]> = [];
@@ -85,6 +86,10 @@ function collectSessionIdMatchesForRequest(opts: {
};
addMatches(opts.sessionStore, opts.storePath, { primary: true });
if (!opts.searchOtherAgentStores) {
return { matches, primaryStoreMatches, storeByKey };
}
for (const agentId of listAgentIds(opts.cfg)) {
if (agentId === opts.storeAgentId) {
continue;
@@ -146,7 +151,9 @@ export function resolveSessionKeyForRequest(opts: {
agentId: requestedAgentId,
})
: undefined);
const storeAgentId = resolveAgentIdFromSessionKey(explicitSessionKey) ?? requestedAgentId;
const storeAgentId = explicitSessionKey
? resolveAgentIdFromSessionKey(explicitSessionKey)
: (requestedAgentId ?? normalizeAgentId(undefined));
const storePath = resolveStorePath(sessionCfg?.store, {
agentId: storeAgentId,
});
@@ -171,6 +178,7 @@ export function resolveSessionKeyForRequest(opts: {
storePath,
storeAgentId,
sessionId: opts.sessionId,
searchOtherAgentStores: requestedAgentId === undefined,
});
const preferredSelection = resolveSessionIdMatchSelection(matches, opts.sessionId);
const currentStoreSelection =

View File

@@ -126,6 +126,30 @@ describe("resolveSessionKeyForRequest", () => {
expect(result.storePath).toBe(MYBOT_STORE_PATH);
});
it("does not search other agent stores when --agent scopes --session-id", async () => {
setupMainAndMybotStorePaths();
mockStoresByPath({
[MAIN_STORE_PATH]: {
"agent:main:whatsapp:direct:+15550000000": {
sessionId: "target-session-id",
updatedAt: 10,
},
},
[MYBOT_STORE_PATH]: {},
});
const result = resolveSessionKeyForRequest({
cfg: baseCfg,
agentId: "mybot",
sessionId: "target-session-id",
});
expect(result.sessionKey).toBe("agent:mybot:explicit:target-session-id");
expect(result.storePath).toBe(MYBOT_STORE_PATH);
expect(mocks.loadSessionStore).toHaveBeenCalledTimes(1);
expect(mocks.loadSessionStore).toHaveBeenCalledWith(MYBOT_STORE_PATH);
});
it("returns correct sessionStore when session found in non-primary agent store", async () => {
const mybotStore = {
"agent:mybot:main": { sessionId: "target-session-id", updatedAt: 0 },

View File

@@ -1018,9 +1018,11 @@ describe("gateway agent handler", () => {
await waitForAssertion(() => expect(mocks.agentCommand).toHaveBeenCalled());
const call = mocks.agentCommand.mock.calls.at(-1)?.[0] as {
agentId?: string;
sessionId?: string;
sessionKey?: string;
};
expect(call?.agentId).toBe("main");
expect(call?.sessionId).toBe("resume-whatsapp-session");
expect(call?.sessionKey).toBeUndefined();
});

View File

@@ -921,6 +921,7 @@ export const agentHandlers: GatewayRequestHandlers = {
message,
images,
imageOrder,
agentId,
provider: providerOverride,
model: modelOverride,
to: resolvedTo,