@gguf/claw
Version:
Multi-channel AI gateway with extensible messaging integrations
838 lines (825 loc) • 2.48 MB
JavaScript
import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js";
import { g as resolveStateDir, r as STATE_DIR, u as resolveGatewayPort, y as resolveRequiredHomeDir } from "./paths-B4BZAPZh.js";
import { B as theme, C as sleep$1, D as isPlainObject, E as truncateUtf16Safe, F as shouldLogVerbose, J as normalizeLogLevel, L as warn, M as logVerbose, O as danger, S as shortenHomePath, V as getChildLogger, X as resolvePreferredOpenClawTmpDir, d as isRecord$1, i as clampInt, l as escapeRegExp, m as normalizeE164, t as CONFIG_DIR, w as sliceUtf16Safe, x as shortenHomeInString, y as resolveUserPath } from "./utils-CP9YLh6M.js";
import { a as normalizeElevatedLevel, c as normalizeUsageDisplay, d as supportsXHighThinking, l as normalizeVerboseLevel, n as formatXHighModelHint, o as normalizeReasoningLevel, s as normalizeThinkLevel, t as formatThinkingLevels, u as resolveResponseUsageMode } from "./thinking-EAliFiVK.js";
import { S as resolveThreadParentSessionKey, _ as isAcpSessionKey, b as isSubagentSessionKey, c as normalizeAccountId$3, d as resolveAgentIdFromSessionKey, f as resolveThreadSessionKeys, g as getSubagentDepth, i as buildAgentMainSessionKey, l as normalizeAgentId, n as DEFAULT_AGENT_ID, p as sanitizeAgentId, s as classifySessionKeyShape, t as DEFAULT_ACCOUNT_ID$1, u as normalizeMainKey, v as isCronRunSessionKey, x as parseAgentSessionKey, y as isCronSessionKey } from "./session-key-CZ6OwgSB.js";
import { t as resolveOpenClawPackageRoot } from "./openclaw-root-BM-yQZH6.js";
import { C as createInternalHookEvent, T as triggerInternalHook, _ as clearPluginCommands, b as listPluginCommands, c as normalizeAnyChannelId, f as requireActivePluginRegistry, g as normalizePluginHttpPath, h as createPluginRegistry, l as normalizeChannelId, n as CHAT_CHANNEL_ORDER, p as setActivePluginRegistry, r as DEFAULT_CHAT_CHANNEL, v as executePluginCommand, x as matchPluginCommand, y as getPluginCommandSpecs } from "./registry-B-j4DRfe.js";
import { d as createNonExitingRuntime, f as defaultRuntime, t as createSubsystemLogger } from "./subsystem-BCQGGxdd.js";
import { a as logError, i as logDebug, n as runExec, o as logInfo, r as spawnWithFallback, s as logWarn, t as runCommandWithTimeout } from "./exec-DYqRzFbo.js";
import { C as ensureAgentWorkspace, E as loadWorkspaceBootstrapFiles, a as resolveAgentModelFallbacksOverride, c as resolveAgentWorkspaceDir, d as resolveSessionAgentId, f as resolveSessionAgentIds, h as DEFAULT_BOOTSTRAP_FILENAME, i as resolveAgentDir, l as resolveDefaultAgentId, m as DEFAULT_AGENT_WORKSPACE_DIR, n as listAgentIds, o as resolveAgentModelPrimary, r as resolveAgentConfig, s as resolveAgentSkillsFilter, u as resolveEffectiveModelFallbacks, w as filterBootstrapFilesForSession } from "./agent-scope-BnZW9Gh2.js";
import { $ as resolveShellEnvFallbackTimeoutMs, Bt as resolveAuthProfileDisplayLabel, Ct as dedupeProfileIds, Ft as withFileLock, G as requireApiKey, Gt as DEFAULT_PROVIDER, H as createOllamaStreamFn, J as resolveEnvApiKey, K as resolveApiKeyForProvider, Nt as resolveAuthStorePathForDisplay, Pt as resolveOpenClawAgentDir, Tt as markAuthProfileGood, U as getApiKeyForModel, Ut as DEFAULT_CONTEXT_TOKENS, V as OLLAMA_NATIVE_BASE_URL, W as getCustomProviderApiKey, Wt as DEFAULT_MODEL, Y as resolveModelAuthMode, Z as getShellPathFromLoginShell, _t as resolveApiKeyForProfile, c as normalizeModelRef$2, dt as resolveAuthProfileOrder, ft as getSoonestCooldownExpiry, g as resolveModelRefFromString, ht as markAuthProfileUsed, i as findNormalizedProviderValue, kt as ensureAuthProfileStore, l as normalizeProviderId, m as resolveDefaultModelForAgent, mt as markAuthProfileFailure, n as buildConfiguredAllowlistKeys, o as isCliProvider, p as resolveConfiguredModelRef, pt as isProfileInCooldown, r as buildModelAliasIndex, s as modelKey, t as buildAllowedModelSet, u as parseModelRef, v as resolveSubagentSpawnModelSelection, wt as listProfilesForProvider, y as resolveThinkingDefault, zt as normalizeSecretInput } from "./model-selection-CqaTAlhy.js";
import { a as saveJsonFile, i as loadJsonFile } from "./github-copilot-token-D2zp6kMZ.js";
import { t as formatCliCommand } from "./command-format-DEKzLnLg.js";
import { t as parseBooleanValue$1 } from "./boolean-BsqeuxE6.js";
import { t as isTruthyEnvValue } from "./env-VriqyjXT.js";
import { a as isInternalMessageChannel, c as listDeliverableMessageChannels, d as resolveMessageChannel, h as GATEWAY_CLIENT_NAMES, i as isGatewayMessageChannel, 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-Bena1Tzd.js";
import { $ as resolveDiscordChannelId, A as addRoleDiscord, B as removeRoleDiscord, C as fetchMessageDiscord, Ct as applyChannelMatchMeta, D as readMessagesDiscord, E as pinMessageDiscord, Et as resolveChannelEntryMatchWithFallback, F as fetchRoleInfoDiscord, G as createChannelDiscord, H as listGuildEmojisDiscord, I as fetchVoiceStatusDiscord, J as moveChannelDiscord, K as deleteChannelDiscord, L as kickMemberDiscord, M as createScheduledEventDiscord, N as fetchChannelInfoDiscord, O as searchMessagesDiscord, P as fetchMemberInfoDiscord, Q as parseDiscordTarget, R as listGuildChannelsDiscord, S as editMessageDiscord, St as chunkDiscordTextWithMode, T as listThreadsDiscord, Tt as normalizeChannelSlug, U as uploadEmojiDiscord, V as timeoutMemberDiscord, W as uploadStickerDiscord, X as setChannelPermissionDiscord, Y as removeChannelPermissionDiscord, Z as stripUndefinedFields, _ as sendPollDiscord, _t as resolveTimestampMs, a as removeReactionDiscord, at as normalizeDiscordSlug, b as createThreadDiscord, bt as hasAnyGuildPermissionDiscord, c as formatDiscordComponentEventText, ct as resolveDiscordGuildEntry, d as parseDiscordModalCustomId, dt as resolveDiscordShouldRequireMention, et as listDiscordDirectoryGroupsLive, f as parseDiscordModalCustomIdForCarbon, ft as resolveGroupDmAllow, g as sendMessageDiscord, gt as resolveDiscordSystemLocation, h as resolveDiscordModalEntry, ht as formatDiscordUserTag, i as removeOwnReactionsDiscord, it as normalizeDiscordAllowList, j as banMemberDiscord, k as unpinMessageDiscord, l as parseDiscordComponentCustomId, lt as resolveDiscordMemberAccessState, m as resolveDiscordComponentEntry, mt as formatDiscordReactionEmoji, n as fetchReactionsDiscord, nt as allowListMatches$1, o as sendDiscordComponentMessage, ot as resolveDiscordAllowListMatch, p as readDiscordComponentSpec, pt as shouldEmitDiscordReactionNotification, q as editChannelDiscord, r as reactMessageDiscord, rt as isDiscordGroupAllowedByPolicy, s as createDiscordFormModal, st as resolveDiscordChannelConfigWithFallback, tt as listDiscordDirectoryPeersLive, u as parseDiscordComponentCustomIdForCarbon, ut as resolveDiscordOwnerAllowFrom, v as sendStickerDiscord, vt as fetchDiscord, w as listPinsDiscord, wt as buildChannelKeyCandidates, x as deleteMessageDiscord, xt as createDiscordClient, y as sendVoiceMessageDiscord, yt as fetchChannelPermissionsDiscord, z as listScheduledEventsDiscord } from "./send-CsyONLnQ.js";
import { A as parseConfigPath, C as parseDurationMs, D as setConfigOverride, E as resetConfigOverrides, M as unsetConfigValueAtPath, O as unsetConfigOverride, T as getConfigOverrides, V as VERSION, _ as isInboundPathAllowed, b as resolveIMessageRemoteAttachmentRoots, c as resolveConfigSnapshotHash, h as resolveTelegramCustomCommands, i as loadConfig, j as setConfigValueAtPath, k as getConfigValueAtPath, l as writeConfigFile, m as normalizeTelegramCommandName, o as readConfigFileSnapshot, p as TELEGRAM_COMMAND_NAME_PATTERN, u as validateConfigObjectWithPlugins, w as validateJsonSchemaValue, x as normalizeScpRemoteHost, y as resolveIMessageAttachmentRoots, z as resolveAgentMaxConcurrent } from "./config-PQiujvsf.js";
import { a as isPathInsideWithRealpath } from "./legacy-names-DyDKpCnk.js";
import { a as safeStatSync, c as applyTestPluginDefaults, d as resolveEnableState, f as resolveMemorySlotDecision, i as isPathInside, n as loadPluginManifestRegistry, r as discoverOpenClawPlugins, u as normalizePluginsConfig } from "./manifest-registry-4k4vkhPS.js";
import { t as normalizeChatType } from "./chat-type-DyovJwCt.js";
import { n as resolveConversationLabel } from "./conversation-label-Bn5j3lUT.js";
import { r as normalizeInboundTextNewlines, t as finalizeInboundContext } from "./inbound-context-CmmmT8IP.js";
import { _ as applyTemplate, a as resolveMediaAttachmentLocalRoots, c as resolveAttachmentKind, d as registerUnhandledRejectionHandler, f as resolveConcurrency, g as CLI_OUTPUT_MAX_BUFFER, h as resolveMediaUnderstandingScope, i as resolveAutoImageModel, l as buildRandomTempFilePath, m as normalizeMediaUnderstandingChatType, n as createMediaAttachmentCache, o as runCapability, p as resolveTimeoutMs, r as normalizeMediaAttachments, t as buildProviderRegistry } from "./runner-U04aiHHC.js";
import { _ as stripThinkingTagsFromText, a as decodeDataUrl, b as minimaxUnderstandImage, c as extractAssistantThinking, d as formatReasoningMessage, f as inferToolMetaFromArgs, g as stripMinimaxToolCallXml, h as stripDowngradedToolCallText, i as coerceImageModelConfig, l as extractThinkingFromTaggedStream, m as promoteThinkingTagsToBlocks, o as resolveProviderVisionModelFromConfig, p as isAssistantMessage, r as coerceImageAssistantText, s as extractAssistantText$1, u as extractThinkingFromTaggedText, v as stripReasoningTagsFromText, y as extractTextFromChatContent } from "./image-DxEpBZim.js";
import { t as ensureOpenClawModelsJson } from "./models-config-B459BnCS.js";
import { n as discoverModels, t as discoverAuthStorage } from "./pi-model-discovery-4uUnLc3n.js";
import { A as isTransientHttpError, C as isContextOverflowError, D as isRateLimitAssistantError, E as isLikelyContextOverflowError, F as ensureSessionHeader, I as resolveBootstrapMaxChars, L as resolveBootstrapTotalMaxChars, M as parseImageSizeError, N as sanitizeUserFacingText, O as isRawApiErrorPayload, P as buildBootstrapContextFiles, R as sanitizeGoogleTurnOrdering, S as isCompactionFailureError, T as isFailoverErrorMessage, _ as formatRawAssistantErrorForUi, a as isMessagingToolDuplicateNormalized, b as isBillingAssistantError, c as extractToolCallsFromAssistant, d as isAntigravityClaude, f as isGoogleModelApi, g as formatBillingErrorMessage, h as formatAssistantErrorText, j as parseImageDimensionError, k as isTimeoutErrorMessage, l as extractToolResultId, 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 getApiErrorPayloadFingerprint, w as isFailoverAssistantError, x as isCloudCodeAssistFormatError, y as isAuthAssistantError } from "./pi-embedded-helpers-BdscQhyS.js";
import { C as compileGlobPatterns, S as stripPluginOnlyAllowlist, _ as expandPolicyWithPluginGroups, a as ensureSandboxWorkspaceForSession, b as normalizeToolName, c as resolveSandboxRuntimeStatus, d as resolveSandboxConfigForAgent, g as collectExplicitAllowlist, h as buildPluginToolGroups, m as applyOwnerOnlyToolPolicy, o as resolveSandboxContext, u as getBridgeAuthForPort, w as matchesAnyGlobPattern, x as resolveToolProfilePolicy, y as mergeAlsoAllowPolicy } from "./sandbox-UAzvS0V6.js";
import { c as detectMime, d as imageMimeFromFormat, f as isAudioFileName, g as MAX_IMAGE_BYTES, i as getImageMetadata, l as extensionForMime, p as isGifMedia, s as resizeToJpeg, v as mediaKindFromMime } from "./image-ops-CI1VknD1.js";
import { a as jsonResult, c as readReactionParams, d as readStringParam, g as resolveImageSanitizationLimits, h as sanitizeToolResultImages, i as imageResultFromFile, l as readStringArrayParam, m as sanitizeImageBlocks, n as createActionGate, o as parseAvailableTags, r as imageResult, s as readNumberParam, u as readStringOrNumberParam } from "./common-a25M2Kvi.js";
import { T as DEFAULT_AI_SNAPSHOT_MAX_CHARS } from "./chrome-Dd5zBIFu.js";
import { i as resolveBrowserConfig, m as resolveBrowserControlAuth } from "./server-context-DAWsUNUs.js";
import { a as resolveSkillsPromptForRun, d as resolveSandboxInputPath, h as applySkillEnvOverridesFromSnapshot, i as loadWorkspaceSkillEntries, l as assertMediaNotDataUrl, m as applySkillEnvOverrides, p as resolveSandboxedMediaSource, r as buildWorkspaceSkillSnapshot, u as assertSandboxPath } from "./skills-CLmzWt48.js";
import { n as formatErrorMessage, r as formatUncaughtError } from "./errors-kfGqPQ4b.js";
import { i as resolveExistingPathsWithinRoot, r as DEFAULT_UPLOAD_DIR } from "./paths-D1WZUYry.js";
import { i as isBlockedHostnameOrIp, o as normalizeHostname, t as SsrFBlockedError } from "./ssrf-6f5m2MMA.js";
import { n as getMediaDir, r as saveMediaBuffer } from "./store-DSGYY-H9.js";
import { A as resolveSessionKey, B as resolveExplicitAgentSessionKey, F as resolveThreadFlag, G as buildGroupDisplayName, I as DEFAULT_RESET_TRIGGERS, K as resolveGroupSessionKey, L as resolveFreshSessionTotalTokens, M as resolveChannelResetConfig, N as resolveSessionResetPolicy, P as resolveSessionResetType, R as canonicalizeMainSessionAlias, S as capArrayByJsonBytes, T as readSessionTitleFieldsFromTranscript, U as deriveSessionMetaPatch, V as resolveMainSessionKey, Y as resolveSessionLockMaxHoldFromTimeout, _ as normalizeDeliveryContext, a as loadSessionStore, d as updateSessionStoreEntry, f as isCacheEnabled, g as mergeDeliveryContext, h as deliveryContextKey, j as evaluateSessionFreshness, l as updateLastRoute, m as deliveryContextFromSession, o as readSessionUpdatedAt, p as resolveCacheTtlMs$1, q as acquireSessionWriteLock, r as appendAssistantMessageToSessionTranscript, s as recordSessionMetaFromInbound, t as extractDeliveryInfo, u as updateSessionStore, v as normalizeSessionDeliveryFields, x as archiveSessionTranscripts, y as normalizeAccountId$4, z as resolveAgentMainSessionKey } from "./sessions-Z1BZU3xh.js";
import { a as resolveChannelGroupRequireMention, c as normalizeHyphenSlug, i as resolveChannelGroupPolicy, l as normalizeStringEntries, n as listChannelDocks, r as normalizeSignalMessagingTarget, s as normalizeAtHashSlug, t as getChannelDock, u as normalizeStringEntriesLower } from "./dock-7F-MiPtF.js";
import { a as listTelegramAccountIds, c as resolveSlackAccount, d as resolveSlackBotToken, f as createDiscordActionGate, h as normalizeDiscordToken, i as listEnabledTelegramAccounts, m as resolveDiscordAccount, n as normalizeWhatsAppTarget, o as resolveTelegramAccount, p as listEnabledDiscordAccounts, r as createTelegramActionGate, s as resolveTelegramToken, t as isWhatsAppGroupJid, u as resolveSlackAppToken } from "./normalize-Ci8UyR3Z.js";
import { a as logWebSelfId, i as getWebAuthAgeMs, m as webAuthExists, n as resolveWhatsAppAccount, o as logoutWeb, u as readWebSelfId } from "./accounts-Bj1dJ-fd.js";
import { t as resolveIMessageAccount } from "./accounts-DOl1Wkxo.js";
import { n as resolveSignalAccount, t as listEnabledSignalAccounts } from "./accounts-t6R5_PzC.js";
import { a as resolveSlackWebClientOptions, c as buildSlackBlocksFallbackText, i as createSlackWebClient, l as parseSlackTarget, o as parseSlackBlocksInput, s as validateSlackBlocksArray, t as sendMessageSlack, u as resolveSlackChannelId } from "./send-uu2Jc-Js.js";
import { n as listChannelPlugins, r as normalizeChannelId$1, t as getChannelPlugin } from "./plugins-CKbXkuXd.js";
import { c as resolveStorePath, i as resolveSessionTranscriptPath, n as resolveSessionFilePath, r as resolveSessionFilePathOptions, t as resolveDefaultSessionStorePath } from "./paths-C2NfoGZE.js";
import { i as normalizeInputProvenance, n as applyInputProvenanceToUserMessage, r as hasInterSessionUserProvenance } from "./input-provenance-DkoU-lPU.js";
import { t as emitSessionTranscriptUpdate } from "./transcript-events-BwQWL-Af.js";
import { n as resolveToolDisplay } from "./tool-display-Bx4M6uNT.js";
import { n as fetchWithTimeout, t as bindAbortRelay } from "./fetch-timeout-DoySHqfO.js";
import { t as fetchWithSsrFGuard } from "./fetch-guard-C1sYsWgl.js";
import { a as readResponseWithLimit, i as fetchRemoteMedia, n as getDefaultMediaLocalRoots, t as getAgentScopedMediaLocalRoots } from "./local-roots-DiDvXIIo.js";
import { v as runTasksWithConcurrency } from "./sqlite-JcMMx8Z5.js";
import { n as loadModelCatalog, r as modelSupportsVision, t as findModelInCatalog } from "./model-catalog-CIixTnGt.js";
import { n as SILENT_REPLY_TOKEN, r as isSilentReplyText, t as HEARTBEAT_TOKEN } from "./tokens-D4lZk7-h.js";
import { n as createBrowserRouteDispatcher, r as getMachineDisplayName, t as withTimeout$4 } from "./with-timeout-DijiQjw6.js";
import { C as getGlobalHookRunner, S as throwIfAborted, _ as normalizeTargetForProvider, a as normalizeOutboundPayloadsForJson, b as splitMediaFromOutput, c as applyReplyThreading, d as isRenderablePayload, f as shouldSuppressMessagingToolReplies, g as normalizeChannelTargetInput, h as buildTargetResolverSignature, i as normalizeOutboundPayloads, l as filterMessagingToolDuplicates, m as resolveReplyToMode, o as normalizeReplyPayloadsForDelivery, p as createReplyToModeFilterForChannel, r as formatOutboundPayloadLog, s as applyReplyTagsToPayload, t as deliverOutboundPayloads, u as filterMessagingToolMediaDuplicates, v as parseReplyDirectives, w as initializeGlobalHookRunner, x as parseInlineDirectives$1, y as MEDIA_TOKEN_RE } from "./deliver-DgvS3uCz.js";
import { a as logMessageProcessed, c as logWebhookError, d as startDiagnosticHeartbeat, f as stopDiagnosticHeartbeat, i as logLaneEnqueue, l as logWebhookProcessed, m as isDiagnosticsEnabled, o as logMessageQueued, p as emitDiagnosticEvent, r as logLaneDequeue, s as logSessionStateChange, t as diag, u as logWebhookReceived } from "./diagnostic-UUwku4RV.js";
import { r as getDiagnosticSessionState } from "./diagnostic-session-state-ByqoIyGn.js";
import { A as hasBotMention, B as resolveSenderAllowMatch, C as buildTelegramGroupPeerId, D as describeReplyTarget, E as buildTypingThreadParams, F as resolveTelegramReplyId, G as toLocationContext, H as isSenderIdAllowed, I as resolveTelegramStreamMode, J as parseTelegramTarget, K as withTelegramApiErrorLogging, L as resolveTelegramThreadSpec, M as resolveTelegramForumThreadId, N as resolveTelegramGroupAllowFromContext, O as expandTextLinks, P as resolveTelegramMediaPlaceholder, R as isSenderAllowed$1, S as buildTelegramGroupFrom, T as buildTelegramThreadParams, U as mergeAllowFromSources, V as firstDefined$1, W as formatLocationText, Y as resolveTelegramTargetChatType, _ as resolveTelegramFetch, a as reactMessageTelegram, b as buildSenderLabel, c as sendStickerTelegram, d as wasSentByBot, f as isRecoverableTelegramNetworkError, g as wrapFileReferencesInHtml, h as renderTelegramHtmlText, i as editMessageTelegram, j as normalizeForwardedContext, k as extractTelegramLocation, m as markdownToTelegramHtml, n as createForumTopicTelegram, o as sendMessageTelegram, p as markdownToTelegramChunks, q as isVoiceCompatibleAudio, r as deleteMessageTelegram, s as sendPollTelegram, t as buildInlineKeyboard, u as resolveTelegramVoiceSend, v as splitTelegramCaption, w as buildTelegramParentPeer, x as buildSenderName, y as buildGroupLabel, z as normalizeAllowFromWithStore$1 } from "./send-DbwyyQAv.js";
import { a as buildModelAliasLines, n as resolveModel } from "./model-VbWjwqaW.js";
import { i as resolveAckReaction, o as resolveEffectiveMessagesConfig, r as resolveResponsePrefixTemplate, s as resolveHumanDelayConfig, t as createReplyPrefixOptions } from "./reply-prefix-DAK7-zK4.js";
import { i as resolveMemoryBackendConfig, n as registerMemoryCli, r as getMemorySearchManager } from "./memory-cli-DxmtLhh_.js";
import { n as resolveMemorySearchConfig } from "./manager-C0teWocQ.js";
import { n as retryAsync } from "./retry-rUEdE6zT.js";
import { a as chunkText, c as resolveChunkMode, d as isSafeFenceBreak, f as parseFenceSpans, i as chunkMarkdownTextWithMode, l as resolveTextChunkLimit, o as chunkTextWithMode, r as chunkMarkdownText, t as chunkByNewline, u as findFenceSpanAt } from "./chunk-CMylpCPi.js";
import { n as resolveMarkdownTableMode } from "./markdown-tables-B9VGUdDc.js";
import { a as loadWebMedia, i as getDefaultLocalRoots } from "./ir-24qCLTKH.js";
import { a as listChatCommandsForConfig, c as normalizeCommandBody, d as resolveCommandArgMenu, f as serializeCommandArgs, i as listChatCommands, l as parseCommandArgs, o as listNativeCommandSpecs, p as shouldHandleTextCommands, r as findCommandByNativeName, s as listNativeCommandSpecsForConfig, t as buildCommandTextFromArgs, u as resolveCommandArgChoices } from "./commands-registry-bb_U-3FM.js";
import { Mt as SESSION_LABEL_MAX_LENGTH, t as GatewayClient } from "./client-BdSkEtCd.js";
import { a as randomIdempotencyKey, d as resolveLeastPrivilegeOperatorScopesForMethod, n as callGateway, r as callGatewayLeastPrivilege, t as buildGatewayConnectionDetails } from "./call-BCz_8mqq.js";
import { n as formatTimeAgo } from "./format-relative-DdvuDKIv.js";
import { n as normalizePollInput } from "./polls-CdvQ578Y.js";
import { n as recordChannelActivity, r as createDiscordRetryRunner, t as getChannelActivity } from "./channel-activity-DynIQUB_.js";
import { n as wrapFetchWithAbortSignal, t as resolveFetch } from "./fetch-Bu5zBCce.js";
import { t as convertMarkdownTables } from "./tables-C70h_80U.js";
import { c as signalRpcRequest, l as streamSignalEvents, n as sendReadReceiptSignal, o as resolveSignalRpcContext, r as sendTypingSignal, s as signalCheck, t as sendMessageSignal } from "./send-CAfFUUkm.js";
import { i as readChannelAllowFromStore, l as listPairingChannels, o as removeChannelAllowFromStoreEntry, s as upsertChannelPairingRequest, t as addChannelAllowFromStoreEntry } from "./pairing-store-T5DpOfoL.js";
import { t as makeProxyFetch } from "./proxy-BiOWrea2.js";
import { i as formatDurationSeconds, r as formatDurationPrecise, t as formatDurationCompact$1 } from "./format-duration-pIcWg99c.js";
import { n as resolveAgentRoute, t as buildAgentSessionKey } from "./resolve-route-2TU_aaLs.js";
import { a as createReplyReferencePlanner, i as resolveSlackThreadTs, n as deliverReplies$3, t as createSlackReplyDeliveryPlan } from "./replies-NhrZJ3yf.js";
import { b as ensureSkillsWatcher, i as resolveSkillCommandInvocation, n as listSkillCommandsForAgents, o as getRemoteSkillEligibility, r as listSkillCommandsForWorkspace, t as listReservedChatSlashCommandNames, x as getSkillsSnapshotVersion } from "./skill-commands-N8Sho46-.js";
import { a as resolveSubagentToolPolicy, c as isRestartEnabled, i as resolveGroupToolPolicy, l as resolveNativeCommandsEnabled, n as isToolAllowedByPolicies, r as resolveEffectiveToolPolicy, s as isNativeCommandsExplicitlyDisabled, t as filterToolsByPolicy, u as resolveNativeSkillsEnabled } from "./pi-tools.policy-DTy1DnPK.js";
import { c as hasNonzeroUsage, l as normalizeUsage, n as loadCostUsageSummary, o as derivePromptTokens, r as loadSessionCostSummary, s as deriveSessionTotalTokens } from "./session-cost-usage-BlUDaylg.js";
import { a as normalizeIMessageHandle, c as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS, i as isAllowedIMessageSender, o as parseIMessageTarget, r as formatIMessageChatTarget, s as createIMessageRpcClient, t as sendMessageIMessage } from "./send-4LoRaltQ.js";
import { r as detectBinary } from "./onboard-helpers-DbjfBSMX.js";
import { t as resolvePairingIdLabel } from "./pairing-labels-DaESq9ML.js";
import { i as resolveModelCostConfig, n as formatTokenCount$2, r as formatUsd, t as estimateUsageCost } from "./usage-format-BzKEDn0q.js";
import { t as getActiveWebListener } from "./active-listener-CQFe2moz.js";
import { _ as getTrustedSafeBinDirs, b as buildSafeShellCommand, d as resolveExecApprovals, f as resolveExecApprovalsFromFile, g as resolveSafeBins, h as evaluateShellAllowlist, i as maxAsk, l as recordAllowlistUse, n as addAllowlistEntry, o as minSecurity, u as requiresExecApproval, y as buildSafeBinsShellCommand } from "./exec-approvals-q0C8VDMT.js";
import { a as canvasSnapshotTempPath, c as parseCameraClipPayload, d as writeCameraClipPayloadToFile, f as writeUrlToFile, g as normalizePathPrepend, h as mergePathPrepend, i as parseEnvPairs, l as parseCameraSnapPayload, m as applyPathPrepend, n as screenRecordTempPath, o as parseCanvasSnapshotPayload, p as buildNodeShellCommand, r as writeScreenRecordToFile, s as cameraTempPath, t as parseScreenRecordPayload, u as writeBase64ToFile } from "./nodes-screen-5fMfTT2n.js";
import { n as parseNodeList, r as parsePairingList, t as resolveNodeIdFromCandidates } from "./node-match-CN8o4Vi3.js";
import { n as recordCommandPoll, r as resetCommandPollCount } from "./command-poll-backoff-BiwOFDEK.js";
import { n as createBrowserControlContext, r as startBrowserControlServiceFromConfig } from "./control-service-BoO2TGOx.js";
import { i as parseAbsoluteTimeMs, r as resolveDefaultCronStaggerMs, t as normalizeCronStaggerMs } from "./stagger-B6VQyn1F.js";
import { c as resolveGatewayLaunchAgentLabel, d as resolveGatewaySystemdServiceName } from "./constants-CEbQvI8z.js";
import { n as resolveMessageChannelSelection, t as listConfiguredMessageChannels } from "./channel-selection-DuDSoVSC.js";
import { t as parseTimeoutMs } from "./parse-timeout-UOA56UND.js";
import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import fs, { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
import os, { homedir } from "node:os";
import path from "node:path";
import JSON5 from "json5";
import fs$1 from "node:fs/promises";
import { execFileSync, spawn, spawnSync } from "node:child_process";
import { inspect } from "node:util";
import crypto, { randomBytes, randomUUID } from "node:crypto";
import { complete, completeSimple, streamSimple } from "@mariozechner/pi-ai";
import { CURRENT_SESSION_VERSION, DefaultResourceLoader, SessionManager, SettingsManager, codingTools, createAgentSession, createEditTool, createReadTool, createWriteTool, estimateTokens, generateSummary, readTool } from "@mariozechner/pi-coding-agent";
import { createServer } from "node:http";
import { ProxyAgent, fetch as fetch$1 } from "undici";
import WebSocket from "ws";
import { Buffer as Buffer$1 } from "node:buffer";
import { EdgeTTS } from "node-edge-tts";
import { createJiti } from "jiti";
import { Type } from "@sinclair/typebox";
import { ApplicationCommandOptionType, ButtonStyle, ChannelType, PermissionFlagsBits, Routes, StickerFormatType } from "discord-api-types/v10";
import { Button, ChannelSelectMenu, ChannelType as ChannelType$1, Client, Command, CommandWithSubcommands, Container, MentionableSelectMenu, MessageCreateListener, MessageReactionAddListener, MessageReactionRemoveListener, MessageType, Modal, PresenceUpdateListener, ReadyListener, RoleSelectMenu, Row, Separator, StringSelectMenu, TextDisplay, UserSelectMenu, serializePayload } from "@buape/carbon";
import { API_CONSTANTS, Bot, GrammyError, InputFile, webhookCallback } from "grammy";
import { GatewayCloseCodes, GatewayIntents, GatewayPlugin } from "@buape/carbon/gateway";
import { VoicePlugin } from "@buape/carbon/voice";
import { AudioPlayerStatus, EndBehaviorType, VoiceConnectionStatus, createAudioPlayer, createAudioResource, entersState, joinVoiceChannel } from "@discordjs/voice";
import { HttpsProxyAgent } from "https-proxy-agent";
import { setTimeout as setTimeout$1 } from "node:timers/promises";
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/directive-parsing.ts
function skipDirectiveArgPrefix(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;
}
return i;
}
function takeDirectiveToken(raw, startIndex) {
let i = startIndex;
const len = raw.length;
while (i < len && /\s/.test(raw[i])) i += 1;
if (i >= len) return {
token: null,
nextIndex: i
};
const start = i;
while (i < len && !/\s/.test(raw[i])) i += 1;
if (start === i) return {
token: null,
nextIndex: i
};
const token = raw.slice(start, i);
while (i < len && /\s/.test(raw[i])) i += 1;
return {
token,
nextIndex: i
};
}
//#endregion
//#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) {
const len = raw.length;
let i = skipDirectiveArgPrefix(raw);
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 = () => {
const res = takeDirectiveToken(raw, i);
i = res.nextIndex;
return res.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 matchLevelDirective = (body, names) => {
const namePattern = names.map(escapeRegExp).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).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 MAX_SAFE_TIMEOUT_MS = 2147e6;
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 clampTimeoutMs = (valueMs) => Math.min(Math.max(valueMs, minMs), MAX_SAFE_TIMEOUT_MS);
const defaultMs = clampTimeoutMs(resolveAgentTimeoutSeconds(opts.cfg) * 1e3);
const NO_TIMEOUT_MS = MAX_SAFE_TIMEOUT_MS;
const overrideMs = normalizeNumber(opts.overrideMs);
if (overrideMs !== void 0) {
if (overrideMs === 0) return NO_TIMEOUT_MS;
if (overrideMs < 0) return defaultMs;
return clampTimeoutMs(overrideMs);
}
const overrideSeconds = normalizeNumber(opts.overrideSeconds);
if (overrideSeconds !== void 0) {
if (overrideSeconds === 0) return NO_TIMEOUT_MS;
if (overrideSeconds < 0) return defaultMs;
return clampTimeoutMs(overrideSeconds * 1e3);
}
return defaultMs;
}
//#endregion
//#region src/channels/model-overrides.ts
const THREAD_SUFFIX_REGEX$1 = /:(?:thread|topic):[^:]+$/i;
function resolveProviderEntry(modelByChannel, channel) {
const normalized = normalizeMessageChannel(channel) ?? channel.trim().toLowerCase();
return modelByChannel?.[normalized] ?? modelByChannel?.[Object.keys(modelByChannel ?? {}).find((key) => {
return (normalizeMessageChannel(key) ?? key.trim().toLowerCase()) === normalized;
}) ?? ""];
}
function resolveParentGroupId(groupId) {
const raw = groupId?.trim();
if (!raw || !THREAD_SUFFIX_REGEX$1.test(raw)) return;
const parent = raw.replace(THREAD_SUFFIX_REGEX$1, "").trim();
return parent && parent !== raw ? parent : void 0;
}
function resolveGroupIdFromSessionKey(sessionKey) {
const raw = sessionKey?.trim();
if (!raw) return;
return (parseAgentSessionKey(raw)?.rest ?? raw).match(/(?:^|:)(?:group|channel):([^:]+)(?::|$)/i)?.[1]?.trim() || void 0;
}
function buildChannelCandidates(params) {
const groupId = params.groupId?.trim();
const parentGroupId = resolveParentGroupId(groupId);
const parentGroupIdFromSession = resolveGroupIdFromSessionKey(params.parentSessionKey);
const parentGroupIdResolved = resolveParentGroupId(parentGroupIdFromSession) ?? parentGroupIdFromSession;
const groupChannel = params.groupChannel?.trim();
const groupSubject = params.groupSubject?.trim();
const channelBare = groupChannel ? groupChannel.replace(/^#/, "") : void 0;
const subjectBare = groupSubject ? groupSubject.replace(/^#/, "") : void 0;
return buildChannelKeyCandidates(groupId, parentGroupId, parentGroupIdResolved, groupChannel, channelBare, channelBare ? normalizeChannelSlug(channelBare) : void 0, groupSubject, subjectBare, subjectBare ? normalizeChannelSlug(subjectBare) : void 0);
}
function resolveChannelModelOverride(params) {
const channel = params.channel?.trim();
if (!channel) return null;
const modelByChannel = params.cfg.channels?.modelByChannel;
if (!modelByChannel) return null;
const providerEntries = resolveProviderEntry(modelByChannel, channel);
if (!providerEntries) return null;
const candidates = buildChannelCandidates(params);
if (candidates.length === 0) return null;
const match = resolveChannelEntryMatchWithFallback({
entries: providerEntries,
keys: candidates,
wildcardKey: "*",
normalizeKey: (value) => value.trim().toLowerCase()
});
const raw = match.entry ?? match.wildcardEntry;
if (typeof raw !== "string") return null;
const model = raw.trim();
if (!model) return null;
return {
channel: normalizeMessageChannel(channel) ?? channel.trim().toLowerCase(),
model,
matchKey: match.matchKey,
matchSource: match.matchSource
};
}
//#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/channels/allowlist-match.ts
function formatAllowlistMatchMeta(match) {
return `matchKey=${match?.matchKey ?? "none"} matchSource=${match?.matchSource ?? "none"}`;
}
//#endregion
//#region src/link-understanding/defaults.ts
const DEFAULT_LINK_TIMEOUT_SECONDS = 30;
const DEFAULT_MAX_LINKS = 3;
//#endregion
//#region src/link-understanding/detect.ts
const MARKDOWN_LINK_RE = /\[[^\]]*]\((https?:\/\/\S+?)\)/gi;
const BARE_LINK_RE = /https?:\/\/\S+/gi;
function stripMarkdownLinks(message) {
return message.replace(MARKDOWN_LINK_RE, " ");
}
function resolveMaxLinks(value) {
if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
return DEFAULT_MAX_LINKS;
}
function isAllowedUrl(raw) {
try {
const parsed = new URL(raw);
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
if (isBlockedHostnameOrIp(parsed.hostname)) return false;
return true;
} catch {
return false;
}
}
function extractLinksFromMessage(message, opts) {
const source = message?.trim();
if (!source) return [];
const maxLinks = resolveMaxLinks(opts?.maxLinks);
const sanitized = stripMarkdownLinks(source);
const seen = /* @__PURE__ */ new Set();
const results = [];
for (const match of sanitized.matchAll(BARE_LINK_RE)) {
const raw = match[0]?.trim();
if (!raw) continue;
if (!isAllowedUrl(raw)) continue;
if (seen.has(raw)) continue;
seen.add(raw);
results.push(raw);
if (results.length >= maxLinks) break;
}
return results;
}
//#endregion
//#region src/link-understanding/runner.ts
function resolveScopeDecision(params) {
return resolveMediaUnderstandingScope({
scope: params.config?.scope,
sessionKey: params.ctx.SessionKey,
channel: params.ctx.Surface ?? params.ctx.Provider,
chatType: normalizeMediaUnderstandingChatType(params.ctx.ChatType)
});
}
function resolveTimeoutMsFromConfig(params) {
return resolveTimeoutMs(params.entry.timeoutSeconds ?? params.config?.timeoutSeconds, DEFAULT_LINK_TIMEOUT_SECONDS);
}
async function runCliEntry(params) {
if ((params.entry.type ?? "cli") !== "cli") return null;
const command = params.entry.command.trim();
if (!command) return null;
const args = params.entry.args ?? [];
const timeoutMs = resolveTimeoutMsFromConfig({
config: params.config,
entry: params.entry
});
const templCtx = {
...params.ctx,
LinkUrl: params.url
};
const argv = [command, ...args].map((part, index) => index === 0 ? part : applyTemplate(part, templCtx));
if (shouldLogVerbose()) logVerbose(`Link understanding via CLI: ${argv.join(" ")}`);
const { stdout } = await runExec(argv[0], argv.slice(1), {
timeoutMs,
maxBuffer: CLI_OUTPUT_MAX_BUFFER
});
return stdout.trim() || null;
}
async function runLinkEntries(params) {
let lastError;
for (const entry of params.entries) try {
const output = await runCliEntry({
entry,
ctx: params.ctx,
url: params.url,
config: params.config
});
if (output) return output;
} catch (err) {
lastError = err;
if (shouldLogVerbose()) logVerbose(`Link understanding failed for ${params.url}: ${String(err)}`);
}
if (lastError && shouldLogVerbose()) logVerbose(`Link understanding exhausted for ${params.url}`);
return null;
}
async function runLinkUnderstanding(params) {
const config = params.cfg.tools?.links;
if (!config || config.enabled === false) return {
urls: [],
outputs: []
};
if (resolveScopeDecision({
config,
ctx: params.ctx
}) === "deny") {
if (shouldLogVerbose()) logVerbose("Link understanding disabled by scope policy.");
return {
urls: [],
outputs: []
};
}
const links = extractLinksFromMessage(params.message ?? params.ctx.CommandBody ?? params.ctx.RawBody ?? params.ctx.Body ?? "", { maxLinks: config?.maxLinks });
if (links.length === 0) return {
urls: [],
outputs: []
};
const entries = config?.models ?? [];
if (entries.length === 0) return {
urls: links,
outputs: []
};
const outputs = [];
for (const url of links) {
const output = await runLinkEntries({
entries,
ctx: params.ctx,
url,
config
});
if (output) outputs.push(output);
}
return {
urls: links,
outputs
};
}
//#endregion
//#region src/link-understanding/apply.ts
async function applyLinkUnderstanding(params) {
const result = await runLinkUnderstanding({
cfg: params.cfg,
ctx: params.ctx
});
if (result.outputs.length === 0) return result;
params.ctx.LinkUnderstanding = [...params.ctx.LinkUnderstanding ?? [], ...result.outputs];
params.ctx.Body = formatLinkUnderstandingBody({
body: params.ctx.Body,
outputs: result.outputs
});
finalizeInboundContext(params.ctx, {
forceBodyForAgent: true,
forceBodyForCommands: true
});
return result;
}
//#endregion
//#region src/media/base64.ts
function estimateBase64DecodedBytes(base64) {
let effectiveLen = 0;
for (let i = 0; i < base64.length; i += 1) {
if (base64.charCodeAt(i) <= 32) continue;
effectiveLen += 1;
}
if (effectiveLen === 0) return 0;
let padding = 0;
let end = base64.length - 1;
while (end >= 0 && base64.charCodeAt(end) <= 32) end -= 1;
if (end >= 0 && base64[end] === "=") {
padding = 1;
end -= 1;
while (end >= 0 && base64.charCodeAt(end) <= 32) end -= 1;
if (end >= 0 && base64[end] === "=") padding = 2;
}
const estimated = Math.floor(effectiveLen * 3 / 4) - padding;
return Math.max(0, estimated);
}
//#endregion
//#region src/media/input-files.ts
let canvasModulePromise = null;
let pdfJsModulePromise = null;
async function loadCanvasModule() {
if (!canvasModulePromise) canvasModulePromise = import("@napi-rs/canvas").catch((err) => {
canvasModulePromise = null;
throw new Error(`Optional dependency @napi-rs/canvas is required for PDF image extraction: ${String(err)}`);
});
return canvasModulePromise;
}
async function loadPdfJsModule() {
if (!pdfJsModulePromise) pdfJsModulePromise = import("pdfjs-dist/legacy/build/pdf.mjs").catch((err) => {
pdfJsModulePromise = null;
throw new Error(`Optional dependency pdfjs-dist is required for PDF extraction: ${String(err)}`);
});
return pdfJsModulePromise;
}
const DEFAULT_INPUT_IMAGE_MIMES = [
"image/jpeg",
"image/png",
"image/gif",
"image/webp"
];
const DEFAULT_INPUT_FILE_MIMES = [
"text/plain",
"text/markdown",
"text/html",
"text/csv",
"application/json",
"application/pdf"
];
const DEFAULT_INPUT_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
const DEFAULT_INPUT_FILE_MAX_BYTES = 5 * 1024 * 1024;
const DEFAULT_INPUT_FILE_MAX_CHARS = 2e5;
const DEFAULT_INPUT_MAX_REDIRECTS = 3;
const DEFAULT_INPUT_TIMEOUT_MS = 1e4;
const DEFAULT_INPUT_PDF_MAX_PAGES = 4;
const DEFAULT_INPUT_PDF_MAX_PIXELS = 4e6;
const DEFAULT_INPUT_PDF_MIN_TEXT_CHARS = 200;
function rejectOversizedBase64Payload(params) {
const estimated = estimateBase64DecodedBytes(params.data);
if (estimated > params.maxBytes) throw new Error(`${params.label} too large: ${estimated} bytes (limit: ${params.maxBytes} bytes)`);
}
function normalizeMimeType(value) {
if (!value) return;
const [raw] = value.split(";");
return raw?.trim().toLowerCase() || void 0;
}
function parseContentType(value) {
if (!value) return {};
const parts = value.split(";").map((part) => part.trim());
return {
mimeType: normalizeMimeType(parts[0]),
charset: parts.map((part) => part.match(/^charset=(.+)$/i)?.[1]?.trim()).find((part) => part && part.length > 0)
};
}
function normalizeMimeList(values, fallback) {
const input = values && values.length > 0 ? values : fallback;
return new Set(input.map((value) => normalizeMimeType(value)).filter(Boolean));
}
function resolveInputFileLimits(config) {
return {
allowUrl: config?.allowUrl ?? true,
allowedMimes: normalizeMimeList(config?.allowedMimes, DEFAULT_INPUT_FILE_MIMES),
maxBytes: config?.maxBytes ?? DEFAULT_INPUT_FILE_MAX_BYTES,
maxChars: config?.maxChars ?? DEFAULT_INPUT_FILE_MAX_CHARS,
maxRedirects: config?.maxRedirects ?? DEFAULT_INPUT_MAX_REDIRECTS,
timeoutMs: config?.timeoutMs ?? DEFAULT_INPUT_TIMEOUT_MS,
pdf: {
maxPages: config?.pdf?.maxPages ?? DEFAULT_INPUT_PDF_MAX_PAGES,
maxPixels: config?.pdf?.maxPixels ?? DEFAULT_INPUT_PDF_MAX_PIXELS,
minTextChars: config?.pdf?.minTextChars ?? DEFAULT_INPUT_PDF_MIN_TEXT_CHARS
}
};
}
async function fetchWithGuard(params) {
const { response, release } = await fetchWithSsrFGuard({
url: params.url,
maxRedirects: params.maxRedirects,
timeoutMs: params.timeoutMs,
policy: params.policy,
auditContext: params.auditContext,
init: { headers: { "User-Agent": "OpenClaw-Gateway/1.0" } }
});
try {
if (!response.ok) throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`);
const contentLength = response.headers.get("content-length");
if (contentLength) {
const size = Number(contentLength);
if (Number.isFinite(size) && size > params.maxBytes) throw new Error(`Content too large: ${size} bytes (limit: ${params.maxBytes} bytes)`);
}
const buffer = await readResponseWithLimit(response, params.maxBytes);
const contentType = response.headers.get("content-type") || void 0;
return {
buffer,
mimeType: parseContentType(contentType).mimeType ?? "application/octet-stream",
contentType
};
} finally {
await release();
}
}
function decodeTextContent(buffer, charset) {
const encoding = charset?.trim().toLowerCase() || "utf-8";
try {
return new TextDecoder(encoding).decode(buffer);
} catch {
return new TextDecoder("utf-8").decode(buffer);
}
}
function clampText(text, maxChars) {
if (text.length <= maxChars) return text;
return text.slice(0, maxChars);
}
async function extractPdfContent(params) {
const { buffer, limits } = params;
const { getDocument } = await loadPdfJsModule();
const pdf = await getDocument({
data: new Uint8Array(buffer),
disableWorker: true
}).promise;
const maxPages = Math.min(pdf.numPages, limits.pdf.maxPages);
const textParts = [];
for (let pageNum = 1; pageNum <= maxPages; pageNum += 1) {
const pageText = (await (await pdf.getPage(pageNum)).getTextContent()).items.map((item) => "str" in item ? String(item.str) : "").filter(Boolean).join(" ");
if (pageText) textParts.push(pageText);
}
const text = tex