mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
Sessions: split chat type derivation seam
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { deriveSessionChatType } from "../sessions/session-chat-type.js";
|
||||
import { deriveSessionChatTypeFromKey } from "../sessions/session-chat-type-shared.js";
|
||||
import {
|
||||
getSubagentDepth,
|
||||
isCronSessionKey,
|
||||
@@ -70,7 +70,7 @@ describe("isCronSessionKey", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("deriveSessionChatType", () => {
|
||||
describe("deriveSessionChatTypeFromKey", () => {
|
||||
it.each([
|
||||
{ key: "agent:main:discord:direct:user1", expected: "direct" },
|
||||
{ key: "agent:main:telegram:group:g1", expected: "group" },
|
||||
@@ -83,7 +83,7 @@ describe("deriveSessionChatType", () => {
|
||||
{ key: "agent:main", expected: "unknown" },
|
||||
{ key: "", expected: "unknown" },
|
||||
] as const)("derives chat type for %j => $expected", ({ key, expected }) => {
|
||||
expect(deriveSessionChatType(key)).toBe(expected);
|
||||
expect(deriveSessionChatTypeFromKey(key)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
67
src/sessions/session-chat-type-shared.ts
Normal file
67
src/sessions/session-chat-type-shared.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { parseAgentSessionKey } from "./session-key-utils.js";
|
||||
|
||||
export type SessionKeyChatType = "direct" | "group" | "channel" | "unknown";
|
||||
|
||||
function deriveBuiltInLegacySessionChatType(
|
||||
scopedSessionKey: string,
|
||||
): SessionKeyChatType | undefined {
|
||||
if (/^group:[^:]+$/.test(scopedSessionKey)) {
|
||||
return "group";
|
||||
}
|
||||
if (/^[0-9]+(?:-[0-9]+)*@g\.us$/.test(scopedSessionKey)) {
|
||||
return "group";
|
||||
}
|
||||
if (/^whatsapp:(?!.*:group:).+@g\.us$/.test(scopedSessionKey)) {
|
||||
return "group";
|
||||
}
|
||||
if (/^discord:(?:[^:]+:)?guild-[^:]+:channel-[^:]+$/.test(scopedSessionKey)) {
|
||||
return "channel";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function deriveSessionChatTypeFromScopedKey(
|
||||
scopedSessionKey: string,
|
||||
deriveLegacySessionChatTypes: Array<
|
||||
(scopedSessionKey: string) => SessionKeyChatType | undefined
|
||||
> = [],
|
||||
): SessionKeyChatType {
|
||||
const tokens = new Set(scopedSessionKey.split(":").filter(Boolean));
|
||||
if (tokens.has("group")) {
|
||||
return "group";
|
||||
}
|
||||
if (tokens.has("channel")) {
|
||||
return "channel";
|
||||
}
|
||||
if (tokens.has("direct") || tokens.has("dm")) {
|
||||
return "direct";
|
||||
}
|
||||
const builtInLegacy = deriveBuiltInLegacySessionChatType(scopedSessionKey);
|
||||
if (builtInLegacy) {
|
||||
return builtInLegacy;
|
||||
}
|
||||
for (const deriveLegacySessionChatType of deriveLegacySessionChatTypes) {
|
||||
const derived = deriveLegacySessionChatType(scopedSessionKey);
|
||||
if (derived) {
|
||||
return derived;
|
||||
}
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort chat-type extraction from session keys across canonical and legacy formats.
|
||||
*/
|
||||
export function deriveSessionChatTypeFromKey(
|
||||
sessionKey: string | undefined | null,
|
||||
deriveLegacySessionChatTypes: Array<
|
||||
(scopedSessionKey: string) => SessionKeyChatType | undefined
|
||||
> = [],
|
||||
): SessionKeyChatType {
|
||||
const raw = (sessionKey ?? "").trim().toLowerCase();
|
||||
if (!raw) {
|
||||
return "unknown";
|
||||
}
|
||||
const scoped = parseAgentSessionKey(raw)?.rest ?? raw;
|
||||
return deriveSessionChatTypeFromScopedKey(scoped, deriveLegacySessionChatTypes);
|
||||
}
|
||||
@@ -1,54 +1,24 @@
|
||||
import { iterateBootstrapChannelPlugins } from "../channels/plugins/bootstrap-registry.js";
|
||||
import { parseAgentSessionKey } from "./session-key-utils.js";
|
||||
import {
|
||||
deriveSessionChatTypeFromKey,
|
||||
type SessionKeyChatType,
|
||||
} from "./session-chat-type-shared.js";
|
||||
|
||||
export type SessionKeyChatType = "direct" | "group" | "channel" | "unknown";
|
||||
export {
|
||||
deriveSessionChatTypeFromKey,
|
||||
type SessionKeyChatType,
|
||||
} from "./session-chat-type-shared.js";
|
||||
|
||||
function deriveBuiltInLegacySessionChatType(
|
||||
scopedSessionKey: string,
|
||||
): SessionKeyChatType | undefined {
|
||||
if (/^group:[^:]+$/.test(scopedSessionKey)) {
|
||||
return "group";
|
||||
}
|
||||
if (/^[0-9]+(?:-[0-9]+)*@g\.us$/.test(scopedSessionKey)) {
|
||||
return "group";
|
||||
}
|
||||
if (/^whatsapp:(?!.*:group:).+@g\.us$/.test(scopedSessionKey)) {
|
||||
return "group";
|
||||
}
|
||||
if (/^discord:(?:[^:]+:)?guild-[^:]+:channel-[^:]+$/.test(scopedSessionKey)) {
|
||||
return "channel";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort chat-type extraction from session keys across canonical and legacy formats.
|
||||
*/
|
||||
export function deriveSessionChatType(sessionKey: string | undefined | null): SessionKeyChatType {
|
||||
const raw = (sessionKey ?? "").trim().toLowerCase();
|
||||
if (!raw) {
|
||||
return "unknown";
|
||||
}
|
||||
const scoped = parseAgentSessionKey(raw)?.rest ?? raw;
|
||||
const tokens = new Set(scoped.split(":").filter(Boolean));
|
||||
if (tokens.has("group")) {
|
||||
return "group";
|
||||
}
|
||||
if (tokens.has("channel")) {
|
||||
return "channel";
|
||||
}
|
||||
if (tokens.has("direct") || tokens.has("dm")) {
|
||||
return "direct";
|
||||
}
|
||||
const builtInLegacy = deriveBuiltInLegacySessionChatType(scoped);
|
||||
if (builtInLegacy) {
|
||||
return builtInLegacy;
|
||||
}
|
||||
for (const plugin of iterateBootstrapChannelPlugins()) {
|
||||
const derived = plugin.messaging?.deriveLegacySessionChatType?.(scoped);
|
||||
if (derived) {
|
||||
return derived;
|
||||
}
|
||||
}
|
||||
return "unknown";
|
||||
return deriveSessionChatTypeFromKey(
|
||||
sessionKey,
|
||||
iterateBootstrapChannelPlugins()
|
||||
.map((plugin) => plugin.messaging?.deriveLegacySessionChatType)
|
||||
.filter(
|
||||
(
|
||||
deriveLegacySessionChatType,
|
||||
): deriveLegacySessionChatType is NonNullable<typeof deriveLegacySessionChatType> =>
|
||||
Boolean(deriveLegacySessionChatType),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user