| export type ParsedAgentSessionKey = { |
| agentId: string; |
| rest: string; |
| }; |
|
|
| export type SessionKeyChatType = "direct" | "group" | "channel" | "unknown"; |
|
|
| |
| |
| |
| |
| export function parseAgentSessionKey( |
| sessionKey: string | undefined | null, |
| ): ParsedAgentSessionKey | null { |
| const raw = (sessionKey ?? "").trim().toLowerCase(); |
| if (!raw) { |
| return null; |
| } |
| const parts = raw.split(":").filter(Boolean); |
| if (parts.length < 3) { |
| return null; |
| } |
| if (parts[0] !== "agent") { |
| return null; |
| } |
| const agentId = parts[1]?.trim(); |
| const rest = parts.slice(2).join(":"); |
| if (!agentId || !rest) { |
| return null; |
| } |
| return { agentId, rest }; |
| } |
|
|
| |
| |
| |
| 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"; |
| } |
| |
| |
| if (/^discord:(?:[^:]+:)?guild-[^:]+:channel-[^:]+$/.test(scoped)) { |
| return "channel"; |
| } |
| return "unknown"; |
| } |
|
|
| export function isCronRunSessionKey(sessionKey: string | undefined | null): boolean { |
| const parsed = parseAgentSessionKey(sessionKey); |
| if (!parsed) { |
| return false; |
| } |
| return /^cron:[^:]+:run:[^:]+$/.test(parsed.rest); |
| } |
|
|
| export function isCronSessionKey(sessionKey: string | undefined | null): boolean { |
| const parsed = parseAgentSessionKey(sessionKey); |
| if (!parsed) { |
| return false; |
| } |
| return parsed.rest.toLowerCase().startsWith("cron:"); |
| } |
|
|
| export function isSubagentSessionKey(sessionKey: string | undefined | null): boolean { |
| const raw = (sessionKey ?? "").trim(); |
| if (!raw) { |
| return false; |
| } |
| if (raw.toLowerCase().startsWith("subagent:")) { |
| return true; |
| } |
| const parsed = parseAgentSessionKey(raw); |
| return Boolean((parsed?.rest ?? "").toLowerCase().startsWith("subagent:")); |
| } |
|
|
| export function getSubagentDepth(sessionKey: string | undefined | null): number { |
| const raw = (sessionKey ?? "").trim().toLowerCase(); |
| if (!raw) { |
| return 0; |
| } |
| return raw.split(":subagent:").length - 1; |
| } |
|
|
| export function isAcpSessionKey(sessionKey: string | undefined | null): boolean { |
| const raw = (sessionKey ?? "").trim(); |
| if (!raw) { |
| return false; |
| } |
| const normalized = raw.toLowerCase(); |
| if (normalized.startsWith("acp:")) { |
| return true; |
| } |
| const parsed = parseAgentSessionKey(raw); |
| return Boolean((parsed?.rest ?? "").toLowerCase().startsWith("acp:")); |
| } |
|
|
| const THREAD_SESSION_MARKERS = [":thread:", ":topic:"]; |
|
|
| export function resolveThreadParentSessionKey( |
| sessionKey: string | undefined | null, |
| ): string | null { |
| const raw = (sessionKey ?? "").trim(); |
| if (!raw) { |
| return null; |
| } |
| const normalized = raw.toLowerCase(); |
| let idx = -1; |
| for (const marker of THREAD_SESSION_MARKERS) { |
| const candidate = normalized.lastIndexOf(marker); |
| if (candidate > idx) { |
| idx = candidate; |
| } |
| } |
| if (idx <= 0) { |
| return null; |
| } |
| const parent = raw.slice(0, idx).trim(); |
| return parent ? parent : null; |
| } |
|
|