Files
clawdbot/src/auto-reply/reply/agent-runner-helpers.ts
2026-01-17 05:33:39 +00:00

80 lines
2.5 KiB
TypeScript

import { loadSessionStore } from "../../config/sessions.js";
import { isAudioFileName } from "../../media/mime.js";
import { normalizeVerboseLevel, type VerboseLevel } from "../thinking.js";
import type { ReplyPayload } from "../types.js";
import { scheduleFollowupDrain } from "./queue.js";
import type { TypingSignaler } from "./typing-mode.js";
const hasAudioMedia = (urls?: string[]): boolean =>
Boolean(urls?.some((url) => isAudioFileName(url)));
export const isAudioPayload = (payload: ReplyPayload): boolean =>
hasAudioMedia(payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : undefined));
export const createShouldEmitToolResult = (params: {
sessionKey?: string;
storePath?: string;
resolvedVerboseLevel: VerboseLevel;
}): (() => boolean) => {
return () => {
if (!params.sessionKey || !params.storePath) {
return params.resolvedVerboseLevel !== "off";
}
try {
const store = loadSessionStore(params.storePath);
const entry = store[params.sessionKey];
const current = normalizeVerboseLevel(entry?.verboseLevel);
if (current) return current !== "off";
} catch {
// ignore store read failures
}
return params.resolvedVerboseLevel !== "off";
};
};
export const createShouldEmitToolOutput = (params: {
sessionKey?: string;
storePath?: string;
resolvedVerboseLevel: VerboseLevel;
}): (() => boolean) => {
return () => {
if (!params.sessionKey || !params.storePath) {
return params.resolvedVerboseLevel === "full";
}
try {
const store = loadSessionStore(params.storePath);
const entry = store[params.sessionKey];
const current = normalizeVerboseLevel(entry?.verboseLevel);
if (current) return current === "full";
} catch {
// ignore store read failures
}
return params.resolvedVerboseLevel === "full";
};
};
export const finalizeWithFollowup = <T>(
value: T,
queueKey: string,
runFollowupTurn: Parameters<typeof scheduleFollowupDrain>[1],
): T => {
scheduleFollowupDrain(queueKey, runFollowupTurn);
return value;
};
export const signalTypingIfNeeded = async (
payloads: ReplyPayload[],
typingSignals: TypingSignaler,
): Promise<void> => {
const shouldSignalTyping = payloads.some((payload) => {
const trimmed = payload.text?.trim();
if (trimmed) return true;
if (payload.mediaUrl) return true;
if (payload.mediaUrls && payload.mediaUrls.length > 0) return true;
return false;
});
if (shouldSignalTyping) {
await typingSignals.signalRunStart();
}
};