Files
Moltbot/src/auto-reply/reply/commands.ts
2026-01-10 02:11:43 +00:00

998 lines
30 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
resolveAgentDir,
resolveDefaultAgentId,
resolveSessionAgentId,
} from "../../agents/agent-scope.js";
import {
ensureAuthProfileStore,
resolveAuthProfileDisplayLabel,
resolveAuthProfileOrder,
} from "../../agents/auth-profiles.js";
import {
getCustomProviderApiKey,
resolveEnvApiKey,
} from "../../agents/model-auth.js";
import { normalizeProviderId } from "../../agents/model-selection.js";
import {
abortEmbeddedPiRun,
compactEmbeddedPiSession,
isEmbeddedPiRunActive,
waitForEmbeddedPiRunEnd,
} from "../../agents/pi-embedded.js";
import type { ClawdbotConfig } from "../../config/config.js";
import {
readConfigFileSnapshot,
validateConfigObject,
writeConfigFile,
} from "../../config/config.js";
import {
getConfigValueAtPath,
parseConfigPath,
setConfigValueAtPath,
unsetConfigValueAtPath,
} from "../../config/config-paths.js";
import {
getConfigOverrides,
resetConfigOverrides,
setConfigOverride,
unsetConfigOverride,
} from "../../config/runtime-overrides.js";
import {
resolveSessionFilePath,
type SessionEntry,
type SessionScope,
saveSessionStore,
} from "../../config/sessions.js";
import { logVerbose } from "../../globals.js";
import {
formatUsageSummaryLine,
loadProviderUsageSummary,
resolveUsageProviderId,
} from "../../infra/provider-usage.js";
import {
scheduleGatewaySigusr1Restart,
triggerClawdbotRestart,
} from "../../infra/restart.js";
import { enqueueSystemEvent } from "../../infra/system-events.js";
import { parseAgentSessionKey } from "../../routing/session-key.js";
import { resolveSendPolicy } from "../../sessions/send-policy.js";
import { normalizeE164 } from "../../utils.js";
import { resolveCommandAuthorization } from "../command-auth.js";
import {
normalizeCommandBody,
shouldHandleTextCommands,
} from "../commands-registry.js";
import {
normalizeGroupActivation,
parseActivationCommand,
} from "../group-activation.js";
import { parseSendPolicyCommand } from "../send-policy.js";
import {
buildCommandsMessage,
buildHelpMessage,
buildStatusMessage,
formatContextUsageShort,
formatTokenCount,
} from "../status.js";
import type { MsgContext } from "../templating.js";
import type {
ElevatedLevel,
ReasoningLevel,
ThinkLevel,
VerboseLevel,
} from "../thinking.js";
import type { ReplyPayload } from "../types.js";
import { isAbortTrigger, setAbortMemory } from "./abort.js";
import { parseConfigCommand } from "./config-commands.js";
import { parseDebugCommand } from "./debug-commands.js";
import type { InlineDirectives } from "./directive-handling.js";
import { stripMentions, stripStructuralPrefixes } from "./mentions.js";
import { getFollowupQueueDepth, resolveQueueSettings } from "./queue.js";
import { incrementCompactionCount } from "./session-updates.js";
function resolveSessionEntryForKey(
store: Record<string, SessionEntry> | undefined,
sessionKey: string | undefined,
) {
if (!store || !sessionKey) return {};
const direct = store[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 {};
}
export type CommandContext = {
surface: string;
provider: string;
isWhatsAppProvider: boolean;
ownerList: string[];
isAuthorizedSender: boolean;
senderE164?: string;
abortKey?: string;
rawBodyNormalized: string;
commandBodyNormalized: string;
from?: string;
to?: string;
};
export async function buildStatusReply(params: {
cfg: ClawdbotConfig;
command: CommandContext;
sessionEntry?: SessionEntry;
sessionKey: string;
sessionScope?: SessionScope;
provider: string;
model: string;
contextTokens: number;
resolvedThinkLevel?: ThinkLevel;
resolvedVerboseLevel: VerboseLevel;
resolvedReasoningLevel: ReasoningLevel;
resolvedElevatedLevel?: ElevatedLevel;
resolveDefaultThinkingLevel: () => Promise<ThinkLevel | undefined>;
isGroup: boolean;
defaultGroupActivation: () => "always" | "mention";
}): Promise<ReplyPayload | undefined> {
const {
cfg,
command,
sessionEntry,
sessionKey,
sessionScope,
provider,
model,
contextTokens,
resolvedThinkLevel,
resolvedVerboseLevel,
resolvedReasoningLevel,
resolvedElevatedLevel,
resolveDefaultThinkingLevel,
isGroup,
defaultGroupActivation,
} = params;
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /status from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return undefined;
}
const statusAgentId = sessionKey
? resolveSessionAgentId({ sessionKey, config: cfg })
: resolveDefaultAgentId(cfg);
const statusAgentDir = resolveAgentDir(cfg, statusAgentId);
let usageLine: string | null = null;
try {
const usageProvider = resolveUsageProviderId(provider);
if (usageProvider) {
const usageSummary = await loadProviderUsageSummary({
timeoutMs: 3500,
providers: [usageProvider],
agentDir: statusAgentDir,
});
usageLine = formatUsageSummaryLine(usageSummary, { now: Date.now() });
if (
!usageLine &&
(resolvedVerboseLevel === "on" || resolvedElevatedLevel === "on")
) {
const entry = usageSummary.providers[0];
if (entry?.error) {
usageLine = `📊 Usage: ${entry.displayName} (${entry.error})`;
}
}
}
} catch {
usageLine = null;
}
const queueSettings = resolveQueueSettings({
cfg,
provider: command.provider,
sessionEntry,
});
const queueKey = sessionKey ?? sessionEntry?.sessionId;
const queueDepth = queueKey ? getFollowupQueueDepth(queueKey) : 0;
const queueOverrides = Boolean(
sessionEntry?.queueDebounceMs ??
sessionEntry?.queueCap ??
sessionEntry?.queueDrop,
);
const groupActivation = isGroup
? (normalizeGroupActivation(sessionEntry?.groupActivation) ??
defaultGroupActivation())
: undefined;
const agentDefaults = cfg.agents?.defaults ?? {};
const statusText = buildStatusMessage({
config: cfg,
agent: {
...agentDefaults,
model: {
...agentDefaults.model,
primary: `${provider}/${model}`,
},
contextTokens,
thinkingDefault: agentDefaults.thinkingDefault,
verboseDefault: agentDefaults.verboseDefault,
elevatedDefault: agentDefaults.elevatedDefault,
},
sessionEntry,
sessionKey,
sessionScope,
groupActivation,
resolvedThink: resolvedThinkLevel ?? (await resolveDefaultThinkingLevel()),
resolvedVerbose: resolvedVerboseLevel,
resolvedReasoning: resolvedReasoningLevel,
resolvedElevated: resolvedElevatedLevel,
modelAuth: resolveModelAuthLabel(
provider,
cfg,
sessionEntry,
statusAgentDir,
),
usageLine: usageLine ?? undefined,
queue: {
mode: queueSettings.mode,
depth: queueDepth,
debounceMs: queueSettings.debounceMs,
cap: queueSettings.cap,
dropPolicy: queueSettings.dropPolicy,
showDetails: queueOverrides,
},
includeTranscriptUsage: false,
});
return { text: statusText };
}
function formatApiKeySnippet(apiKey: string): string {
const compact = apiKey.replace(/\s+/g, "");
if (!compact) return "unknown";
const edge = compact.length >= 12 ? 6 : 4;
const head = compact.slice(0, edge);
const tail = compact.slice(-edge);
return `${head}${tail}`;
}
function resolveModelAuthLabel(
provider?: string,
cfg?: ClawdbotConfig,
sessionEntry?: SessionEntry,
agentDir?: string,
): string | undefined {
const resolved = provider?.trim();
if (!resolved) return undefined;
const providerKey = normalizeProviderId(resolved);
const store = ensureAuthProfileStore(agentDir, {
allowKeychainPrompt: false,
});
const profileOverride = sessionEntry?.authProfileOverride?.trim();
const order = resolveAuthProfileOrder({
cfg,
store,
provider: providerKey,
preferredProfile: profileOverride,
});
const candidates = [profileOverride, ...order].filter(Boolean) as string[];
for (const profileId of candidates) {
const profile = store.profiles[profileId];
if (!profile || normalizeProviderId(profile.provider) !== providerKey) {
continue;
}
const label = resolveAuthProfileDisplayLabel({ cfg, store, profileId });
if (profile.type === "oauth") {
return `oauth${label ? ` (${label})` : ""}`;
}
if (profile.type === "token") {
const snippet = formatApiKeySnippet(profile.token);
return `token ${snippet}${label ? ` (${label})` : ""}`;
}
const snippet = formatApiKeySnippet(profile.key);
return `api-key ${snippet}${label ? ` (${label})` : ""}`;
}
const envKey = resolveEnvApiKey(providerKey);
if (envKey?.apiKey) {
if (envKey.source.includes("OAUTH_TOKEN")) {
return `oauth (${envKey.source})`;
}
return `api-key ${formatApiKeySnippet(envKey.apiKey)} (${envKey.source})`;
}
const customKey = getCustomProviderApiKey(cfg, providerKey);
if (customKey) {
return `api-key ${formatApiKeySnippet(customKey)} (models.json)`;
}
return "unknown";
}
function extractCompactInstructions(params: {
rawBody?: string;
ctx: MsgContext;
cfg: ClawdbotConfig;
agentId?: string;
isGroup: boolean;
}): string | undefined {
const raw = stripStructuralPrefixes(params.rawBody ?? "");
const stripped = params.isGroup
? stripMentions(raw, params.ctx, params.cfg, params.agentId)
: raw;
const trimmed = stripped.trim();
if (!trimmed) return undefined;
const lowered = trimmed.toLowerCase();
const prefix = lowered.startsWith("/compact") ? "/compact" : null;
if (!prefix) return undefined;
let rest = trimmed.slice(prefix.length).trimStart();
if (rest.startsWith(":")) rest = rest.slice(1).trimStart();
return rest.length ? rest : undefined;
}
export function buildCommandContext(params: {
ctx: MsgContext;
cfg: ClawdbotConfig;
agentId?: string;
sessionKey?: string;
isGroup: boolean;
triggerBodyNormalized: string;
commandAuthorized: boolean;
}): CommandContext {
const { ctx, cfg, agentId, sessionKey, isGroup, triggerBodyNormalized } =
params;
const auth = resolveCommandAuthorization({
ctx,
cfg,
commandAuthorized: params.commandAuthorized,
});
const surface = (ctx.Surface ?? ctx.Provider ?? "").trim().toLowerCase();
const provider = (ctx.Provider ?? surface).trim().toLowerCase();
const abortKey =
sessionKey ?? (auth.from || undefined) ?? (auth.to || undefined);
const rawBodyNormalized = triggerBodyNormalized;
const commandBodyNormalized = normalizeCommandBody(
isGroup
? stripMentions(rawBodyNormalized, ctx, cfg, agentId)
: rawBodyNormalized,
);
return {
surface,
provider,
isWhatsAppProvider: auth.isWhatsAppProvider,
ownerList: auth.ownerList,
isAuthorizedSender: auth.isAuthorizedSender,
senderE164: auth.senderE164,
abortKey,
rawBodyNormalized,
commandBodyNormalized,
from: auth.from,
to: auth.to,
};
}
function resolveAbortTarget(params: {
ctx: MsgContext;
sessionKey?: string;
sessionEntry?: SessionEntry;
sessionStore?: Record<string, SessionEntry>;
}) {
const targetSessionKey =
params.ctx.CommandTargetSessionKey?.trim() || params.sessionKey;
const { entry, key } = resolveSessionEntryForKey(
params.sessionStore,
targetSessionKey,
);
if (entry && key) return { entry, key, sessionId: entry.sessionId };
if (params.sessionEntry && params.sessionKey) {
return {
entry: params.sessionEntry,
key: params.sessionKey,
sessionId: params.sessionEntry.sessionId,
};
}
return { entry: undefined, key: targetSessionKey, sessionId: undefined };
}
export async function handleCommands(params: {
ctx: MsgContext;
cfg: ClawdbotConfig;
command: CommandContext;
agentId?: string;
directives: InlineDirectives;
sessionEntry?: SessionEntry;
sessionStore?: Record<string, SessionEntry>;
sessionKey: string;
storePath?: string;
sessionScope?: SessionScope;
workspaceDir: string;
defaultGroupActivation: () => "always" | "mention";
resolvedThinkLevel?: ThinkLevel;
resolvedVerboseLevel: VerboseLevel;
resolvedReasoningLevel: ReasoningLevel;
resolvedElevatedLevel?: ElevatedLevel;
resolveDefaultThinkingLevel: () => Promise<ThinkLevel | undefined>;
provider: string;
model: string;
contextTokens: number;
isGroup: boolean;
}): Promise<{
reply?: ReplyPayload;
shouldContinue: boolean;
}> {
const {
ctx,
cfg,
command,
directives,
sessionEntry,
sessionStore,
sessionKey,
storePath,
sessionScope,
workspaceDir,
defaultGroupActivation,
resolvedThinkLevel,
resolvedVerboseLevel,
resolvedReasoningLevel,
resolvedElevatedLevel,
resolveDefaultThinkingLevel,
provider,
model,
contextTokens,
isGroup,
} = params;
const resetRequested =
command.commandBodyNormalized === "/reset" ||
command.commandBodyNormalized === "/new";
if (resetRequested && !command.isAuthorizedSender) {
logVerbose(
`Ignoring /reset from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
const activationCommand = parseActivationCommand(
command.commandBodyNormalized,
);
const sendPolicyCommand = parseSendPolicyCommand(
command.commandBodyNormalized,
);
const allowTextCommands = shouldHandleTextCommands({
cfg,
surface: command.surface,
commandSource: ctx.CommandSource,
});
if (allowTextCommands && activationCommand.hasCommand) {
if (!isGroup) {
return {
shouldContinue: false,
reply: { text: "⚙️ Group activation only applies to group chats." },
};
}
const activationOwnerList = command.ownerList;
const activationSenderE164 = command.senderE164
? normalizeE164(command.senderE164)
: "";
const isActivationOwner =
!command.isWhatsAppProvider || activationOwnerList.length === 0
? command.isAuthorizedSender
: Boolean(activationSenderE164) &&
activationOwnerList.includes(activationSenderE164);
if (
!command.isAuthorizedSender ||
(command.isWhatsAppProvider && !isActivationOwner)
) {
logVerbose(
`Ignoring /activation from unauthorized sender in group: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
if (!activationCommand.mode) {
return {
shouldContinue: false,
reply: { text: "⚙️ Usage: /activation mention|always" },
};
}
if (sessionEntry && sessionStore && sessionKey) {
sessionEntry.groupActivation = activationCommand.mode;
sessionEntry.groupActivationNeedsSystemIntro = true;
sessionEntry.updatedAt = Date.now();
sessionStore[sessionKey] = sessionEntry;
if (storePath) {
await saveSessionStore(storePath, sessionStore);
}
}
return {
shouldContinue: false,
reply: { text: `⚙️ Group activation set to ${activationCommand.mode}.` },
};
}
if (allowTextCommands && sendPolicyCommand.hasCommand) {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /send from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
if (!sendPolicyCommand.mode) {
return {
shouldContinue: false,
reply: { text: "⚙️ Usage: /send on|off|inherit" },
};
}
if (sessionEntry && sessionStore && sessionKey) {
if (sendPolicyCommand.mode === "inherit") {
delete sessionEntry.sendPolicy;
} else {
sessionEntry.sendPolicy = sendPolicyCommand.mode;
}
sessionEntry.updatedAt = Date.now();
sessionStore[sessionKey] = sessionEntry;
if (storePath) {
await saveSessionStore(storePath, sessionStore);
}
}
const label =
sendPolicyCommand.mode === "inherit"
? "inherit"
: sendPolicyCommand.mode === "allow"
? "on"
: "off";
return {
shouldContinue: false,
reply: { text: `⚙️ Send policy set to ${label}.` },
};
}
if (allowTextCommands && command.commandBodyNormalized === "/restart") {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /restart from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
if (cfg.commands?.restart !== true) {
return {
shouldContinue: false,
reply: {
text: "⚠️ /restart is disabled. Set commands.restart=true to enable.",
},
};
}
const hasSigusr1Listener = process.listenerCount("SIGUSR1") > 0;
if (hasSigusr1Listener) {
scheduleGatewaySigusr1Restart({ reason: "/restart" });
return {
shouldContinue: false,
reply: {
text: "⚙️ Restarting clawdbot in-process (SIGUSR1); back in a few seconds.",
},
};
}
const restartMethod = triggerClawdbotRestart();
if (!restartMethod.ok) {
const detail = restartMethod.detail
? ` Details: ${restartMethod.detail}`
: "";
return {
shouldContinue: false,
reply: {
text: `⚠️ Restart failed (${restartMethod.method}).${detail}`,
},
};
}
return {
shouldContinue: false,
reply: {
text: `⚙️ Restarting clawdbot via ${restartMethod.method}; give me a few seconds to come back online.`,
},
};
}
const helpRequested = command.commandBodyNormalized === "/help";
if (allowTextCommands && helpRequested) {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /help from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
return { shouldContinue: false, reply: { text: buildHelpMessage() } };
}
const commandsRequested = command.commandBodyNormalized === "/commands";
if (allowTextCommands && commandsRequested) {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /commands from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
return { shouldContinue: false, reply: { text: buildCommandsMessage() } };
}
const statusRequested =
directives.hasStatusDirective ||
command.commandBodyNormalized === "/status";
if (allowTextCommands && statusRequested) {
const reply = await buildStatusReply({
cfg,
command,
sessionEntry,
sessionKey,
sessionScope,
provider,
model,
contextTokens,
resolvedThinkLevel,
resolvedVerboseLevel,
resolvedReasoningLevel,
resolvedElevatedLevel,
resolveDefaultThinkingLevel,
isGroup,
defaultGroupActivation,
});
return { shouldContinue: false, reply };
}
const configCommand = allowTextCommands
? parseConfigCommand(command.commandBodyNormalized)
: null;
if (configCommand) {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /config from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
if (configCommand.action === "error") {
return {
shouldContinue: false,
reply: { text: `⚠️ ${configCommand.message}` },
};
}
const snapshot = await readConfigFileSnapshot();
if (
!snapshot.valid ||
!snapshot.parsed ||
typeof snapshot.parsed !== "object"
) {
return {
shouldContinue: false,
reply: {
text: "⚠️ Config file is invalid; fix it before using /config.",
},
};
}
const parsedBase = structuredClone(
snapshot.parsed as Record<string, unknown>,
);
if (configCommand.action === "show") {
const pathRaw = configCommand.path?.trim();
if (pathRaw) {
const parsedPath = parseConfigPath(pathRaw);
if (!parsedPath.ok || !parsedPath.path) {
return {
shouldContinue: false,
reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` },
};
}
const value = getConfigValueAtPath(parsedBase, parsedPath.path);
const rendered = JSON.stringify(value ?? null, null, 2);
return {
shouldContinue: false,
reply: {
text: `⚙️ Config ${pathRaw}:\n\`\`\`json\n${rendered}\n\`\`\``,
},
};
}
const json = JSON.stringify(parsedBase, null, 2);
return {
shouldContinue: false,
reply: { text: `⚙️ Config (raw):\n\`\`\`json\n${json}\n\`\`\`` },
};
}
if (configCommand.action === "unset") {
const parsedPath = parseConfigPath(configCommand.path);
if (!parsedPath.ok || !parsedPath.path) {
return {
shouldContinue: false,
reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` },
};
}
const removed = unsetConfigValueAtPath(parsedBase, parsedPath.path);
if (!removed) {
return {
shouldContinue: false,
reply: { text: `⚙️ No config value found for ${configCommand.path}.` },
};
}
const validated = validateConfigObject(parsedBase);
if (!validated.ok) {
const issue = validated.issues[0];
return {
shouldContinue: false,
reply: {
text: `⚠️ Config invalid after unset (${issue.path}: ${issue.message}).`,
},
};
}
await writeConfigFile(validated.config);
return {
shouldContinue: false,
reply: { text: `⚙️ Config updated: ${configCommand.path} removed.` },
};
}
if (configCommand.action === "set") {
const parsedPath = parseConfigPath(configCommand.path);
if (!parsedPath.ok || !parsedPath.path) {
return {
shouldContinue: false,
reply: { text: `⚠️ ${parsedPath.error ?? "Invalid path."}` },
};
}
setConfigValueAtPath(parsedBase, parsedPath.path, configCommand.value);
const validated = validateConfigObject(parsedBase);
if (!validated.ok) {
const issue = validated.issues[0];
return {
shouldContinue: false,
reply: {
text: `⚠️ Config invalid after set (${issue.path}: ${issue.message}).`,
},
};
}
await writeConfigFile(validated.config);
const valueLabel =
typeof configCommand.value === "string"
? `"${configCommand.value}"`
: JSON.stringify(configCommand.value);
return {
shouldContinue: false,
reply: {
text: `⚙️ Config updated: ${configCommand.path}=${valueLabel ?? "null"}`,
},
};
}
}
const debugCommand = allowTextCommands
? parseDebugCommand(command.commandBodyNormalized)
: null;
if (debugCommand) {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /debug from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
if (debugCommand.action === "error") {
return {
shouldContinue: false,
reply: { text: `⚠️ ${debugCommand.message}` },
};
}
if (debugCommand.action === "show") {
const overrides = getConfigOverrides();
const hasOverrides = Object.keys(overrides).length > 0;
if (!hasOverrides) {
return {
shouldContinue: false,
reply: { text: "⚙️ Debug overrides: (none)" },
};
}
const effectiveConfig = cfg ?? {};
const json = JSON.stringify(overrides, null, 2);
const effectiveJson = JSON.stringify(effectiveConfig, null, 2);
return {
shouldContinue: false,
reply: {
text: `⚙️ Debug overrides (memory-only):\n\`\`\`json\n${json}\n\`\`\`\n⚙ Effective config (with overrides):\n\`\`\`json\n${effectiveJson}\n\`\`\``,
},
};
}
if (debugCommand.action === "reset") {
resetConfigOverrides();
return {
shouldContinue: false,
reply: { text: "⚙️ Debug overrides cleared; using config on disk." },
};
}
if (debugCommand.action === "unset") {
const result = unsetConfigOverride(debugCommand.path);
if (!result.ok) {
return {
shouldContinue: false,
reply: { text: `⚠️ ${result.error ?? "Invalid path."}` },
};
}
if (!result.removed) {
return {
shouldContinue: false,
reply: {
text: `⚙️ No debug override found for ${debugCommand.path}.`,
},
};
}
return {
shouldContinue: false,
reply: { text: `⚙️ Debug override removed for ${debugCommand.path}.` },
};
}
if (debugCommand.action === "set") {
const result = setConfigOverride(debugCommand.path, debugCommand.value);
if (!result.ok) {
return {
shouldContinue: false,
reply: { text: `⚠️ ${result.error ?? "Invalid override."}` },
};
}
const valueLabel =
typeof debugCommand.value === "string"
? `"${debugCommand.value}"`
: JSON.stringify(debugCommand.value);
return {
shouldContinue: false,
reply: {
text: `⚙️ Debug override set: ${debugCommand.path}=${valueLabel ?? "null"}`,
},
};
}
}
const stopRequested = command.commandBodyNormalized === "/stop";
if (allowTextCommands && stopRequested) {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /stop from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
const abortTarget = resolveAbortTarget({
ctx,
sessionKey,
sessionEntry,
sessionStore,
});
if (abortTarget.sessionId) {
abortEmbeddedPiRun(abortTarget.sessionId);
}
if (abortTarget.entry && sessionStore && abortTarget.key) {
abortTarget.entry.abortedLastRun = true;
abortTarget.entry.updatedAt = Date.now();
sessionStore[abortTarget.key] = abortTarget.entry;
if (storePath) {
await saveSessionStore(storePath, sessionStore);
}
} else if (command.abortKey) {
setAbortMemory(command.abortKey, true);
}
return { shouldContinue: false, reply: { text: "⚙️ Agent was aborted." } };
}
const compactRequested =
command.commandBodyNormalized === "/compact" ||
command.commandBodyNormalized.startsWith("/compact ");
if (compactRequested) {
if (!command.isAuthorizedSender) {
logVerbose(
`Ignoring /compact from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
);
return { shouldContinue: false };
}
if (!sessionEntry?.sessionId) {
return {
shouldContinue: false,
reply: { text: "⚙️ Compaction unavailable (missing session id)." },
};
}
const sessionId = sessionEntry.sessionId;
if (isEmbeddedPiRunActive(sessionId)) {
abortEmbeddedPiRun(sessionId);
await waitForEmbeddedPiRunEnd(sessionId, 15_000);
}
const customInstructions = extractCompactInstructions({
rawBody: ctx.Body,
ctx,
cfg,
agentId: params.agentId,
isGroup,
});
const result = await compactEmbeddedPiSession({
sessionId,
sessionKey,
messageProvider: command.provider,
sessionFile: resolveSessionFilePath(sessionId, sessionEntry),
workspaceDir,
config: cfg,
skillsSnapshot: sessionEntry.skillsSnapshot,
provider,
model,
thinkLevel: resolvedThinkLevel ?? (await resolveDefaultThinkingLevel()),
bashElevated: {
enabled: false,
allowed: false,
defaultLevel: "off",
},
customInstructions,
ownerNumbers:
command.ownerList.length > 0 ? command.ownerList : undefined,
});
const totalTokens =
sessionEntry.totalTokens ??
(sessionEntry.inputTokens ?? 0) + (sessionEntry.outputTokens ?? 0);
const contextSummary = formatContextUsageShort(
totalTokens > 0 ? totalTokens : null,
contextTokens ?? sessionEntry.contextTokens ?? null,
);
const compactLabel = result.ok
? result.compacted
? result.result?.tokensBefore
? `Compacted (${formatTokenCount(result.result.tokensBefore)} before)`
: "Compacted"
: "Compaction skipped"
: "Compaction failed";
if (result.ok && result.compacted) {
await incrementCompactionCount({
sessionEntry,
sessionStore,
sessionKey,
storePath,
});
}
const reason = result.reason?.trim();
const line = reason
? `${compactLabel}: ${reason}${contextSummary}`
: `${compactLabel}${contextSummary}`;
enqueueSystemEvent(line, { sessionKey });
return { shouldContinue: false, reply: { text: `⚙️ ${line}` } };
}
const abortRequested = isAbortTrigger(command.rawBodyNormalized);
if (allowTextCommands && abortRequested) {
const abortTarget = resolveAbortTarget({
ctx,
sessionKey,
sessionEntry,
sessionStore,
});
if (abortTarget.sessionId) {
abortEmbeddedPiRun(abortTarget.sessionId);
}
if (abortTarget.entry && sessionStore && abortTarget.key) {
abortTarget.entry.abortedLastRun = true;
abortTarget.entry.updatedAt = Date.now();
sessionStore[abortTarget.key] = abortTarget.entry;
if (storePath) {
await saveSessionStore(storePath, sessionStore);
}
} else if (command.abortKey) {
setAbortMemory(command.abortKey, true);
}
return { shouldContinue: false, reply: { text: "⚙️ Agent was aborted." } };
}
const sendPolicy = resolveSendPolicy({
cfg,
entry: sessionEntry,
sessionKey,
provider: sessionEntry?.provider ?? command.provider,
chatType: sessionEntry?.chatType,
});
if (sendPolicy === "deny") {
logVerbose(`Send blocked by policy for session ${sessionKey ?? "unknown"}`);
return { shouldContinue: false };
}
return { shouldContinue: true };
}