Skip to content

Fix #63992: resolveSessionKey hardcodes DEFAULT_AGENT_ID instead of using configured default agent#64108

Closed
mushuiyu886 wants to merge 4 commits into
openclaw:mainfrom
mushuiyu886:fix/issue-63992-v2
Closed

Fix #63992: resolveSessionKey hardcodes DEFAULT_AGENT_ID instead of using configured default agent#64108
mushuiyu886 wants to merge 4 commits into
openclaw:mainfrom
mushuiyu886:fix/issue-63992-v2

Conversation

@mushuiyu886

Copy link
Copy Markdown
Contributor

Summary

Fixes #63992

Problem

resolveSessionKey() was hardcoding DEFAULT_AGENT_ID ("main") when building session keys for non-group chats, ignoring any configured default agent. This was a regression from PR #30654.

Changes

Root fix (src/config/sessions/session-key.ts)

  • Added OpenClawConfig import
  • Added resolveDefaultAgentId import from agent-scope.ts
  • Added optional cfg?: OpenClawConfig parameter to resolveSessionKey
  • Replaced hardcoded DEFAULT_AGENT_ID with resolveDefaultAgentId(cfg ?? {})

Call site fixes

  • src/agents/command/session.ts: pass opts.cfg to resolveSessionKey
  • extensions/slack/src/monitor/context.ts: pass params.cfg to resolveSessionKey

Notes

Some call sites (whatsapp, auto-reply/reply/session.ts) already use canonicalizeMainSessionAlias as a workaround and are unaffected by this change. The fix is backward compatible - call sites that don't pass cfg will continue to use DEFAULT_AGENT_ID="main".

Testing

Existing tests pass. The fix allows custom default agents (e.g., default: true on a non-main agent) to be properly respected when resolving session keys.

…ULT_AGENT_ID

resolveSessionKey() was hardcoding DEFAULT_AGENT_ID ("main") when building
session keys for non-group chats, ignoring any configured default agent.

Now passes the OpenClawConfig to resolveDefaultAgentId() so that user-defined
default agents are respected when resolving session keys.

Fixed call sites:
- src/config/sessions/session-key.ts: added cfg parameter and use resolveDefaultAgentId
- src/agents/command/session.ts: pass opts.cfg to resolveSessionKey
- extensions/slack/src/monitor/context.ts: pass params.cfg to resolveSessionKey

Fixes openclaw#63992
@openclaw-barnacle openclaw-barnacle Bot added channel: slack Channel integration: slack agents Agent runtime and tooling size: XS labels Apr 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e3963e8a9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const ctx: MsgContext | undefined = opts.to?.trim() ? { From: opts.to } : undefined;
let sessionKey: string | undefined =
explicitSessionKey ?? (ctx ? resolveSessionKey(scope, ctx, mainKey) : undefined);
explicitSessionKey ?? (ctx ? resolveSessionKey(scope, ctx, mainKey, opts.cfg) : undefined);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Derive store path from resolved session key agent

When no explicit session key is provided, this new call can now produce agent:<default-agent>:..., but storePath/sessionStore were already resolved earlier from explicitSessionKey and still default to the main store. In configs where the default agent is not main, that writes a non-main agent key into the main store, while other code paths that resolve store location from the key’s agent id (for example status/session resolution flows) will read from the non-main agent store and miss the session, splitting history across stores.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a regression where resolveSessionKey() hardcoded DEFAULT_AGENT_ID="main" when building session keys for both direct-chat and group sessions, ignoring any configured default agent. The fix adds an optional cfg?: OpenClawConfig parameter to resolveSessionKey, delegates to resolveDefaultAgentId(cfg ?? {}), and updates two call sites (src/agents/command/session.ts and extensions/slack/src/monitor/context.ts). The change is backward-compatible: callers that omit cfg still resolve to "main".

Confidence Score: 5/5

Safe to merge; the fix is correct and backward-compatible, with only P2 findings.

The core change is logically sound: adding the optional cfg parameter and delegating to resolveDefaultAgentId correctly fixes the regression for both the direct-chat and group key paths. Backward compatibility is preserved for all callers that omit cfg. The two identified findings are P2 — a cross-layer import concern and a missing migration path for existing group session keys — neither of which blocks merge or causes immediate data corruption.

src/config/sessions/session-key.ts — cross-layer import and missing group session migration path

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/config/sessions/session-key.ts
Line: 10

Comment:
**Cross-layer import adds weight to a lightweight utility**

`session-key.ts` is a low-level `config/sessions/` utility; importing `resolveDefaultAgentId` from `agents/agent-scope.ts` pulls in `createSubsystemLogger`, `resolveAgentModelFallbackValues`, `resolveStateDir`, and the rest of the `agents/` module graph into any code path (and test suite) that imports `session-key.ts`.

