refactor: drop legacy session store keys

This commit is contained in:
Peter Steinberger
2026-01-17 06:48:34 +00:00
parent 353d778988
commit 37a2eee837
22 changed files with 65 additions and 93 deletions

View File

@@ -136,11 +136,7 @@ function loadRequesterSessionEntry(requesterSessionKey: string) {
const agentId = resolveAgentIdFromSessionKey(canonicalKey); const agentId = resolveAgentIdFromSessionKey(canonicalKey);
const storePath = resolveStorePath(cfg.session?.store, { agentId }); const storePath = resolveStorePath(cfg.session?.store, { agentId });
const store = loadSessionStore(storePath); const store = loadSessionStore(storePath);
const legacyKey = canonicalKey.startsWith("agent:") const entry = store[canonicalKey];
? canonicalKey.split(":").slice(2).join(":")
: undefined;
const entry =
store[canonicalKey] ?? store[requesterSessionKey] ?? (legacyKey ? store[legacyKey] : undefined);
return { cfg, entry, canonicalKey }; return { cfg, entry, canonicalKey };
} }

View File

@@ -52,11 +52,6 @@ function resolveSessionEntryForKey(
if (!store || !sessionKey) return {}; if (!store || !sessionKey) return {};
const direct = store[sessionKey]; const direct = store[sessionKey];
if (direct) return { entry: direct, key: sessionKey }; if (direct) return { entry: direct, key: sessionKey };
const parsed = parseAgentSessionKey(sessionKey);
const legacyKey = parsed?.rest;
if (legacyKey && store[legacyKey]) {
return { entry: store[legacyKey], key: legacyKey };
}
return {}; return {};
} }

View File

@@ -4,7 +4,6 @@ import { updateSessionStore } from "../../config/sessions.js";
import { logVerbose } from "../../globals.js"; import { logVerbose } from "../../globals.js";
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js"; import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
import { scheduleGatewaySigusr1Restart, triggerClawdbotRestart } from "../../infra/restart.js"; import { scheduleGatewaySigusr1Restart, triggerClawdbotRestart } from "../../infra/restart.js";
import { parseAgentSessionKey } from "../../routing/session-key.js";
import { parseActivationCommand } from "../group-activation.js"; import { parseActivationCommand } from "../group-activation.js";
import { parseSendPolicyCommand } from "../send-policy.js"; import { parseSendPolicyCommand } from "../send-policy.js";
import { import {
@@ -23,11 +22,6 @@ function resolveSessionEntryForKey(
if (!store || !sessionKey) return {}; if (!store || !sessionKey) return {};
const direct = store[sessionKey]; const direct = store[sessionKey];
if (direct) return { entry: direct, key: sessionKey }; if (direct) return { entry: direct, key: sessionKey };
const parsed = parseAgentSessionKey(sessionKey);
const legacyKey = parsed?.rest;
if (legacyKey && store[legacyKey]) {
return { entry: store[legacyKey], key: legacyKey };
}
return {}; return {};
} }

View File

@@ -1,6 +1,7 @@
import { normalizeChatType } from "../../channels/chat-type.js"; import { normalizeChatType } from "../../channels/chat-type.js";
import { resolveConversationLabel } from "../../channels/conversation-label.js"; import { resolveConversationLabel } from "../../channels/conversation-label.js";
import type { MsgContext } from "../templating.js"; import type { MsgContext } from "../templating.js";
import { formatInboundBodyWithSenderMeta } from "./inbound-sender-meta.js";
import { normalizeInboundTextNewlines } from "./inbound-text.js"; import { normalizeInboundTextNewlines } from "./inbound-text.js";
export type FinalizeInboundContextOptions = { export type FinalizeInboundContextOptions = {
@@ -55,5 +56,13 @@ export function finalizeInboundContext<T extends Record<string, unknown>>(
normalized.ConversationLabel = explicitLabel; normalized.ConversationLabel = explicitLabel;
} }
// Ensure group/channel messages retain a sender meta line even when the body is a
// structured envelope (e.g. "[Signal ...] Alice: hi").
normalized.Body = formatInboundBodyWithSenderMeta({ ctx: normalized, body: normalized.Body });
normalized.BodyForAgent = formatInboundBodyWithSenderMeta({
ctx: normalized,
body: normalized.BodyForAgent,
});
return normalized; return normalized;
} }

