openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
118 lines (117 loc) • 5.95 kB
JavaScript
import { s as normalizeOptionalLowercaseString } from "./string-coerce-mnp54Vah.js";
import { j as resolveTimerTimeoutMs, n as MAX_TIMER_TIMEOUT_MS } from "./number-coercion-CJQ8TR--.js";
import { a as shouldLogVerbose, r as logVerbose } from "./globals-GTrXU4s9.js";
import { t as normalizeChatType } from "./chat-type-CxEvM45e.js";
import { i as DEFAULT_MAX_CHARS_BY_CAPABILITY, n as DEFAULT_MAX_BYTES, o as DEFAULT_PROMPT } from "./defaults.constants-A49pIMjc.js";
import { r as resolveEffectiveMediaEntryCapabilities } from "./entry-capabilities-BK3bTOCE.js";
//#region src/media-understanding/scope.ts
function normalizeDecision(value) {
const normalized = normalizeOptionalLowercaseString(value);
if (normalized === "allow") return "allow";
if (normalized === "deny") return "deny";
}
/** Normalizes channel/direct chat type aliases used by media-understanding scope rules. */
function normalizeMediaUnderstandingChatType(raw) {
return normalizeChatType(raw ?? void 0);
}
/** Evaluates ordered media-understanding scope rules against channel, chat type, and session key. */
function resolveMediaUnderstandingScope(params) {
const scope = params.scope;
if (!scope) return "allow";
const channel = normalizeOptionalLowercaseString(params.channel);
const chatType = normalizeMediaUnderstandingChatType(params.chatType);
const sessionKey = normalizeOptionalLowercaseString(params.sessionKey) ?? "";
for (const rule of scope.rules ?? []) {
if (!rule) continue;
const action = normalizeDecision(rule.action) ?? "allow";
const match = rule.match ?? {};
const matchChannel = normalizeOptionalLowercaseString(match.channel);
const matchChatType = normalizeMediaUnderstandingChatType(match.chatType);
const matchPrefix = normalizeOptionalLowercaseString(match.keyPrefix);
if (matchChannel && matchChannel !== channel) continue;
if (matchChatType && matchChatType !== chatType) continue;
if (matchPrefix && !sessionKey.startsWith(matchPrefix)) continue;
return action;
}
return normalizeDecision(scope.default) ?? "allow";
}
//#endregion
//#region src/media-understanding/resolve.ts
/** Default per-provider media-understanding runtime timeout in milliseconds. */
const DEFAULT_MEDIA_RUNTIME_TIMEOUT_MS = 3e4;
const MIN_MEDIA_TIMEOUT_MS = 1e3;
/** Converts configured timeout seconds into a timer-safe millisecond deadline. */
function resolveTimeoutMs(seconds, fallbackSeconds) {
const value = typeof seconds === "number" && Number.isFinite(seconds) ? seconds : fallbackSeconds;
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return MIN_MEDIA_TIMEOUT_MS;
const timeoutMs = Math.floor(value * 1e3);
return resolveTimerTimeoutMs(Number.isFinite(timeoutMs) ? timeoutMs : MAX_TIMER_TIMEOUT_MS, MIN_MEDIA_TIMEOUT_MS, MIN_MEDIA_TIMEOUT_MS);
}
/** Clamps an already-millisecond runtime timeout to the shared timer bounds. */
function resolveMediaRuntimeTimeoutMs(timeoutMs) {
return resolveTimerTimeoutMs(timeoutMs, DEFAULT_MEDIA_RUNTIME_TIMEOUT_MS);
}
/** Resolves the provider prompt and appends length guidance for non-audio outputs. */
function resolvePrompt(capability, prompt, maxChars) {
const base = prompt?.trim() || DEFAULT_PROMPT[capability];
if (!maxChars || capability === "audio") return base;
return `${base} Respond in at most ${maxChars} characters.`;
}
/** Resolves the effective max response characters for a model entry and capability. */
function resolveMaxChars(params) {
const { capability, entry, cfg } = params;
const configured = entry.maxChars ?? params.config?.maxChars ?? cfg.tools?.media?.[capability]?.maxChars;
if (typeof configured === "number") return configured;
return DEFAULT_MAX_CHARS_BY_CAPABILITY[capability];
}
/** Resolves the effective input byte cap for a model entry and capability. */
function resolveMaxBytes(params) {
const configured = params.entry.maxBytes ?? params.config?.maxBytes ?? params.cfg.tools?.media?.[params.capability]?.maxBytes;
if (typeof configured === "number") return configured;
return DEFAULT_MAX_BYTES[params.capability];
}
/** Maps the message context to an allow/deny decision for configured media scope rules. */
function resolveScopeDecision(params) {
return resolveMediaUnderstandingScope({
scope: params.scope,
sessionKey: params.ctx.SessionKey,
channel: params.ctx.Surface ?? params.ctx.Provider,
chatType: normalizeMediaUnderstandingChatType(params.ctx.ChatType)
});
}
/** Resolves configured model entries that can handle the requested media capability. */
function resolveModelEntries(params) {
const { cfg, capability, config } = params;
const sharedModels = cfg.tools?.media?.models ?? [];
const entries = [...(config?.models ?? []).map((entry) => ({
entry,
source: "capability"
})), ...sharedModels.map((entry) => ({
entry,
source: "shared"
}))];
if (entries.length === 0) return [];
return entries.filter(({ entry, source }) => {
const caps = resolveEffectiveMediaEntryCapabilities({
entry,
source,
providerRegistry: params.providerRegistry
});
if (!caps || caps.length === 0) {
if (source === "shared") {
if (shouldLogVerbose()) logVerbose(`Skipping shared media model without capabilities: ${entry.provider ?? entry.command ?? "unknown"}`);
return false;
}
return true;
}
return caps.includes(capability);
}).map(({ entry }) => entry);
}
/** Resolves the bounded media-understanding task concurrency from config. */
function resolveConcurrency(cfg) {
const configured = cfg.tools?.media?.concurrency;
if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) return Math.floor(configured);
return 2;
}
//#endregion
export { resolveModelEntries as a, resolveTimeoutMs as c, resolveMediaRuntimeTimeoutMs as i, normalizeMediaUnderstandingChatType as l, resolveMaxBytes as n, resolvePrompt as o, resolveMaxChars as r, resolveScopeDecision as s, resolveConcurrency as t, resolveMediaUnderstandingScope as u };