refactor: normalize main session key handling

This commit is contained in:
Peter Steinberger
2026-01-09 22:30:10 +01:00
parent 83270f98f7
commit 6c7a27c010
14 changed files with 40 additions and 30 deletions

View File

@@ -19,7 +19,7 @@ import {
loadConfig,
STATE_DIR_CLAWDBOT,
} from "../config/config.js";
import { normalizeAgentId } from "../routing/session-key.js";
import { normalizeAgentId, normalizeMainKey } from "../routing/session-key.js";
import { defaultRuntime } from "../runtime.js";
import { resolveUserPath } from "../utils.js";
import {
@@ -1045,7 +1045,7 @@ export async function resolveSandboxContext(params: {
if (!rawSessionKey) return null;
const agentId = resolveAgentIdFromSessionKey(rawSessionKey);
const cfg = resolveSandboxConfigForAgent(params.config, agentId);
const mainKey = params.config?.session?.mainKey?.trim() || "main";
const mainKey = normalizeMainKey(params.config?.session?.mainKey);
if (!shouldSandboxSession(cfg, rawSessionKey, mainKey)) return null;
await maybePruneSandboxes(cfg);
@@ -1121,7 +1121,7 @@ export async function ensureSandboxWorkspaceForSession(params: {
if (!rawSessionKey) return null;
const agentId = resolveAgentIdFromSessionKey(rawSessionKey);
const cfg = resolveSandboxConfigForAgent(params.config, agentId);
const mainKey = params.config?.session?.mainKey?.trim() || "main";
const mainKey = normalizeMainKey(params.config?.session?.mainKey);
if (!shouldSandboxSession(cfg, rawSessionKey, mainKey)) return null;
const agentWorkspaceDir = resolveUserPath(

View File

@@ -1,4 +1,5 @@
import type { ClawdbotConfig } from "../../config/config.js";
import { normalizeMainKey } from "../../routing/session-key.js";
export type SessionKind = "main" | "group" | "cron" | "hook" | "node" | "other";
@@ -8,7 +9,7 @@ function normalizeKey(value?: string) {
}
export function resolveMainSessionAlias(cfg: ClawdbotConfig) {
const mainKey = normalizeKey(cfg.session?.mainKey) ?? "main";
const mainKey = normalizeMainKey(cfg.session?.mainKey);
const scope = cfg.session?.scope ?? "per-sender";
const alias = scope === "global" ? "global" : mainKey;
return { mainKey, alias, scope };

View File

@@ -29,6 +29,7 @@ import {
import { resolveSessionFilePath } from "../config/sessions.js";
import { logVerbose } from "../globals.js";
import { clearCommandLane, getQueueSize } from "../process/command-queue.js";
import { normalizeMainKey } from "../routing/session-key.js";
import { defaultRuntime } from "../runtime.js";
import { resolveCommandAuthorization } from "./command-auth.js";
import { hasControlCommand } from "./command-detection.js";
@@ -780,7 +781,7 @@ export async function getReplyFromConfig(
const isGroupSession =
sessionEntry?.chatType === "group" || sessionEntry?.chatType === "room";
const isMainSession =
!isGroupSession && sessionKey === (sessionCfg?.mainKey ?? "main");
!isGroupSession && sessionKey === normalizeMainKey(sessionCfg?.mainKey);
prefixedBodyBase = await prependSystemEvents({
cfg,
sessionKey,

View File

@@ -23,6 +23,7 @@ import {
type SessionScope,
saveSessionStore,
} from "../../config/sessions.js";
import { normalizeMainKey } from "../../routing/session-key.js";
import { resolveCommandAuthorization } from "../command-auth.js";
import type { MsgContext, TemplateContext } from "../templating.js";
import { stripMentions, stripStructuralPrefixes } from "./mentions.js";
@@ -90,7 +91,7 @@ export async function initSessionState(params: {
}): Promise<SessionInitResult> {
const { ctx, cfg, commandAuthorized } = params;
const sessionCfg = cfg.session;
const mainKey = sessionCfg?.mainKey ?? "main";
const mainKey = normalizeMainKey(sessionCfg?.mainKey);
const agentId = resolveAgentIdFromSessionKey(ctx.SessionKey);
const resetTriggers = sessionCfg?.resetTriggers?.length
? sessionCfg.resetTriggers

View File

@@ -7,6 +7,7 @@ import {
resolveStorePath,
} from "../config/sessions.js";
import { callGateway, randomIdempotencyKey } from "../gateway/call.js";
import { normalizeMainKey } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { normalizeMessageProvider } from "../utils/message-provider.js";
import { agentCommand } from "./agent.js";
@@ -51,7 +52,7 @@ function resolveGatewaySessionKey(opts: {
}): string | undefined {
const sessionCfg = opts.cfg.session;
const scope = sessionCfg?.scope ?? "per-sender";
const mainKey = sessionCfg?.mainKey ?? "main";
const mainKey = normalizeMainKey(sessionCfg?.mainKey);
const storePath = resolveStorePath(sessionCfg?.store);
const store = loadSessionStore(storePath);

View File

@@ -56,6 +56,7 @@ import {
normalizeOutboundPayloadsForJson,
} from "../infra/outbound/payloads.js";
import { resolveOutboundTarget } from "../infra/outbound/targets.js";
import { normalizeMainKey } from "../routing/session-key.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { resolveSendPolicy } from "../sessions/send-policy.js";
import {
@@ -104,7 +105,7 @@ function resolveSession(opts: {
}): SessionResolution {
const sessionCfg = opts.cfg.session;
const scope = sessionCfg?.scope ?? "per-sender";
const mainKey = sessionCfg?.mainKey ?? "main";
const mainKey = normalizeMainKey(sessionCfg?.mainKey);
const idleMinutes = Math.max(
sessionCfg?.idleMinutes ?? DEFAULT_IDLE_MINUTES,
1,

View File

@@ -9,8 +9,8 @@ import type { MsgContext } from "../auto-reply/templating.js";
import {
buildAgentMainSessionKey,
DEFAULT_AGENT_ID,
DEFAULT_MAIN_KEY,
normalizeAgentId,
normalizeMainKey,
resolveAgentIdFromSessionKey,
} from "../routing/session-key.js";
import { normalizeE164 } from "../utils.js";
@@ -228,8 +228,7 @@ export function resolveMainSessionKey(cfg?: {
agents[0]?.id ??
DEFAULT_AGENT_ID;
const agentId = normalizeAgentId(defaultAgentId);
const mainKey =
(cfg?.session?.mainKey ?? DEFAULT_MAIN_KEY).trim() || DEFAULT_MAIN_KEY;
const mainKey = normalizeMainKey(cfg?.session?.mainKey);
return buildAgentMainSessionKey({ agentId, mainKey });
}
@@ -243,9 +242,7 @@ export function resolveAgentMainSessionKey(params: {
cfg?: { session?: { mainKey?: string } };
agentId: string;
}): string {
const mainKey =
(params.cfg?.session?.mainKey ?? DEFAULT_MAIN_KEY).trim() ||
DEFAULT_MAIN_KEY;
const mainKey = normalizeMainKey(params.cfg?.session?.mainKey);
return buildAgentMainSessionKey({ agentId: params.agentId, mainKey });
}
@@ -548,8 +545,7 @@ export function resolveSessionKey(
if (explicit) return explicit;
const raw = deriveSessionKey(scope, ctx);
if (scope === "global") return raw;
const canonicalMainKey =
(mainKey ?? DEFAULT_MAIN_KEY).trim() || DEFAULT_MAIN_KEY;
const canonicalMainKey = normalizeMainKey(mainKey);
const canonical = buildAgentMainSessionKey({
agentId: DEFAULT_AGENT_ID,
mainKey: canonicalMainKey,

View File

@@ -33,6 +33,7 @@ import {
setVoiceWakeTriggers,
} from "../infra/voicewake.js";
import { clearCommandLane } from "../process/command-queue.js";
import { normalizeMainKey } from "../routing/session-key.js";
import { defaultRuntime } from "../runtime.js";
import { buildMessageWithAttachments } from "./chat-attachments.js";
import {
@@ -944,8 +945,7 @@ export function createBridgeHandlers(ctx: BridgeHandlersContext) {
if (text.length > 20_000) return;
const sessionKeyRaw =
typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
const mainKey =
(loadConfig().session?.mainKey ?? "main").trim() || "main";
const mainKey = normalizeMainKey(loadConfig().session?.mainKey);
const sessionKey = sessionKeyRaw.length > 0 ? sessionKeyRaw : mainKey;
const { storePath, store, entry } = loadSessionEntry(sessionKey);
const now = Date.now();

View File

@@ -9,6 +9,7 @@ import {
saveSessionStore,
} from "../../config/sessions.js";
import { registerAgentRunContext } from "../../infra/agent-events.js";
import { normalizeMainKey } from "../../routing/session-key.js";
import { defaultRuntime } from "../../runtime.js";
import { resolveSendPolicy } from "../../sessions/send-policy.js";
import { normalizeMessageProvider } from "../../utils/message-provider.js";
@@ -129,7 +130,7 @@ export const agentHandlers: GatewayRequestHandlers = {
cfg,
agentId,
});
const rawMainKey = (cfg.session?.mainKey ?? "main").trim() || "main";
const rawMainKey = normalizeMainKey(cfg.session?.mainKey);
if (
requestedSessionKey === mainSessionKey ||
requestedSessionKey === rawMainKey

View File

@@ -21,8 +21,8 @@ import {
type SessionScope,
} from "../config/sessions.js";
import {
DEFAULT_MAIN_KEY,
normalizeAgentId,
normalizeMainKey,
parseAgentSessionKey,
} from "../routing/session-key.js";
@@ -255,8 +255,7 @@ export function listAgentsForGateway(cfg: ClawdbotConfig): {
agents: GatewayAgentRow[];
} {
const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
const mainKey =
(cfg.session?.mainKey ?? DEFAULT_MAIN_KEY).trim() || DEFAULT_MAIN_KEY;
const mainKey = normalizeMainKey(cfg.session?.mainKey);
const scope = cfg.session?.scope ?? "per-sender";
const configuredById = new Map<string, { name?: string }>();
for (const entry of cfg.agents?.list ?? []) {

View File

@@ -6,6 +6,11 @@ function normalizeToken(value: string | undefined | null): string {
return (value ?? "").trim().toLowerCase();
}
export function normalizeMainKey(value: string | undefined | null): string {
const trimmed = (value ?? "").trim();
return trimmed ? trimmed : DEFAULT_MAIN_KEY;
}
export type ParsedAgentSessionKey = {
agentId: string;
rest: string;
@@ -77,8 +82,7 @@ export function buildAgentMainSessionKey(params: {
mainKey?: string | undefined;
}): string {
const agentId = normalizeAgentId(params.agentId);
const mainKey =
(params.mainKey ?? DEFAULT_MAIN_KEY).trim() || DEFAULT_MAIN_KEY;
const mainKey = normalizeMainKey(params.mainKey);
return `agent:${agentId}:${mainKey}`;
}

View File

@@ -53,7 +53,10 @@ import {
upsertProviderPairingRequest,
} from "../pairing/pairing-store.js";
import { resolveAgentRoute } from "../routing/resolve-route.js";
import { resolveThreadSessionKeys } from "../routing/session-key.js";
import {
normalizeMainKey,
resolveThreadSessionKeys,
} from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import { resolveSlackAccount } from "./accounts.js";
import { reactSlackMessage } from "./actions.js";
@@ -427,7 +430,7 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) {
});
const sessionCfg = cfg.session;
const sessionScope = sessionCfg?.scope ?? "per-sender";
const mainKey = (sessionCfg?.mainKey ?? "main").trim() || "main";
const mainKey = normalizeMainKey(sessionCfg?.mainKey);
const resolveSlackSystemEventSessionKey = (params: {
channelId?: string | null;

View File

@@ -12,6 +12,7 @@ import { loadConfig } from "../config/config.js";
import {
buildAgentMainSessionKey,
normalizeAgentId,
normalizeMainKey,
parseAgentSessionKey,
} from "../routing/session-key.js";
import { formatTokenCount } from "../utils/usage-format.js";
@@ -132,7 +133,7 @@ export async function runTui(opts: TuiOptions) {
const initialSessionInput = (opts.session ?? "").trim();
let sessionScope: SessionScope = (config.session?.scope ??
"per-sender") as SessionScope;
let sessionMainKey = (config.session?.mainKey ?? "main").trim() || "main";
let sessionMainKey = normalizeMainKey(config.session?.mainKey);
let agentDefaultId = resolveDefaultAgentId(config);
let currentAgentId = agentDefaultId;
let agents: AgentSummary[] = [];
@@ -263,7 +264,7 @@ export async function runTui(opts: TuiOptions) {
const applyAgentsResult = (result: GatewayAgentsList) => {
agentDefaultId = normalizeAgentId(result.defaultId);
sessionMainKey = result.mainKey.trim() || sessionMainKey;
sessionMainKey = normalizeMainKey(result.mainKey);
sessionScope = result.scope ?? sessionScope;
agents = result.agents.map((agent) => ({
id: normalizeAgentId(agent.id),

View File

@@ -57,6 +57,7 @@ import {
buildGroupHistoryKey,
DEFAULT_MAIN_KEY,
normalizeAgentId,
normalizeMainKey,
} from "../routing/session-key.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { isSelfChatMode, jidToE164, normalizeE164 } from "../utils.js";
@@ -291,7 +292,7 @@ export async function runWebHeartbeatOnce(opts: {
const cfg = cfgOverride ?? loadConfig();
const sessionCfg = cfg.session;
const sessionScope = sessionCfg?.scope ?? "per-sender";
const mainKey = sessionCfg?.mainKey;
const mainKey = normalizeMainKey(sessionCfg?.mainKey);
const sessionKey = resolveSessionKey(sessionScope, { From: to }, mainKey);
if (sessionId) {
const storePath = resolveStorePath(cfg.session?.store);
@@ -539,7 +540,7 @@ function getSessionSnapshot(
const key = resolveSessionKey(
scope,
{ From: from, To: "", Body: "" },
sessionCfg?.mainKey,
normalizeMainKey(sessionCfg?.mainKey),
);
const store = loadSessionStore(resolveStorePath(sessionCfg?.store));
const entry = store[key];