`main-session.ts` already solves the same problem without the extra dependency:

```ts
const agents = cfg?.agents?.list ?? [];
const defaultAgentId =
  agents.find((agent) => agent?.default)?.id ?? agents[0]?.id ?? DEFAULT_AGENT_ID;
```

Consider inlining this short computation (and replicating the multi-default warning if desired) to avoid widening the import surface of an otherwise lightweight module.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/config/sessions/session-key.ts
Line: 49

Comment:
**No migration path for existing group session keys**

The fix correctly replaces `DEFAULT_AGENT_ID` in both the direct-chat branch (line 47) and the group fallback branch (line 49). For users who previously configured a non-`"main"` default agent, group sessions were stored under `agent:main:<channel>:group:…`; after this change, new messages to the same groups look for `agent:<custom>:<channel>:group:…`, orphaning the older entries.

The direct-chat path has `canonicalizeMainSessionAlias` to cover this legacy shape (see `main-session.ts` lines 62-67). Group session keys have no equivalent migration seam, so any existing group conversation context stored under the old `agent:main:` prefix will be silently dropped for affected users.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(sessions): use configured default ag..." | Re-trigger Greptile

Comment thread src/config/sessions/session-key.ts Outdated
import { normalizeE164 } from "../../utils.js";
import { normalizeExplicitSessionKey } from "./explicit-session-key-normalization.js";
import { resolveGroupSessionKey } from "./group.js";
import { resolveDefaultAgentId } from "../../agents/agent-scope.js";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Cross-layer import adds weight to a lightweight utility

session-key.ts is a low-level config/sessions/ utility; importing resolveDefaultAgentId from agents/agent-scope.ts pulls in createSubsystemLogger, resolveAgentModelFallbackValues, resolveStateDir, and the rest of the agents/ module graph into any code path (and test suite) that imports session-key.ts.

main-session.ts already solves the same problem without the extra dependency:

const agents = cfg?.agents?.list ?? [];
const defaultAgentId =
  agents.find((agent) => agent?.default)?.id ?? agents[0]?.id ?? DEFAULT_AGENT_ID;

Consider inlining this short computation (and replicating the multi-default warning if desired) to avoid widening the import surface of an otherwise lightweight module.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/config/sessions/session-key.ts
Line: 10

Comment:
**Cross-layer import adds weight to a lightweight utility**

`session-key.ts` is a low-level `config/sessions/` utility; importing `resolveDefaultAgentId` from `agents/agent-scope.ts` pulls in `createSubsystemLogger`, `resolveAgentModelFallbackValues`, `resolveStateDir`, and the rest of the `agents/` module graph into any code path (and test suite) that imports `session-key.ts`.

`main-session.ts` already solves the same problem without the extra dependency:

```ts
const agents = cfg?.agents?.list ?? [];
const defaultAgentId =
  agents.find((agent) => agent?.default)?.id ?? agents[0]?.id ?? DEFAULT_AGENT_ID;
```

Consider inlining this short computation (and replicating the multi-default warning if desired) to avoid widening the import surface of an otherwise lightweight module.

How can I resolve this? If you propose a fix, please make it concise.