View File

@@ -170,13 +170,6 @@ export async function initSessionState(params: {
} }
sessionKey = resolveSessionKey(sessionScope, sessionCtxForState, mainKey); sessionKey = resolveSessionKey(sessionScope, sessionCtxForState, mainKey);
if (groupResolution?.legacyKey && groupResolution.legacyKey !== sessionKey) {
const legacyEntry = sessionStore[groupResolution.legacyKey];
if (legacyEntry && !sessionStore[sessionKey]) {
sessionStore[sessionKey] = legacyEntry;
delete sessionStore[groupResolution.legacyKey];
}
}
const entry = sessionStore[sessionKey]; const entry = sessionStore[sessionKey];
const previousSessionEntry = resetTriggered && entry ? { ...entry } : undefined; const previousSessionEntry = resetTriggered && entry ? { ...entry } : undefined;
const idleMs = idleMinutes * 60_000; const idleMs = idleMinutes * 60_000;
@@ -309,12 +302,6 @@ export async function initSessionState(params: {
// Preserve per-session overrides while resetting compaction state on /new. // Preserve per-session overrides while resetting compaction state on /new.
sessionStore[sessionKey] = { ...sessionStore[sessionKey], ...sessionEntry }; sessionStore[sessionKey] = { ...sessionStore[sessionKey], ...sessionEntry };
await updateSessionStore(storePath, (store) => { await updateSessionStore(storePath, (store) => {
if (groupResolution?.legacyKey && groupResolution.legacyKey !== sessionKey) {
if (store[groupResolution.legacyKey] && !store[sessionKey]) {
store[sessionKey] = store[groupResolution.legacyKey];
}
delete store[groupResolution.legacyKey];
}
// Preserve per-session overrides while resetting compaction state on /new. // Preserve per-session overrides while resetting compaction state on /new.
store[sessionKey] = { ...store[sessionKey], ...sessionEntry }; store[sessionKey] = { ...store[sessionKey], ...sessionEntry };
}); });

View File

@@ -4,6 +4,7 @@ import type { MsgContext } from "../../auto-reply/templating.js";
import type { ClawdbotConfig } from "../../config/config.js"; import type { ClawdbotConfig } from "../../config/config.js";
import type { PollInput } from "../../polls.js"; import type { PollInput } from "../../polls.js";
import type { GatewayClientMode, GatewayClientName } from "../../utils/message-channel.js"; import type { GatewayClientMode, GatewayClientName } from "../../utils/message-channel.js";
import type { NormalizedChatType } from "../chat-type.js";
import type { ChatChannelId } from "../registry.js"; import type { ChatChannelId } from "../registry.js";
import type { ChannelMessageActionName as ChannelMessageActionNameFromList } from "./message-action-names.js"; import type { ChannelMessageActionName as ChannelMessageActionNameFromList } from "./message-action-names.js";
@@ -138,7 +139,7 @@ export type ChannelGroupContext = {
}; };
export type ChannelCapabilities = { export type ChannelCapabilities = {
chatTypes: Array<"direct" | "group" | "channel" | "thread">; chatTypes: Array<NormalizedChatType | "thread">;
polls?: boolean; polls?: boolean;
reactions?: boolean; reactions?: boolean;
threads?: boolean; threads?: boolean;

View File

@@ -63,8 +63,8 @@ export function resolveGroupSessionKey(ctx: MsgContext): GroupKeyResolution | nu
if (!isGroup) return null; if (!isGroup) return null;
const providerHint = ctx.Provider?.trim().toLowerCase(); const providerHint = ctx.Provider?.trim().toLowerCase();
const hasLegacyGroupPrefix = from.startsWith("group:"); const hasGroupPrefix = from.startsWith("group:");
const raw = (hasLegacyGroupPrefix ? from.slice("group:".length) : from).trim(); const raw = (hasGroupPrefix ? from.slice("group:".length) : from).trim();
let provider: string | undefined; let provider: string | undefined;
let kind: "group" | "channel" | undefined; let kind: "group" | "channel" | undefined;
@@ -97,7 +97,7 @@ export function resolveGroupSessionKey(ctx: MsgContext): GroupKeyResolution | nu
} }
}; };
if (hasLegacyGroupPrefix) { if (hasGroupPrefix) {
const legacyParts = raw.split(":").filter(Boolean); const legacyParts = raw.split(":").filter(Boolean);
if (legacyParts.length > 1) { if (legacyParts.length > 1) {
parseParts(legacyParts); parseParts(legacyParts);
@@ -115,25 +115,19 @@ export function resolveGroupSessionKey(ctx: MsgContext): GroupKeyResolution | nu
const resolvedProvider = provider ?? providerHint; const resolvedProvider = provider ?? providerHint;
if (!resolvedProvider) { if (!resolvedProvider) {
const legacy = hasLegacyGroupPrefix ? `group:${raw}` : `group:${from}`; const legacy = hasGroupPrefix ? `group:${raw}` : `group:${from}`;
return { return {
key: legacy, key: legacy,
id: raw || from, id: raw || from,
legacyKey: legacy,
chatType: "group", chatType: "group",
}; };
} }
const resolvedKind = kind === "channel" ? "channel" : "group"; const resolvedKind = kind === "channel" ? "channel" : "group";
const key = `${resolvedProvider}:${resolvedKind}:${id || raw || from}`; const key = `${resolvedProvider}:${resolvedKind}:${id || raw || from}`;
let legacyKey: string | undefined;
if (hasLegacyGroupPrefix || from.includes("@g.us")) {
legacyKey = `group:${id || raw || from}`;
}
return { return {
key, key,
legacyKey,
channel: resolvedProvider, channel: resolvedProvider,
id: id || raw || from, id: id || raw || from,
chatType: resolvedKind === "channel" ? "channel" : "group", chatType: resolvedKind === "channel" ? "channel" : "group",

View File

@@ -1,6 +1,7 @@
import crypto from "node:crypto"; import crypto from "node:crypto";
import type { Skill } from "@mariozechner/pi-coding-agent"; import type { Skill } from "@mariozechner/pi-coding-agent";
import type { NormalizedChatType } from "../../channels/chat-type.js";
import type { ChannelId } from "../../channels/plugins/types.js"; import type { ChannelId } from "../../channels/plugins/types.js";
import type { DeliveryContext } from "../../utils/delivery-context.js"; import type { DeliveryContext } from "../../utils/delivery-context.js";
@@ -8,10 +9,7 @@ export type SessionScope = "per-sender" | "global";
export type SessionChannelId = ChannelId | "webchat"; export type SessionChannelId = ChannelId | "webchat";
export type SessionChatType = export type SessionChatType = NormalizedChatType;
| "direct"
| "group"
| "channel";
export type SessionEntry = { export type SessionEntry = {
/** /**
@@ -90,7 +88,6 @@ export function mergeSessionEntry(
export type GroupKeyResolution = { export type GroupKeyResolution = {
key: string; key: string;
legacyKey?: string;
channel?: string; channel?: string;
id?: string; id?: string;
chatType?: SessionChatType; chatType?: SessionChatType;

View File

@@ -1,3 +1,5 @@
import type { NormalizedChatType } from "../channels/chat-type.js";
export type ReplyMode = "text" | "command"; export type ReplyMode = "text" | "command";
export type TypingMode = "never" | "instant" | "thinking" | "message"; export type TypingMode = "never" | "instant" | "thinking" | "message";
export type SessionScope = "per-sender" | "global"; export type SessionScope = "per-sender" | "global";
@@ -41,7 +43,7 @@ export type HumanDelayConfig = {
export type SessionSendPolicyAction = "allow" | "deny"; export type SessionSendPolicyAction = "allow" | "deny";
export type SessionSendPolicyMatch = { export type SessionSendPolicyMatch = {
channel?: string; channel?: string;
chatType?: "direct" | "group" | "channel"; chatType?: NormalizedChatType;
keyPrefix?: string; keyPrefix?: string;
}; };
export type SessionSendPolicyRule = { export type SessionSendPolicyRule = {

View File

@@ -1,8 +1,9 @@
import type { NormalizedChatType } from "../channels/chat-type.js";
import type { AgentElevatedAllowFromConfig, SessionSendPolicyAction } from "./types.base.js"; import type { AgentElevatedAllowFromConfig, SessionSendPolicyAction } from "./types.base.js";
export type MediaUnderstandingScopeMatch = { export type MediaUnderstandingScopeMatch = {
channel?: string; channel?: string;
chatType?: "direct" | "group" | "channel"; chatType?: NormalizedChatType;
keyPrefix?: string; keyPrefix?: string;
}; };

View File

@@ -1,6 +1,7 @@
import { loadConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js";
import { loadSessionStore, resolveStorePath } from "../config/sessions.js"; import { loadSessionStore, resolveStorePath } from "../config/sessions.js";
import { getAgentRunContext, registerAgentRunContext } from "../infra/agent-events.js"; import { getAgentRunContext, registerAgentRunContext } from "../infra/agent-events.js";
import { parseAgentSessionKey } from "../routing/session-key.js";
export function resolveSessionKeyForRun(runId: string) { export function resolveSessionKeyForRun(runId: string) {
const cached = getAgentRunContext(runId)?.sessionKey; const cached = getAgentRunContext(runId)?.sessionKey;
@@ -9,9 +10,12 @@ export function resolveSessionKeyForRun(runId: string) {
const storePath = resolveStorePath(cfg.session?.store); const storePath = resolveStorePath(cfg.session?.store);
const store = loadSessionStore(storePath); const store = loadSessionStore(storePath);
const found = Object.entries(store).find(([, entry]) => entry?.sessionId === runId); const found = Object.entries(store).find(([, entry]) => entry?.sessionId === runId);
const sessionKey = found?.[0]; const storeKey = found?.[0];
if (sessionKey) { if (storeKey) {
const parsed = parseAgentSessionKey(storeKey);
const sessionKey = parsed?.rest ?? storeKey;
registerAgentRunContext(runId, { sessionKey }); registerAgentRunContext(runId, { sessionKey });
}
return sessionKey; return sessionKey;
}
return undefined;
} }

View File

@@ -30,7 +30,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-stale", sessionId: "sess-main-stale",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "whatsapp", lastChannel: "whatsapp",
@@ -115,7 +115,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-account", sessionId: "sess-main-account",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "whatsapp", lastChannel: "whatsapp",
@@ -160,7 +160,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-explicit", sessionId: "sess-main-explicit",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "whatsapp", lastChannel: "whatsapp",
@@ -205,7 +205,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-explicit-account", sessionId: "sess-main-explicit-account",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "whatsapp", lastChannel: "whatsapp",
@@ -251,7 +251,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-implicit", sessionId: "sess-main-implicit",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "whatsapp", lastChannel: "whatsapp",
@@ -294,7 +294,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-images", sessionId: "sess-main-images",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -347,7 +347,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-missing-provider", sessionId: "sess-main-missing-provider",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -388,7 +388,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-whatsapp", sessionId: "sess-main-whatsapp",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "whatsapp", lastChannel: "whatsapp",
@@ -433,7 +433,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "telegram", lastChannel: "telegram",
@@ -477,7 +477,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-discord", sessionId: "sess-discord",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "discord", lastChannel: "discord",
@@ -521,7 +521,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-slack", sessionId: "sess-slack",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "slack", lastChannel: "slack",
@@ -565,7 +565,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-signal", sessionId: "sess-signal",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "signal", lastChannel: "signal",

View File

@@ -84,7 +84,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-teams", sessionId: "sess-teams",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "msteams", lastChannel: "msteams",
@@ -137,7 +137,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-alias", sessionId: "sess-alias",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "imessage", lastChannel: "imessage",
@@ -210,7 +210,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-webchat", sessionId: "sess-main-webchat",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "webchat", lastChannel: "webchat",
@@ -254,7 +254,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main-webchat-internal", sessionId: "sess-main-webchat-internal",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "webchat", lastChannel: "webchat",
@@ -412,7 +412,7 @@ describe("gateway server agent", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },

View File

@@ -240,7 +240,7 @@ describe("gateway server chat", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -353,7 +353,7 @@ describe("gateway server chat", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
sessionFile: forkedPath, sessionFile: forkedPath,
updatedAt: Date.now(), updatedAt: Date.now(),
@@ -401,7 +401,7 @@ describe("gateway server chat", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -451,7 +451,7 @@ describe("gateway server chat", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },

View File

@@ -221,7 +221,7 @@ describe("gateway server node/bridge", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -278,7 +278,7 @@ describe("gateway server node/bridge", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -335,7 +335,7 @@ describe("gateway server node/bridge", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -412,7 +412,7 @@ describe("gateway server node/bridge", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },

View File

@@ -46,7 +46,7 @@ describe("gateway server node/bridge", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
lastChannel: "whatsapp", lastChannel: "whatsapp",
@@ -83,7 +83,7 @@ describe("gateway server node/bridge", () => {
string, string,
{ sessionId?: string } | undefined { sessionId?: string } | undefined
>; >;
expect(stored.main?.sessionId).toBe("sess-main"); expect(stored["agent:main:main"]?.sessionId).toBe("sess-main");
expect(stored["node-ios-node"]).toBeUndefined(); expect(stored["node-ios-node"]).toBeUndefined();
await server.close(); await server.close();
@@ -96,7 +96,7 @@ describe("gateway server node/bridge", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },
@@ -187,7 +187,7 @@ describe("gateway server node/bridge", () => {
testState.sessionStorePath, testState.sessionStorePath,
JSON.stringify( JSON.stringify(
{ {
main: { "agent:main:main": {
sessionId: "sess-main", sessionId: "sess-main",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },

View File

@@ -359,8 +359,8 @@ describe("gateway server sessions", () => {
storePath, storePath,
JSON.stringify( JSON.stringify(
{ {
main: { sessionId: "sess-main", updatedAt: Date.now() }, "agent:main:main": { sessionId: "sess-main", updatedAt: Date.now() },
"discord:group:dev": { "agent:main:discord:group:dev": {
sessionId: "sess-active", sessionId: "sess-active",
updatedAt: Date.now(), updatedAt: Date.now(),
}, },

View File

@@ -50,10 +50,7 @@ export function loadSessionEntry(sessionKey: string) {
const agentId = resolveSessionStoreAgentId(cfg, canonicalKey); const agentId = resolveSessionStoreAgentId(cfg, canonicalKey);
const storePath = resolveStorePath(sessionCfg?.store, { agentId }); const storePath = resolveStorePath(sessionCfg?.store, { agentId });
const store = loadSessionStore(storePath); const store = loadSessionStore(storePath);
const parsed = parseAgentSessionKey(canonicalKey); const entry = store[canonicalKey];
const legacyKey = parsed?.rest ?? parseAgentSessionKey(sessionKey)?.rest ?? undefined;
const entry =
store[canonicalKey] ?? store[sessionKey] ?? (legacyKey ? store[legacyKey] : undefined);
return { cfg, storePath, store, entry, canonicalKey }; return { cfg, storePath, store, entry, canonicalKey };
} }
@@ -248,10 +245,8 @@ export function resolveGatewaySessionStoreTarget(params: { cfg: ClawdbotConfig;
return { agentId, storePath, canonicalKey, storeKeys }; return { agentId, storePath, canonicalKey, storeKeys };
} }
const parsed = parseAgentSessionKey(canonicalKey);
const storeKeys = new Set<string>(); const storeKeys = new Set<string>();
storeKeys.add(canonicalKey); storeKeys.add(canonicalKey);
if (parsed?.rest) storeKeys.add(parsed.rest);
if (key && key !== canonicalKey) storeKeys.add(key); if (key && key !== canonicalKey) storeKeys.add(key);
return { return {
agentId, agentId,

View File

@@ -1,3 +1,4 @@
import type { NormalizedChatType } from "../channels/chat-type.js";
import type { SessionEntry } from "../config/sessions.js"; import type { SessionEntry } from "../config/sessions.js";
import type { DeliveryContext } from "../utils/delivery-context.js"; import type { DeliveryContext } from "../utils/delivery-context.js";
@@ -16,7 +17,7 @@ export type GatewaySessionRow = {
subject?: string; subject?: string;
room?: string; room?: string;
space?: string; space?: string;
chatType?: "direct" | "group" | "channel"; chatType?: NormalizedChatType;
updatedAt: number | null; updatedAt: number | null;
sessionId?: string; sessionId?: string;
systemSent?: boolean; systemSent?: boolean;

View File

@@ -27,7 +27,6 @@ import {
} from "../../auto-reply/reply/history.js"; } from "../../auto-reply/reply/history.js";
import { buildMentionRegexes, matchesMentionPatterns } from "../../auto-reply/reply/mentions.js"; import { buildMentionRegexes, matchesMentionPatterns } from "../../auto-reply/reply/mentions.js";
import { createReplyDispatcher } from "../../auto-reply/reply/reply-dispatcher.js"; import { createReplyDispatcher } from "../../auto-reply/reply/reply-dispatcher.js";
import { formatInboundBodyWithSenderMeta } from "../../auto-reply/reply/inbound-sender-meta.js";
import { loadConfig } from "../../config/config.js"; import { loadConfig } from "../../config/config.js";
import { import {
resolveChannelGroupPolicy, resolveChannelGroupPolicy,
@@ -419,7 +418,6 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
OriginatingChannel: "imessage" as const, OriginatingChannel: "imessage" as const,
OriginatingTo: imessageTo, OriginatingTo: imessageTo,
}); });
ctxPayload.Body = formatInboundBodyWithSenderMeta({ ctx: ctxPayload, body: ctxPayload.Body });
if (!isGroup) { if (!isGroup) {
const sessionCfg = cfg.session; const sessionCfg = cfg.session;

View File

@@ -19,7 +19,6 @@ import {
clearHistoryEntries, clearHistoryEntries,
} from "../../auto-reply/reply/history.js"; } from "../../auto-reply/reply/history.js";
import { finalizeInboundContext } from "../../auto-reply/reply/inbound-context.js"; import { finalizeInboundContext } from "../../auto-reply/reply/inbound-context.js";
import { formatInboundBodyWithSenderMeta } from "../../auto-reply/reply/inbound-sender-meta.js";
import { createReplyDispatcher } from "../../auto-reply/reply/reply-dispatcher.js"; import { createReplyDispatcher } from "../../auto-reply/reply/reply-dispatcher.js";
import { resolveStorePath, updateLastRoute } from "../../config/sessions.js"; import { resolveStorePath, updateLastRoute } from "../../config/sessions.js";
import { danger, logVerbose, shouldLogVerbose } from "../../globals.js"; import { danger, logVerbose, shouldLogVerbose } from "../../globals.js";
@@ -134,7 +133,6 @@ export function createSignalEventHandler(deps: SignalEventHandlerDeps) {
OriginatingChannel: "signal" as const, OriginatingChannel: "signal" as const,
OriginatingTo: signalTo, OriginatingTo: signalTo,
}); });
ctxPayload.Body = formatInboundBodyWithSenderMeta({ ctx: ctxPayload, body: ctxPayload.Body });
if (!entry.isGroup) { if (!entry.isGroup) {
const sessionCfg = deps.cfg.session; const sessionCfg = deps.cfg.session;

View File

@@ -274,7 +274,7 @@ export async function prepareSlackMessage(params: {
}); });
const effectiveWasMentioned = mentionGate.effectiveWasMentioned; const effectiveWasMentioned = mentionGate.effectiveWasMentioned;
if (isRoom && shouldRequireMention && mentionGate.shouldSkip) { if (isRoom && shouldRequireMention && mentionGate.shouldSkip) {
ctx.logger.info({ channel: message.channel, reason: "no-mention" }, "skipping room message"); ctx.logger.info({ channel: message.channel, reason: "no-mention" }, "skipping channel message");
if (ctx.historyLimit > 0) { if (ctx.historyLimit > 0) {
const pendingText = (message.text ?? "").trim(); const pendingText = (message.text ?? "").trim();
const fallbackFile = message.files?.[0]?.name const fallbackFile = message.files?.[0]?.name