@gguf/claw
Version:
WhatsApp gateway CLI (Baileys web) with Pi RPC agent
1,098 lines (1,071 loc) • 2.26 MB
JavaScript
import { A as parseImageSizeError, B as normalizeElevatedLevel, C as isFailoverAssistantError, D as isRawApiErrorPayload, E as isRateLimitAssistantError, F as sanitizeGoogleTurnOrdering, G as resolveResponseUsageMode, H as normalizeThinkLevel, I as formatThinkingLevels, K as supportsXHighThinking, L as formatXHighModelHint, M as buildBootstrapContextFiles, N as ensureSessionHeader, O as isTimeoutErrorMessage, P as resolveBootstrapMaxChars, S as isContextOverflowError, T as isLikelyContextOverflowError, U as normalizeUsageDisplay, V as normalizeReasoningLevel, W as normalizeVerboseLevel, _ as getApiErrorPayloadFingerprint, a as isMessagingToolDuplicateNormalized, b as isCloudCodeAssistFormatError, c as sanitizeImageBlocks, d as isAntigravityClaude, f as isGoogleModelApi, g as formatRawAssistantErrorForUi, h as formatAssistantErrorText, j as sanitizeUserFacingText, k as parseImageDimensionError, l as sanitizeToolResultImages, m as classifyFailoverReason, n as validateGeminiTurns, o as normalizeTextForComparison, p as BILLING_ERROR_USER_MESSAGE, r as pickFallbackThinkingLevel, s as sanitizeSessionMessagesImages, t as validateAnthropicTurns, u as downgradeOpenAIReasoningBlocks, v as isAuthAssistantError, w as isFailoverErrorMessage, x as isCompactionFailureError, y as isBillingAssistantError } from "./pi-embedded-helpers-BB4uACeq.js";
import { g as resolveStateDir, r as STATE_DIR, t as CONFIG_PATH } from "./paths-scjhy7N2.js";
import { _ as parseAgentSessionKey, a as buildAgentPeerSessionKey, c as normalizeAgentId, d as resolveThreadSessionKeys, f as sanitizeAgentId, g as isSubagentSessionKey, h as isAcpSessionKey, i as buildAgentMainSessionKey, l as normalizeMainKey, n as DEFAULT_AGENT_ID, o as buildGroupHistoryKey, r as DEFAULT_MAIN_KEY, s as normalizeAccountId$3, t as DEFAULT_ACCOUNT_ID$1, u as resolveAgentIdFromSessionKey, v as resolveThreadParentSessionKey } from "./session-key-Dm2EOhrH.js";
import { A as logVerbose, D as info, E as danger, F as warn, I as colorize, L as isRich, M as setVerbose, N as shouldLogVerbose, P as success, R as theme, T as setActivePluginRegistry, U as normalizeLogLevel, b as normalizeAnyChannelId, c as defaultRuntime, m as CHAT_CHANNEL_ORDER, t as createSubsystemLogger, w as requireActivePluginRegistry, x as normalizeChannelId, z as getChildLogger } from "./subsystem-CAq3uyo7.js";
import { _ as shortenHomePath, b as toWhatsappJid, d as normalizeE164, g as shortenHomeInString, h as resolveUserPath, l as isSelfChatMode, m as resolveJidToE164, r as clampInt, t as CONFIG_DIR, u as jidToE164, v as sleep, x as truncateUtf16Safe, y as sliceUtf16Safe } from "./utils-CKSrBNwq.js";
import { a as logDebug, c as logWarn, i as spawnWithFallback, n as runExec, o as logError, r as formatSpawnError, s as logInfo, t as runCommandWithTimeout } from "./exec-HEWTMJ7j.js";
import { t as resolveOpenClawPackageRoot } from "./openclaw-root-Cvotktkd.js";
import { C as loadWorkspaceBootstrapFiles, S as filterBootstrapFilesForSession, c as resolveDefaultAgentId, f as DEFAULT_AGENT_WORKSPACE_DIR, i as resolveAgentModelFallbacksOverride, l as resolveSessionAgentId, n as resolveAgentConfig, o as resolveAgentSkillsFilter, p as DEFAULT_BOOTSTRAP_FILENAME, r as resolveAgentDir, s as resolveAgentWorkspaceDir, t as listAgentIds, u as resolveSessionAgentIds, x as ensureAgentWorkspace } from "./agent-scope-CMs5Y7l-.js";
import { $ as resolveApiKeyForProfile, I as resolveEnvApiKey, J as resolveAuthProfileOrder, L as resolveModelAuthMode, M as getCustomProviderApiKey, N as requireApiKey, P as resolveApiKeyForProvider, V as resolveShellEnvFallbackTimeoutMs, X as markAuthProfileFailure, Y as isProfileInCooldown, Z as markAuthProfileUsed, a as isCliProvider, at as listProfilesForProvider, bt as DEFAULT_PROVIDER, d as resolveConfiguredModelRef, f as resolveDefaultModelForAgent, h as resolveThinkingDefault, ht as resolveAuthProfileDisplayLabel, j as getApiKeyForModel, lt as ensureAuthProfileStore, m as resolveModelRefFromString, mt as resolveOpenClawAgentDir, n as buildConfiguredAllowlistKeys, o as modelKey, ot as markAuthProfileGood, pt as resolveAuthStorePathForDisplay, r as buildModelAliasIndex, s as normalizeProviderId, t as buildAllowedModelSet, v as normalizeGoogleModelId, vt as DEFAULT_CONTEXT_TOKENS, yt as DEFAULT_MODEL, z as getShellPathFromLoginShell } from "./model-selection-DMUrNhQP.js";
import { a as saveJsonFile, i as loadJsonFile } from "./github-copilot-token-pGSmVaW-.js";
import { t as formatCliCommand } from "./command-format-ChfKqObn.js";
import { t as parseBooleanValue$1 } from "./boolean-BgXe2hyu.js";
import { t as isTruthyEnvValue } from "./env-0_mKbEWW.js";
import { C as setConfigValueAtPath, S as parseConfigPath, _ as getConfigOverrides, b as unsetConfigOverride, c as writeConfigFile, d as TELEGRAM_COMMAND_NAME_PATTERN, f as normalizeTelegramCommandName, g as validateJsonSchemaValue, h as parseDurationMs, i as loadConfig, j as VERSION, k as resolveAgentMaxConcurrent, l as validateConfigObjectWithPlugins, m as isSafeExecutableValue, o as readConfigFileSnapshot, p as resolveTelegramCustomCommands, s as resolveConfigSnapshotHash, v as resetConfigOverrides, w as unsetConfigValueAtPath, x as getConfigValueAtPath, y as setConfigOverride } from "./config-CAuZ-EkU.js";
import { c as resolveEnableState, l as resolveMemorySlotDecision, n as discoverOpenClawPlugins, s as normalizePluginsConfig, t as loadPluginManifestRegistry } from "./manifest-registry-DHaa1SJb.js";
import { _ as listEnabledDiscordAccounts, a as normalizeWhatsAppTarget, b as normalizeChatType, c as resolveTelegramAccount, d as listBindings, g as resolveSlackBotToken, h as resolveSlackAppToken, i as isWhatsAppGroupJid, l as resolveTelegramToken, n as listChannelPlugins, o as listEnabledTelegramAccounts, p as resolveSlackAccount, r as normalizeChannelId$1, s as listTelegramAccountIds, t as getChannelPlugin, v as resolveDiscordAccount, y as normalizeDiscordToken } from "./plugins-BYIWo0Cp.js";
import { A as resolveSessionResetPolicy, C as normalizeDeliveryContext, D as resolveSessionKey$1, H as listChannelDocks, J as resolveIMessageAccount, K as listEnabledSignalAccounts, L as resolveMainSessionKey, M as resolveThreadFlag, N as DEFAULT_RESET_TRIGGERS, O as evaluateSessionFreshness, P as canonicalizeMainSessionAlias, S as mergeDeliveryContext, U as resolveChannelGroupPolicy, V as getChannelDock, W as resolveChannelGroupRequireMention, X as resolveGroupSessionKey, Y as buildGroupDisplayName, Z as resolveSandboxConfigForAgent, _ as updateSessionStoreEntry, a as ensureSandboxWorkspaceForSession, at as normalizeToolName, b as deliveryContextFromSession, c as resolveSandboxRuntimeStatus, d as loadSessionStore, dt as resolveConversationLabel, et as applyOwnerOnlyToolPolicy, f as readSessionUpdatedAt, g as updateSessionStore, h as updateLastRoute, j as resolveSessionResetType, k as resolveChannelResetConfig, l as appendAssistantMessageToSessionTranscript, nt as collectExplicitAllowlist, o as resolveSandboxContext, ot as resolveToolProfilePolicy, p as recordSessionMetaFromInbound, q as resolveSignalAccount, rt as expandPolicyWithPluginGroups, st as stripPluginOnlyAllowlist, tt as buildPluginToolGroups, v as isCacheEnabled, w as normalizeSessionDeliveryFields, x as deliveryContextKey, y as resolveCacheTtlMs$1, z as deriveSessionMetaPatch } from "./sandbox-CV8VwPij.js";
import { _ as ensureOpenClawModelsJson, a as decodeDataUrl, c as extractAssistantThinking, d as formatReasoningMessage, f as inferToolMetaFromArgs, g as stripThinkingTagsFromText, h as stripMinimaxToolCallXml, i as coerceImageModelConfig, l as extractThinkingFromTaggedStream, m as stripDowngradedToolCallText, o as resolveProviderVisionModelFromConfig, p as promoteThinkingTagsToBlocks, r as coerceImageAssistantText, s as extractAssistantText$1, t as describeImageWithModel, u as extractThinkingFromTaggedText, v as minimaxUnderstandImage } from "./image-Ca_PtqY7.js";
import { n as discoverModels, t as discoverAuthStorage } from "./pi-model-discovery-CV2V1HHz.js";
import { E as formatUncaughtError, T as formatErrorMessage, k as DEFAULT_AI_SNAPSHOT_MAX_CHARS, w as extractErrorCode } from "./chrome-BNSd7Bie.js";
import { a as resolveSkillsPromptForRun, i as loadWorkspaceSkillEntries, l as applySkillEnvOverrides, n as buildWorkspaceSkillCommandSpecs, r as buildWorkspaceSkillSnapshot, s as resolvePluginSkillDirs, u as applySkillEnvOverridesFromSnapshot } from "./skills-D5JDj3TR.js";
import { c as saveMediaBuffer, d as getFileExtension, f as imageMimeFromFormat, g as MAX_IMAGE_BYTES, h as kindFromMime, l as detectMime, m as isGifMedia, o as resizeToJpeg, p as isAudioFileName, r as getImageMetadata, s as getMediaDir, u as extensionForMime, v as mediaKindFromMime, y as SsrFBlockedError } from "./routes-DchZU3EK.js";
import { i as resolveBrowserConfig } from "./server-context-vChIAqjH.js";
import { a as isInternalMessageChannel, c as listDeliverableMessageChannels, d as resolveMessageChannel, h as GATEWAY_CLIENT_NAMES, l as normalizeMessageChannel, m as GATEWAY_CLIENT_MODES, n as isDeliverableMessageChannel, o as isMarkdownCapableMessageChannel, p as GATEWAY_CLIENT_IDS, t as INTERNAL_MESSAGE_CHANNEL, u as resolveGatewayMessageChannel } from "./message-channel-Bpfe5l5f.js";
import { a as logoutWeb, d as webAuthExists, i as logWebSelfId, n as resolveWhatsAppAccount, r as getWebAuthAgeMs, s as readWebSelfId } from "./accounts-BgZmhIm6.js";
import { a as resolveSessionTranscriptsDirForAgent, n as resolveSessionFilePath, o as resolveStorePath, r as resolveSessionTranscriptPath } from "./paths-Bb0nwPeu.js";
import { t as emitSessionTranscriptUpdate } from "./transcript-events-ChU6IQwp.js";
import { n as redactSensitiveText } from "./redact-DJCFY628.js";
import { n as resolveToolDisplay } from "./tool-display-BxZG0o1b.js";
import { A as markdownToIRWithMeta, B as resolveTextChunkLimit, C as signalCheck, D as wrapFetchWithAbortSignal, E as resolveFetch, F as chunkMarkdownText, G as SILENT_REPLY_TOKEN, H as isSafeFenceBreak, I as chunkMarkdownTextWithMode, J as fetchRemoteMedia, K as isSilentReplyText, L as chunkText, M as loadWebMediaRaw, N as resolveMarkdownTableMode, O as chunkMarkdownIR, P as chunkByNewline, R as chunkTextWithMode, S as sendTypingSignal, T as streamSignalEvents, U as parseFenceSpans, V as findFenceSpanAt, W as HEARTBEAT_TOKEN, Y as fetchWithSsrFGuard, _ as parseReplyDirectives, b as sendMessageSignal, c as applyReplyThreading, d as shouldSuppressMessagingToolReplies, f as createReplyToModeFilterForChannel, g as normalizeTargetForProvider, h as normalizeChannelTargetInput, j as loadWebMedia, k as markdownToIR, l as filterMessagingToolDuplicates, m as buildTargetResolverSignature, o as normalizeReplyPayloadsForDelivery, p as resolveReplyToMode, q as MediaFetchError, s as applyReplyTagsToPayload, t as deliverOutboundPayloads, u as isRenderablePayload, v as splitMediaFromOutput, w as signalRpcRequest, x as sendReadReceiptSignal, y as parseInlineDirectives$1, z as resolveChunkMode } from "./deliver-C3bnXkg5.js";
import { i as getMachineDisplayName, n as isWSL, t as createBrowserRouteDispatcher } from "./dispatcher-6oI-H42S.js";
import { i as resolveMemorySearchConfig, n as resolveRetryConfig, r as retryAsync } from "./manager-LpytrxUw.js";
import { c as listMemoryFiles, l as normalizeExtraMemoryPaths } from "./sqlite-BKl1HJFe.js";
import { C as shouldHandleTextCommands, S as serializeCommandArgs, _ as listNativeCommandSpecsForConfig, b as resolveCommandArgChoices, f as buildCommandTextFromArgs, g as listNativeCommandSpecs, h as listChatCommandsForConfig, m as listChatCommands, o as extractTextFromMessage, p as findCommandByNativeName, t as buildChannelSummary, v as normalizeCommandBody, x as resolveCommandArgMenu, y as parseCommandArgs } from "./channel-summary-DUiKDBLv.js";
import { Et as SESSION_LABEL_MAX_LENGTH, t as GatewayClient } from "./client-BYVbRnuQ.js";
import { t as pickPrimaryTailnetIPv4 } from "./tailnet-DLDGNuH2.js";
import { i as randomIdempotencyKey, n as callGateway } from "./call-BTbA5OB4.js";
import { a as formatError$1, i as createWaSocket, n as startWebLoginWithQr, o as getStatusCode$1, r as waitForWebLogin, s as waitForWaConnection } from "./login-qr-BIlr0vwe.js";
import { a as removeChannelAllowFromStoreEntry, c as listPairingChannels, i as readChannelAllowFromStore, o as upsertChannelPairingRequest, t as addChannelAllowFromStoreEntry } from "./pairing-store-DFq7WtOv.js";
import { t as formatDocsLink } from "./links-B5pRdmo1.js";
import { i as withManager, t as formatErrorMessage$1 } from "./cli-utils-BkRQdAoC.js";
import { n as withProgress, r as withProgressTotals } from "./progress-xpLtQsNY.js";
import { a as resolveSubagentToolPolicy, c as resolveNativeSkillsEnabled, i as resolveGroupToolPolicy, n as isToolAllowedByPolicies, o as isNativeCommandsExplicitlyDisabled, r as resolveEffectiveToolPolicy, s as resolveNativeCommandsEnabled, t as filterToolsByPolicy } from "./pi-tools.policy-BQ8N5y8a.js";
import { r as stylePromptTitle } from "./prompt-style-vzh0MGHs.js";
import { t as resolvePairingIdLabel } from "./pairing-labels-CtqLxbG6.js";
import { c as derivePromptTokens, l as hasNonzeroUsage, n as loadCostUsageSummary, o as extractToolCallNames, r as loadSessionCostSummary, s as hasToolCall, u as normalizeUsage } from "./session-cost-usage-CBP4Hv9D.js";
import { i as resolveModelCostConfig, n as formatTokenCount$2, r as formatUsd$1, t as estimateUsageCost } from "./usage-format-DvowRSs-.js";
import { a as evaluateShellAllowlist, d as requiresExecApproval, f as resolveExecApprovals, h as resolveSafeBins, o as maxAsk, p as resolveExecApprovalsFromFile, s as minSecurity, t as addAllowlistEntry, u as recordAllowlistUse } from "./exec-approvals-DZixgolZ.js";
import { a as canvasSnapshotTempPath, c as parseCameraClipPayload, d as buildNodeShellCommand, i as parseEnvPairs, l as parseCameraSnapPayload, n as screenRecordTempPath, o as parseCanvasSnapshotPayload, r as writeScreenRecordToFile, s as cameraTempPath, t as parseScreenRecordPayload, u as writeBase64ToFile } from "./nodes-screen-DT5HvhJV.js";
import { n as createBrowserControlContext, r as startBrowserControlServiceFromConfig } from "./control-service-CS61Road.js";
import { t as parseAbsoluteTimeMs } from "./parse-BZz5lHzQ.js";
import { d as resolveGatewaySystemdServiceName, l as resolveGatewayLaunchAgentLabel } from "./constants-HPrOsATF.js";
import { n as resolveMessageChannelSelection, t as listConfiguredMessageChannels } from "./channel-selection-CJWYmCLf.js";
import { t as parseTimeoutMs } from "./parse-timeout-Du-wHHNi.js";
import { createRequire } from "node:module";
import process$1 from "node:process";
import { fileURLToPath } from "node:url";
import os, { homedir, tmpdir } from "node:os";
import path from "node:path";
import fs, { constants, existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
import fs$1 from "node:fs/promises";
import { execSync, spawn, spawnSync } from "node:child_process";
import { inspect } from "node:util";
import crypto, { randomUUID } from "node:crypto";
import { complete, completeSimple, streamSimple } from "@mariozechner/pi-ai";
import { CURRENT_SESSION_VERSION, SessionManager, SettingsManager, codingTools, createAgentSession, createEditTool, createReadTool, createWriteTool, estimateTokens, readTool } from "@mariozechner/pi-coding-agent";
import { createServer } from "node:http";
import { ProxyAgent, fetch as fetch$1 } from "undici";
import { Buffer as Buffer$1 } from "node:buffer";
import * as net$1 from "node:net";
import { EdgeTTS } from "node-edge-tts";
import { createJiti } from "jiti";
import { Type } from "@sinclair/typebox";
import chokidar from "chokidar";
import { WebClient } from "@slack/web-api";
import { ApplicationCommandOptionType, ButtonStyle, ChannelType, PermissionFlagsBits, Routes } from "discord-api-types/v10";
import { Button, ChannelType as ChannelType$1, Client, Command, MessageCreateListener, MessageReactionAddListener, MessageReactionRemoveListener, MessageType, PresenceUpdateListener, RateLimitError, RequestClient, Row } from "@buape/carbon";
import { PollLayoutType } from "discord-api-types/payloads/v10";
import { API_CONSTANTS, Bot, GrammyError, HttpError, InputFile, webhookCallback } from "grammy";
import { setTimeout as setTimeout$1 } from "node:timers/promises";
import { DisconnectReason, downloadMediaMessage, extractMessageContent, getContentType, isJidGroup, normalizeMessageContent } from "@whiskeysockets/baileys";
import { cancel, isCancel } from "@clack/prompts";
import { GatewayIntents, GatewayPlugin } from "@buape/carbon/gateway";
import { createInterface } from "node:readline";
import { messagingApi } from "@line/bot-sdk";
import SlackBolt from "@slack/bolt";
import { run, sequentialize } from "@grammyjs/runner";
import { apiThrottler } from "@grammyjs/transformer-throttler";
import { EventEmitter } from "node:events";
//#region src/auto-reply/reply/exec/directive.ts
function normalizeExecHost$1(value) {
const normalized = value?.trim().toLowerCase();
if (normalized === "sandbox" || normalized === "gateway" || normalized === "node") return normalized;
}
function normalizeExecSecurity$1(value) {
const normalized = value?.trim().toLowerCase();
if (normalized === "deny" || normalized === "allowlist" || normalized === "full") return normalized;
}
function normalizeExecAsk$1(value) {
const normalized = value?.trim().toLowerCase();
if (normalized === "off" || normalized === "on-miss" || normalized === "always") return normalized;
}
function parseExecDirectiveArgs(raw) {
let i = 0;
const len = raw.length;
while (i < len && /\s/.test(raw[i])) i += 1;
if (raw[i] === ":") {
i += 1;
while (i < len && /\s/.test(raw[i])) i += 1;
}
let consumed = i;
let execHost;
let execSecurity;
let execAsk;
let execNode;
let rawExecHost;
let rawExecSecurity;
let rawExecAsk;
let rawExecNode;
let hasExecOptions = false;
let invalidHost = false;
let invalidSecurity = false;
let invalidAsk = false;
let invalidNode = false;
const takeToken = () => {
if (i >= len) return null;
const start = i;
while (i < len && !/\s/.test(raw[i])) i += 1;
if (start === i) return null;
const token = raw.slice(start, i);
while (i < len && /\s/.test(raw[i])) i += 1;
return token;
};
const splitToken = (token) => {
const eq = token.indexOf("=");
const colon = token.indexOf(":");
const idx = eq === -1 ? colon : colon === -1 ? eq : Math.min(eq, colon);
if (idx === -1) return null;
const key = token.slice(0, idx).trim().toLowerCase();
const value = token.slice(idx + 1).trim();
if (!key) return null;
return {
key,
value
};
};
while (i < len) {
const token = takeToken();
if (!token) break;
const parsed = splitToken(token);
if (!parsed) break;
const { key, value } = parsed;
if (key === "host") {
rawExecHost = value;
execHost = normalizeExecHost$1(value);
if (!execHost) invalidHost = true;
hasExecOptions = true;
consumed = i;
continue;
}
if (key === "security") {
rawExecSecurity = value;
execSecurity = normalizeExecSecurity$1(value);
if (!execSecurity) invalidSecurity = true;
hasExecOptions = true;
consumed = i;
continue;
}
if (key === "ask") {
rawExecAsk = value;
execAsk = normalizeExecAsk$1(value);
if (!execAsk) invalidAsk = true;
hasExecOptions = true;
consumed = i;
continue;
}
if (key === "node") {
rawExecNode = value;
const trimmed = value.trim();
if (!trimmed) invalidNode = true;
else execNode = trimmed;
hasExecOptions = true;
consumed = i;
continue;
}
break;
}
return {
consumed,
execHost,
execSecurity,
execAsk,
execNode,
rawExecHost,
rawExecSecurity,
rawExecAsk,
rawExecNode,
hasExecOptions,
invalidHost,
invalidSecurity,
invalidAsk,
invalidNode
};
}
function extractExecDirective(body) {
if (!body) return {
cleaned: "",
hasDirective: false,
hasExecOptions: false,
invalidHost: false,
invalidSecurity: false,
invalidAsk: false,
invalidNode: false
};
const match = /(?:^|\s)\/exec(?=$|\s|:)/i.exec(body);
if (!match) return {
cleaned: body.trim(),
hasDirective: false,
hasExecOptions: false,
invalidHost: false,
invalidSecurity: false,
invalidAsk: false,
invalidNode: false
};
const start = match.index + match[0].indexOf("/exec");
const argsStart = start + 5;
const parsed = parseExecDirectiveArgs(body.slice(argsStart));
return {
cleaned: `${body.slice(0, start)} ${body.slice(argsStart + parsed.consumed)}`.replace(/\s+/g, " ").trim(),
hasDirective: true,
execHost: parsed.execHost,
execSecurity: parsed.execSecurity,
execAsk: parsed.execAsk,
execNode: parsed.execNode,
rawExecHost: parsed.rawExecHost,
rawExecSecurity: parsed.rawExecSecurity,
rawExecAsk: parsed.rawExecAsk,
rawExecNode: parsed.rawExecNode,
hasExecOptions: parsed.hasExecOptions,
invalidHost: parsed.invalidHost,
invalidSecurity: parsed.invalidSecurity,
invalidAsk: parsed.invalidAsk,
invalidNode: parsed.invalidNode
};
}
//#endregion
//#region src/auto-reply/reply/directives.ts
const escapeRegExp$4 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const matchLevelDirective = (body, names) => {
const namePattern = names.map(escapeRegExp$4).join("|");
const match = body.match(new RegExp(`(?:^|\\s)\\/(?:${namePattern})(?=$|\\s|:)`, "i"));
if (!match || match.index === void 0) return null;
const start = match.index;
let end = match.index + match[0].length;
let i = end;
while (i < body.length && /\s/.test(body[i])) i += 1;
if (body[i] === ":") {
i += 1;
while (i < body.length && /\s/.test(body[i])) i += 1;
}
const argStart = i;
while (i < body.length && /[A-Za-z-]/.test(body[i])) i += 1;
const rawLevel = i > argStart ? body.slice(argStart, i) : void 0;
end = i;
return {
start,
end,
rawLevel
};
};
const extractLevelDirective = (body, names, normalize) => {
const match = matchLevelDirective(body, names);
if (!match) return {
cleaned: body.trim(),
hasDirective: false
};
const rawLevel = match.rawLevel;
const level = normalize(rawLevel);
return {
cleaned: body.slice(0, match.start).concat(" ").concat(body.slice(match.end)).replace(/\s+/g, " ").trim(),
level,
rawLevel,
hasDirective: true
};
};
const extractSimpleDirective = (body, names) => {
const namePattern = names.map(escapeRegExp$4).join("|");
const match = body.match(new RegExp(`(?:^|\\s)\\/(?:${namePattern})(?=$|\\s|:)(?:\\s*:\\s*)?`, "i"));
return {
cleaned: match ? body.replace(match[0], " ").replace(/\s+/g, " ").trim() : body.trim(),
hasDirective: Boolean(match)
};
};
function extractThinkDirective(body) {
if (!body) return {
cleaned: "",
hasDirective: false
};
const extracted = extractLevelDirective(body, [
"thinking",
"think",
"t"
], normalizeThinkLevel);
return {
cleaned: extracted.cleaned,
thinkLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective
};
}
function extractVerboseDirective(body) {
if (!body) return {
cleaned: "",
hasDirective: false
};
const extracted = extractLevelDirective(body, ["verbose", "v"], normalizeVerboseLevel);
return {
cleaned: extracted.cleaned,
verboseLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective
};
}
function extractElevatedDirective(body) {
if (!body) return {
cleaned: "",
hasDirective: false
};
const extracted = extractLevelDirective(body, ["elevated", "elev"], normalizeElevatedLevel);
return {
cleaned: extracted.cleaned,
elevatedLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective
};
}
function extractReasoningDirective(body) {
if (!body) return {
cleaned: "",
hasDirective: false
};
const extracted = extractLevelDirective(body, ["reasoning", "reason"], normalizeReasoningLevel);
return {
cleaned: extracted.cleaned,
reasoningLevel: extracted.level,
rawLevel: extracted.rawLevel,
hasDirective: extracted.hasDirective
};
}
function extractStatusDirective(body) {
if (!body) return {
cleaned: "",
hasDirective: false
};
return extractSimpleDirective(body, ["status"]);
}
//#endregion
//#region src/agents/timeout.ts
const DEFAULT_AGENT_TIMEOUT_SECONDS = 600;
const normalizeNumber = (value) => typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : void 0;
function resolveAgentTimeoutSeconds(cfg) {
const seconds = normalizeNumber(cfg?.agents?.defaults?.timeoutSeconds) ?? DEFAULT_AGENT_TIMEOUT_SECONDS;
return Math.max(seconds, 1);
}
function resolveAgentTimeoutMs(opts) {
const minMs = Math.max(normalizeNumber(opts.minMs) ?? 1, 1);
const defaultMs = resolveAgentTimeoutSeconds(opts.cfg) * 1e3;
const NO_TIMEOUT_MS = 720 * 60 * 60 * 1e3;
const overrideMs = normalizeNumber(opts.overrideMs);
if (overrideMs !== void 0) {
if (overrideMs === 0) return NO_TIMEOUT_MS;
if (overrideMs < 0) return defaultMs;
return Math.max(overrideMs, minMs);
}
const overrideSeconds = normalizeNumber(opts.overrideSeconds);
if (overrideSeconds !== void 0) {
if (overrideSeconds === 0) return NO_TIMEOUT_MS;
if (overrideSeconds < 0) return defaultMs;
return Math.max(overrideSeconds * 1e3, minMs);
}
return Math.max(defaultMs, minMs);
}
//#endregion
//#region src/channels/sender-label.ts
function normalize(value) {
const trimmed = value?.trim();
return trimmed ? trimmed : void 0;
}
function resolveSenderLabel(params) {
const name = normalize(params.name);
const username = normalize(params.username);
const tag = normalize(params.tag);
const e164 = normalize(params.e164);
const id = normalize(params.id);
const display = name ?? username ?? tag ?? "";
const idPart = e164 ?? id ?? "";
if (display && idPart && display !== idPart) return `${display} (${idPart})`;
return display || idPart || null;
}
function listSenderLabelCandidates(params) {
const candidates = /* @__PURE__ */ new Set();
const name = normalize(params.name);
const username = normalize(params.username);
const tag = normalize(params.tag);
const e164 = normalize(params.e164);
const id = normalize(params.id);
if (name) candidates.add(name);
if (username) candidates.add(username);
if (tag) candidates.add(tag);
if (e164) candidates.add(e164);
if (id) candidates.add(id);
const resolved = resolveSenderLabel(params);
if (resolved) candidates.add(resolved);
return Array.from(candidates);
}
//#endregion
//#region src/auto-reply/reply/inbound-sender-meta.ts
function formatInboundBodyWithSenderMeta(params) {
const body = params.body;
if (!body.trim()) return body;
const chatType = normalizeChatType(params.ctx.ChatType);
if (!chatType || chatType === "direct") return body;
if (hasSenderMetaLine(body, params.ctx)) return body;
const senderLabel = resolveSenderLabel({
name: params.ctx.SenderName,
username: params.ctx.SenderUsername,
tag: params.ctx.SenderTag,
e164: params.ctx.SenderE164,
id: params.ctx.SenderId
});
if (!senderLabel) return body;
return `${body}\n[from: ${senderLabel}]`;
}
function hasSenderMetaLine(body, ctx) {
if (/(^|\n)\[from:/i.test(body)) return true;
const candidates = listSenderLabelCandidates({
name: ctx.SenderName,
username: ctx.SenderUsername,
tag: ctx.SenderTag,
e164: ctx.SenderE164,
id: ctx.SenderId
});
if (candidates.length === 0) return false;
return candidates.some((candidate) => {
const escaped = escapeRegExp$3(candidate);
return new RegExp(`(^|\\n|\\]\\s*)${escaped}:\\s`, "i").test(body);
});
}
function escapeRegExp$3(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
//#endregion
//#region src/auto-reply/reply/inbound-text.ts
function normalizeInboundTextNewlines(input) {
return input.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("\\n", "\n");
}
//#endregion
//#region src/auto-reply/reply/inbound-context.ts
function normalizeTextField(value) {
if (typeof value !== "string") return;
return normalizeInboundTextNewlines(value);
}
function finalizeInboundContext(ctx, opts = {}) {
const normalized = ctx;
normalized.Body = normalizeInboundTextNewlines(typeof normalized.Body === "string" ? normalized.Body : "");
normalized.RawBody = normalizeTextField(normalized.RawBody);
normalized.CommandBody = normalizeTextField(normalized.CommandBody);
normalized.Transcript = normalizeTextField(normalized.Transcript);
normalized.ThreadStarterBody = normalizeTextField(normalized.ThreadStarterBody);
if (Array.isArray(normalized.UntrustedContext)) normalized.UntrustedContext = normalized.UntrustedContext.map((entry) => normalizeInboundTextNewlines(entry)).filter((entry) => Boolean(entry));
const chatType = normalizeChatType(normalized.ChatType);
if (chatType && (opts.forceChatType || normalized.ChatType !== chatType)) normalized.ChatType = chatType;
normalized.BodyForAgent = normalizeInboundTextNewlines(opts.forceBodyForAgent ? normalized.Body : normalized.BodyForAgent ?? normalized.Body);
normalized.BodyForCommands = normalizeInboundTextNewlines(opts.forceBodyForCommands ? normalized.CommandBody ?? normalized.RawBody ?? normalized.Body : normalized.BodyForCommands ?? normalized.CommandBody ?? normalized.RawBody ?? normalized.Body);
const explicitLabel = normalized.ConversationLabel?.trim();
if (opts.forceConversationLabel || !explicitLabel) {
const resolved = resolveConversationLabel(normalized)?.trim();
if (resolved) normalized.ConversationLabel = resolved;
} else normalized.ConversationLabel = explicitLabel;
normalized.Body = formatInboundBodyWithSenderMeta({
ctx: normalized,
body: normalized.Body
});
normalized.BodyForAgent = formatInboundBodyWithSenderMeta({
ctx: normalized,
body: normalized.BodyForAgent
});
normalized.CommandAuthorized = normalized.CommandAuthorized === true;
return normalized;
}
//#endregion
//#region src/link-understanding/format.ts
function formatLinkUnderstandingBody(params) {
const outputs = params.outputs.map((output) => output.trim()).filter(Boolean);
if (outputs.length === 0) return params.body ?? "";
const base = (params.body ?? "").trim();
if (!base) return outputs.join("\n");
return `${base}\n\n${outputs.join("\n")}`;
}
//#endregion
//#region src/auto-reply/templating.ts
function formatTemplateValue(value) {
if (value == null) return "";
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
if (typeof value === "symbol" || typeof value === "function") return value.toString();
if (Array.isArray(value)) return value.flatMap((entry) => {
if (entry == null) return [];
if (typeof entry === "string") return [entry];
if (typeof entry === "number" || typeof entry === "boolean" || typeof entry === "bigint") return [String(entry)];
return [];
}).join(",");
if (typeof value === "object") return "";
return "";
}
function applyTemplate(str, ctx) {
if (!str) return "";
return str.replace(/{{\s*(\w+)\s*}}/g, (_, key) => {
const value = ctx[key];
return formatTemplateValue(value);
});
}
//#endregion
//#region src/media-understanding/defaults.ts
const MB = 1024 * 1024;
const DEFAULT_MAX_CHARS$2 = 500;
const DEFAULT_MAX_CHARS_BY_CAPABILITY = {
image: DEFAULT_MAX_CHARS$2,
audio: void 0,
video: DEFAULT_MAX_CHARS$2
};
const DEFAULT_MAX_BYTES = {
image: 10 * MB,
audio: 20 * MB,
video: 50 * MB
};
const DEFAULT_TIMEOUT_SECONDS$1 = {
image: 60,
audio: 60,
video: 120
};
const DEFAULT_PROMPT$1 = {
image: "Describe the image.",
audio: "Transcribe the audio.",
video: "Describe the video."
};
const DEFAULT_VIDEO_MAX_BASE64_BYTES = 70 * MB;
const DEFAULT_AUDIO_MODELS = {
groq: "whisper-large-v3-turbo",
openai: "gpt-4o-mini-transcribe",
deepgram: "nova-3"
};
const CLI_OUTPUT_MAX_BUFFER = 5 * MB;
const DEFAULT_MEDIA_CONCURRENCY = 2;
//#endregion
//#region src/channels/targets.ts
function normalizeTargetId(kind, id) {
return `${kind}:${id}`.toLowerCase();
}
function buildMessagingTarget(kind, id, raw) {
return {
kind,
id,
raw,
normalized: normalizeTargetId(kind, id)
};
}
function ensureTargetId(params) {
if (!params.pattern.test(params.candidate)) throw new Error(params.errorMessage);
return params.candidate;
}
function requireTargetKind(params) {
const kindLabel = params.kind;
if (!params.target) throw new Error(`${params.platform} ${kindLabel} id is required.`);
if (params.target.kind !== params.kind) throw new Error(`${params.platform} ${kindLabel} id is required (use ${kindLabel}:<id>).`);
return params.target.id;
}
//#endregion
//#region src/slack/targets.ts
function parseSlackTarget(raw, options = {}) {
const trimmed = raw.trim();
if (!trimmed) return;
const mentionMatch = trimmed.match(/^<@([A-Z0-9]+)>$/i);
if (mentionMatch) return buildMessagingTarget("user", mentionMatch[1], trimmed);
if (trimmed.startsWith("user:")) {
const id = trimmed.slice(5).trim();
return id ? buildMessagingTarget("user", id, trimmed) : void 0;
}
if (trimmed.startsWith("channel:")) {
const id = trimmed.slice(8).trim();
return id ? buildMessagingTarget("channel", id, trimmed) : void 0;
}
if (trimmed.startsWith("slack:")) {
const id = trimmed.slice(6).trim();
return id ? buildMessagingTarget("user", id, trimmed) : void 0;
}
if (trimmed.startsWith("@")) return buildMessagingTarget("user", ensureTargetId({
candidate: trimmed.slice(1).trim(),
pattern: /^[A-Z0-9]+$/i,
errorMessage: "Slack DMs require a user id (use user:<id> or <@id>)"
}), trimmed);
if (trimmed.startsWith("#")) return buildMessagingTarget("channel", ensureTargetId({
candidate: trimmed.slice(1).trim(),
pattern: /^[A-Z0-9]+$/i,
errorMessage: "Slack channels require a channel id (use channel:<id>)"
}), trimmed);
if (options.defaultKind) return buildMessagingTarget(options.defaultKind, trimmed, trimmed);
return buildMessagingTarget("channel", trimmed, trimmed);
}
function resolveSlackChannelId(raw) {
return requireTargetKind({
platform: "Slack",
target: parseSlackTarget(raw, { defaultKind: "channel" }),
kind: "channel"
});
}
//#endregion
//#region src/channels/channel-config.ts
function applyChannelMatchMeta(result, match) {
if (match.matchKey && match.matchSource) {
result.matchKey = match.matchKey;
result.matchSource = match.matchSource;
}
return result;
}
function resolveChannelMatchConfig(match, resolveEntry) {
if (!match.entry) return null;
return applyChannelMatchMeta(resolveEntry(match.entry), match);
}
function buildChannelKeyCandidates(...keys) {
const seen = /* @__PURE__ */ new Set();
const candidates = [];
for (const key of keys) {
if (typeof key !== "string") continue;
const trimmed = key.trim();
if (!trimmed || seen.has(trimmed)) continue;
seen.add(trimmed);
candidates.push(trimmed);
}
return candidates;
}
function resolveChannelEntryMatch(params) {
const entries = params.entries ?? {};
const match = {};
for (const key of params.keys) {
if (!Object.prototype.hasOwnProperty.call(entries, key)) continue;
match.entry = entries[key];
match.key = key;
break;
}
if (params.wildcardKey && Object.prototype.hasOwnProperty.call(entries, params.wildcardKey)) {
match.wildcardEntry = entries[params.wildcardKey];
match.wildcardKey = params.wildcardKey;
}
return match;
}
function resolveChannelEntryMatchWithFallback(params) {
const direct = resolveChannelEntryMatch({
entries: params.entries,
keys: params.keys,
wildcardKey: params.wildcardKey
});
if (direct.entry && direct.key) return {
...direct,
matchKey: direct.key,
matchSource: "direct"
};
const normalizeKey = params.normalizeKey;
if (normalizeKey) {
const normalizedKeys = params.keys.map((key) => normalizeKey(key)).filter(Boolean);
if (normalizedKeys.length > 0) for (const [entryKey, entry] of Object.entries(params.entries ?? {})) {
const normalizedEntry = normalizeKey(entryKey);
if (normalizedEntry && normalizedKeys.includes(normalizedEntry)) return {
...direct,
entry,
key: entryKey,
matchKey: entryKey,
matchSource: "direct"
};
}
}
const parentKeys = params.parentKeys ?? [];
if (parentKeys.length > 0) {
const parent = resolveChannelEntryMatch({
entries: params.entries,
keys: parentKeys
});
if (parent.entry && parent.key) return {
...direct,
entry: parent.entry,
key: parent.key,
parentEntry: parent.entry,
parentKey: parent.key,
matchKey: parent.key,
matchSource: "parent"
};
if (normalizeKey) {
const normalizedParentKeys = parentKeys.map((key) => normalizeKey(key)).filter(Boolean);
if (normalizedParentKeys.length > 0) for (const [entryKey, entry] of Object.entries(params.entries ?? {})) {
const normalizedEntry = normalizeKey(entryKey);
if (normalizedEntry && normalizedParentKeys.includes(normalizedEntry)) return {
...direct,
entry,
key: entryKey,
parentEntry: entry,
parentKey: entryKey,
matchKey: entryKey,
matchSource: "parent"
};
}
}
}
if (direct.wildcardEntry && direct.wildcardKey) return {
...direct,
entry: direct.wildcardEntry,
key: direct.wildcardKey,
matchKey: direct.wildcardKey,
matchSource: "wildcard"
};
return direct;
}
//#endregion
//#region src/channels/allowlist-match.ts
function formatAllowlistMatchMeta(match) {
return `matchKey=${match?.matchKey ?? "none"} matchSource=${match?.matchSource ?? "none"}`;
}
//#endregion
//#region src/media-understanding/providers/anthropic/index.ts
const anthropicProvider = {
id: "anthropic",
capabilities: ["image"],
describeImage: describeImageWithModel
};
//#endregion
//#region src/media-understanding/providers/shared.ts
const MAX_ERROR_CHARS = 300;
function normalizeBaseUrl(baseUrl, fallback) {
return (baseUrl?.trim() || fallback).replace(/\/+$/, "");
}
async function fetchWithTimeout$3(url, init, timeoutMs, fetchFn) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), Math.max(1, timeoutMs));
try {
return await fetchFn(url, {
...init,
signal: controller.signal
});
} finally {
clearTimeout(timer);
}
}
async function fetchWithTimeoutGuarded(url, init, timeoutMs, fetchFn, options) {
return await fetchWithSsrFGuard({
url,
fetchImpl: fetchFn,
init,
timeoutMs,
policy: options?.ssrfPolicy,
lookupFn: options?.lookupFn,
pinDns: options?.pinDns
});
}
async function readErrorResponse(res) {
try {
const collapsed = (await res.text()).replace(/\s+/g, " ").trim();
if (!collapsed) return;
if (collapsed.length <= MAX_ERROR_CHARS) return collapsed;
return `${collapsed.slice(0, MAX_ERROR_CHARS)}…`;
} catch {
return;
}
}
//#endregion
//#region src/media-understanding/providers/deepgram/audio.ts
const DEFAULT_DEEPGRAM_AUDIO_BASE_URL = "https://api.deepgram.com/v1";
const DEFAULT_DEEPGRAM_AUDIO_MODEL = "nova-3";
function resolveModel$4(model) {
return model?.trim() || DEFAULT_DEEPGRAM_AUDIO_MODEL;
}
async function transcribeDeepgramAudio(params) {
const fetchFn = params.fetchFn ?? fetch;
const baseUrl = normalizeBaseUrl(params.baseUrl, DEFAULT_DEEPGRAM_AUDIO_BASE_URL);
const allowPrivate = Boolean(params.baseUrl?.trim());
const model = resolveModel$4(params.model);
const url = new URL(`${baseUrl}/listen`);
url.searchParams.set("model", model);
if (params.language?.trim()) url.searchParams.set("language", params.language.trim());
if (params.query) for (const [key, value] of Object.entries(params.query)) {
if (value === void 0) continue;
url.searchParams.set(key, String(value));
}
const headers = new Headers(params.headers);
if (!headers.has("authorization")) headers.set("authorization", `Token ${params.apiKey}`);
if (!headers.has("content-type")) headers.set("content-type", params.mime ?? "application/octet-stream");
const body = new Uint8Array(params.buffer);
const { response: res, release } = await fetchWithTimeoutGuarded(url.toString(), {
method: "POST",
headers,
body
}, params.timeoutMs, fetchFn, allowPrivate ? { ssrfPolicy: { allowPrivateNetwork: true } } : void 0);
try {
if (!res.ok) {
const detail = await readErrorResponse(res);
const suffix = detail ? `: ${detail}` : "";
throw new Error(`Audio transcription failed (HTTP ${res.status})${suffix}`);
}
const transcript = (await res.json()).results?.channels?.[0]?.alternatives?.[0]?.transcript?.trim();
if (!transcript) throw new Error("Audio transcription response missing transcript");
return {
text: transcript,
model
};
} finally {
await release();
}
}
//#endregion
//#region src/media-understanding/providers/deepgram/index.ts
const deepgramProvider = {
id: "deepgram",
capabilities: ["audio"],
transcribeAudio: transcribeDeepgramAudio
};
//#endregion
//#region src/media-understanding/providers/google/audio.ts
const DEFAULT_GOOGLE_AUDIO_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
const DEFAULT_GOOGLE_AUDIO_MODEL = "gemini-3-flash-preview";
const DEFAULT_GOOGLE_AUDIO_PROMPT = "Transcribe the audio.";
function resolveModel$3(model) {
const trimmed = model?.trim();
if (!trimmed) return DEFAULT_GOOGLE_AUDIO_MODEL;
return normalizeGoogleModelId(trimmed);
}
function resolvePrompt$2(prompt) {
return prompt?.trim() || DEFAULT_GOOGLE_AUDIO_PROMPT;
}
async function transcribeGeminiAudio(params) {
const fetchFn = params.fetchFn ?? fetch;
const baseUrl = normalizeBaseUrl(params.baseUrl, DEFAULT_GOOGLE_AUDIO_BASE_URL);
const allowPrivate = Boolean(params.baseUrl?.trim());
const model = resolveModel$3(params.model);
const url = `${baseUrl}/models/${model}:generateContent`;
const headers = new Headers(params.headers);
if (!headers.has("content-type")) headers.set("content-type", "application/json");
if (!headers.has("x-goog-api-key")) headers.set("x-goog-api-key", params.apiKey);
const body = { contents: [{
role: "user",
parts: [{ text: resolvePrompt$2(params.prompt) }, { inline_data: {
mime_type: params.mime ?? "audio/wav",
data: params.buffer.toString("base64")
} }]
}] };
const { response: res, release } = await fetchWithTimeoutGuarded(url, {
method: "POST",
headers,
body: JSON.stringify(body)
}, params.timeoutMs, fetchFn, allowPrivate ? { ssrfPolicy: { allowPrivateNetwork: true } } : void 0);
try {
if (!res.ok) {
const detail = await readErrorResponse(res);
const suffix = detail ? `: ${detail}` : "";
throw new Error(`Audio transcription failed (HTTP ${res.status})${suffix}`);
}
const text = ((await res.json()).candidates?.[0]?.content?.parts ?? []).map((part) => part?.text?.trim()).filter(Boolean).join("\n");
if (!text) throw new Error("Audio transcription response missing text");
return {
text,
model
};
} finally {
await release();
}
}
//#endregion
//#region src/media-understanding/providers/google/video.ts
const DEFAULT_GOOGLE_VIDEO_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
const DEFAULT_GOOGLE_VIDEO_MODEL = "gemini-3-flash-preview";
const DEFAULT_GOOGLE_VIDEO_PROMPT = "Describe the video.";
function resolveModel$2(model) {
const trimmed = model?.trim();
if (!trimmed) return DEFAULT_GOOGLE_VIDEO_MODEL;
return normalizeGoogleModelId(trimmed);
}
function resolvePrompt$1(prompt) {
return prompt?.trim() || DEFAULT_GOOGLE_VIDEO_PROMPT;
}
async function describeGeminiVideo(params) {
const fetchFn = params.fetchFn ?? fetch;
const baseUrl = normalizeBaseUrl(params.baseUrl, DEFAULT_GOOGLE_VIDEO_BASE_URL);
const allowPrivate = Boolean(params.baseUrl?.trim());
const model = resolveModel$2(params.model);
const url = `${baseUrl}/models/${model}:generateContent`;
const headers = new Headers(params.headers);
if (!headers.has("content-type")) headers.set("content-type", "application/json");
if (!headers.has("x-goog-api-key")) headers.set("x-goog-api-key", params.apiKey);
const body = { contents: [{
role: "user",
parts: [{ text: resolvePrompt$1(params.prompt) }, { inline_data: {
mime_type: params.mime ?? "video/mp4",
data: params.buffer.toString("base64")
} }]
}] };
const { response: res, release } = await fetchWithTimeoutGuarded(url, {
method: "POST",
headers,
body: JSON.stringify(body)
}, params.timeoutMs, fetchFn, allowPrivate ? { ssrfPolicy: { allowPrivateNetwork: true } } : void 0);
try {
if (!res.ok) {
const detail = await readErrorResponse(res);
const suffix = detail ? `: ${detail}` : "";
throw new Error(`Video description failed (HTTP ${res.status})${suffix}`);
}
const text = ((await res.json()).candidates?.[0]?.content?.parts ?? []).map((part) => part?.text?.trim()).filter(Boolean).join("\n");
if (!text) throw new Error("Video description response missing text");
return {
text,
model
};
} finally {
await release();
}
}
//#endregion
//#region src/media-understanding/providers/google/index.ts
const googleProvider = {
id: "google",
capabilities: [
"image",
"audio",
"video"
],
describeImage: describeImageWithModel,
transcribeAudio: transcribeGeminiAudio,
describeVideo: describeGeminiVideo
};
//#endregion
//#region src/media-understanding/providers/openai/audio.ts
const DEFAULT_OPENAI_AUDIO_BASE_URL = "https://api.openai.com/v1";
const DEFAULT_OPENAI_AUDIO_MODEL = "gpt-4o-mini-transcribe";
function resolveModel$1(model) {
return model?.trim() || DEFAULT_OPENAI_AUDIO_MODEL;
}
async function transcribeOpenAiCompatibleAudio(params) {
const fetchFn = params.fetchFn ?? fetch;
const baseUrl = normalizeBaseUrl(params.baseUrl, DEFAULT_OPENAI_AUDIO_BASE_URL);
const allowPrivate = Boolean(params.baseUrl?.trim());
const url = `${baseUrl}/audio/transcriptions`;
const model = resolveModel$1(params.model);
const form = new FormData();
const fileName = params.fileName?.trim() || path.basename(params.fileName) || "audio";
const bytes = new Uint8Array(params.buffer);
const blob = new Blob([bytes], { type: params.mime ?? "application/octet-stream" });
form.append("file", blob, fileName);
form.append("model", model);
if (params.language?.trim()) form.append("language", params.language.trim());
if (params.prompt?.trim()) form.append("prompt", params.prompt.trim());
const headers = new Headers(params.headers);
if (!headers.has("authorization")) headers.set("authorization", `Bearer ${params.apiKey}`);
const { response: res, release } = await fetchWithTimeoutGuarded(url, {
method: "POST",
headers,
body: form
}, params.timeoutMs, fetchFn, allowPrivate ? { ssrfPolicy: { allowPrivateNetwork: true } } : void 0);
try {
if (!res.ok) {
const detail = await readErrorResponse(res);
const suffix = detail ? `: ${detail}` : "";
throw new Error(`Audio transcription failed (HTTP ${res.status})${suffix}`);
}
const text = (await res.json()).text?.trim();
if (!text) throw new Error("Audio transcription response missing text");
return {
text,
model
};
} finally {
await release();
}
}
//#endregion
//#region src/media-understanding/providers/groq/index.ts
const DEFAULT_GROQ_AUDIO_BASE_URL = "https://api.groq.com/openai/v1";
const groqProvider = {
id: "groq",
capabilities: ["audio"],
transcribeAudio: (req) => transcribeOpenAiCompatibleAudio({
...req,
baseUrl: req.baseUrl ?? DEFAULT_GROQ_AUDIO_BASE_URL
})
};
//#endregion
//#region src/media-understanding/providers/minimax/index.ts
const minimaxProvider = {
id: "minimax",
capabilities: ["image"],
describeImage: describeImageWithModel
};
//#endregion
//#region src/media-understanding/providers/openai/index.ts
const openaiProvider = {
id: "openai",
capabilities: ["image"],
describeImage: describeImageWithModel,
transcribeAudio: transcribeOpenAiCompatibleAudio
};
//#endregion
//#region src/media-understanding/providers/index.ts
const PROVIDERS = [
groqProvider,
openaiProvider,
googleProvider,
anthropicProvider,
minimaxProvider,
deepgramProvider
];
function normalizeMediaProviderId(id) {
const normalized = normalizeProviderId(id);
if (normalized === "gemini") return "google";
return normalized;
}
function buildMediaUnderstandingRegistry(overrides) {
const registry = /* @__PURE__ */ new Map();
for (const provider of PROVIDERS) registry.set(normalizeMediaProviderId(provider.id), provider);
if (overrides) for (const [key, provider] of Object.entries(overrides)) {
const normalizedKey = normalizeMediaProviderId(key);
const existing = registry.get(normalizedKey);
const merged = existing ? {
...existing,
...provider,
capabilities: provider.capabilities ?? existing.capabilities
} : provider;
registry.set(normalizedKey, merged);
}
return registry;
}
function getMediaUnderstandingProvider(id, registry) {
return registry.get(normalizeMediaProviderId(id));
}
//#endregion
//#region src/media-understanding/scope.ts
function normalizeDecision(value) {
const normalized = value?.trim().toLowerCase();
if (normalized === "allow") return "allow";
if (normalized === "deny") return "deny";
}
function normalizeMatch(value) {
return value?.trim().toLowerCase() || void 0;
}
function normalizeMediaUnderstandingChatType(raw) {
return normalizeChatType(raw ?? void 0);
}
function resolveMediaUnderstandingScope(params) {
const scope = params.scope;
if (!scope) return "allow";
const channel = normalizeMatch(params.channel);
const chatType = normalizeMediaUnderstandingChatType(params.chatType);
const sessionKey = normalizeMatch(params.sessionKey) ?? "";
for (const rule of scope.rules ?? []) {
if (!rule) continue;
const action = normalizeDecision(rule.action) ?? "allow";
const match = rule.match ?? {};
const matchChannel = normalizeMatch(match.channel);
const matchChatType = normalizeMediaUnderstandingChatType(match.chatType);
const matchPrefix = normalizeMatch(match.keyPrefix);
if (matchChannel && matchChannel !== channel) continue;
if (matchChatType && matchChatType !== chatType) continue;
if (matchPrefix && !sessionKey.startsWith(matchPrefix)) continue;
return action;
}
return normalizeDecision(scope.d