return canonical;
}
return `agent:${DEFAULT_AGENT_ID}:${raw}`;
return `agent:${defaultAgentId}:${raw}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No migration path for existing group session keys

The fix correctly replaces DEFAULT_AGENT_ID in both the direct-chat branch (line 47) and the group fallback branch (line 49). For users who previously configured a non-"main" default agent, group sessions were stored under agent:main:<channel>:group:…; after this change, new messages to the same groups look for agent:<custom>:<channel>:group:…, orphaning the older entries.

The direct-chat path has canonicalizeMainSessionAlias to cover this legacy shape (see main-session.ts lines 62-67). Group session keys have no equivalent migration seam, so any existing group conversation context stored under the old agent:main: prefix will be silently dropped for affected users.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/config/sessions/session-key.ts
Line: 49

Comment:
**No migration path for existing group session keys**

The fix correctly replaces `DEFAULT_AGENT_ID` in both the direct-chat branch (line 47) and the group fallback branch (line 49). For users who previously configured a non-`"main"` default agent, group sessions were stored under `agent:main:<channel>:group:…`; after this change, new messages to the same groups look for `agent:<custom>:<channel>:group:…`, orphaning the older entries.

The direct-chat path has `canonicalizeMainSessionAlias` to cover this legacy shape (see `main-session.ts` lines 62-67). Group session keys have no equivalent migration seam, so any existing group conversation context stored under the old `agent:main:` prefix will be silently dropped for affected users.

How can I resolve this? If you propose a fix, please make it concise.

@yfge

This comment was marked as spam.

P1: Reorder store loading after session key derivation in
resolveSessionKeyForRequest() so non-main default agents load
the correct store.

P2: Inline resolveDefaultAgentId computation to remove cross-layer
import from agent-scope.ts, following the pattern in main-session.ts.

P2: Add canonicalizeGroupSessionKey() for migration from old group
key format (provider:group:id) to new agent-scoped format
(agent:{id}:provider:group:id).
@mushuiyu886

Copy link
Copy Markdown
Contributor Author

Review feedback addressed

Updated this PR to address all three review comments:

P1: Store loading order (session.ts)

  • Before: storePath/sessionStore were loaded from explicitSessionKey before deriving the final sessionKey, causing non-main default agents to load the wrong store
  • After: Derive sessionKey first via resolveSessionKey(), then load the store from the derived key's agent ID

P2: Cross-layer import (session-key.ts)

  • Before: Imported resolveDefaultAgentId from agent-scope.ts, pulling in heavy dependencies
  • After: Inlined the computation directly in session-key.ts, following the same pattern used in main-session.ts

P2: Group session key migration (session-key.ts)

  • Added canonicalizeGroupSessionKey() that recognizes both old format (provider:group:id) and new agent-scoped format (agent:{id}:provider:group:id)
  • Mirrors the migration pattern of canonicalizeMainSessionAlias for direct-chat keys

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 145ea44214

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

explicitSessionKey ?? (ctx ? resolveSessionKey(scope, ctx, mainKey, opts.cfg) : undefined);

// Now load the store from the derived key's agent ID.
const storeAgentId = resolveAgentIdFromSessionKey(sessionKey ?? explicitSessionKey);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve legacy main-store lookup for session-id resume

Deriving storeAgentId from the newly resolved key means --to requests now start from the configured default agent store, and collectSessionIdMatchesForRequest only scans listAgentIds(cfg) beyond that primary store. In configs that set a non-main default and only list that agent (for example agents.list=[{id:"ops",default:true}]), the legacy main store is no longer searched, so resuming with sessionId can miss an existing session and silently fork history into a new agent store entry.

Useful? React with 👍 / 👎.

When the configured default agent is not "main", the store scan in
collectSessionIdMatchesForRequest would skip the legacy "main" store,
causing sessionId resume to miss existing sessions and silently fork
history. Now always scans the "main" agent store as a fallback.
@mushuiyu886

Copy link
Copy Markdown
Contributor Author

Fix for P2: legacy main-store lookup

Addressed the latest review feedback on session.ts:152.

Problem: After the P1 fix changed storeAgentId derivation to use the resolved session key, configs with a non-main default agent (e.g., agents.list=[{id:"ops",default:true}]) would only scan the "ops" store. The legacy "main" store was skipped, so sessionId resume could miss existing sessions and silently fork history.

Fix: collectSessionIdMatchesForRequest now tracks scanned agent IDs with a Set and explicitly scans the legacy DEFAULT_AGENT_ID ("main") store as a fallback when it hasn't already been covered by the primary store or listAgentIds().

Commit: 8b5e1eb

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14693c8e8b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines 161 to +167
let sessionKey: string | undefined =
explicitSessionKey ?? (ctx ? resolveSessionKey(scope, ctx, mainKey) : undefined);
explicitSessionKey ?? (ctx ? resolveSessionKey(scope, ctx, mainKey, opts.cfg) : undefined);

// Now load the store from the derived key's agent ID.
const storeAgentId = resolveAgentIdFromSessionKey(sessionKey ?? explicitSessionKey);
let storePath = resolveStorePath(sessionCfg?.store, {
agentId: storeAgentId,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve legacy main-key resume on --to requests

resolveSessionKeyForRequest now derives the key with resolveSessionKey(..., opts.cfg), so a non-main default agent produces agent:<default>:main and immediately scopes the store load to that agent. On plain --to resumes (no sessionId), there is no fallback to the legacy agent:main:main entry/store, so existing conversations created before this change are no longer resumed and a new history is silently forked. Please keep a legacy main-key lookup/alias path for this branch, not only the sessionId search path.

Useful? React with 👍 / 👎.

@vincentkoc

Copy link
Copy Markdown
Member

ProjectClownfish could not safely update this branch, so it opened a narrow replacement PR instead.

Replacement PR: #72414
Source PR: #64108
Contributor credit is preserved in the replacement PR body and changelog plan.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: slack Channel integration: slack size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: session key write still hardcodes DEFAULT_AGENT_ID after PR #30654 (regression of #29683)

3 participants