Utils and Helpers
Nội dung này hiện chưa có sẵn bằng ngôn ngữ của bạn.
This is a current map of shared utility modules under src/utils/.
Folder Map
Section titled “Folder Map”utils/asyncutils/audioutils/bridgesutils/cacheutils/chatutils/compactionutils/conditioningutils/dbutils/discordutils/documentsutils/embeddingsutils/imageutils/mcputils/mediautils/memoryutils/metricsutils/miscutils/novelaiutils/personautils/providerutils/quotautils/securityutils/storageutils/teachutils/textutils/tools
High-Impact Modules
Section titled “High-Impact Modules”utils/db
Section titled “utils/db”client.ts: DB client wiringinitializeDatabase.ts: schema + seed startup runnersqlSecurity.ts: query parameterisation helperssqlSplitter.ts: SQL file parsing utilitiesragAvailability.ts: pgvector / RAG feature detectionrepositories/: 28 domain-owned repository modules +index.ts(shared instance + type re-exports only). SQL remains in its owning module; no*ReadSql.ts/*WriteSql.tssibling files exist.ErrorLogRepositoryis a thin shim used bylogger.tsto insert intoerror_logswithout creating a circular import. Seedocs/en/architecture/subsystems/database-schema.mdfor the full repository table and SQL convention.
utils/discord
Section titled “utils/discord”commandLoader.ts: command discovery + localization wiringcommandRegistry.ts: runtime command maps used by handlersinteractionHelper.ts: compatibility barrel for grouped UI helpers inutils/discord/ui/; new code imports the owned UI module directlystreamOrchestrator.ts: public stream orchestration entry point backed by responsibility modules inutils/discord/stream/webhookManager.ts: compatibility barrel for grouped webhook helpers inutils/discord/webhook/; new code imports the owned webhook module directlyembedHelper.ts: shared embed builders and senders (createStandardEmbed,createSummaryEmbed,createTipText,sendStandardEmbed); see Tip modals belowtextDisplayModal.ts: reusable read-only text modal, trigger button, and collector wiringresolveSendableChannel.ts: cache-first, REST-fallback channel resolution for send paths, plusisChannelGoneErrorfor the deleted-channel and lost-access caseshistoryFetcher.ts,historyFormatter.ts
Sending into a channel the cache no longer holds
Section titled “Sending into a channel the cache no longer holds”resolveSendableChannel(client, channelId) returns the channel or the reason it could not be
reached, and reports a transient failure by throwing rather than flattening it into that reason.
Message#channel and Message#reply resolve through the client cache only, so discord.js raises
ChannelNotCached once an entry is gone. That happens both for a deleted channel and for one that
was never populated, and only a REST fetch separates them, so a long streaming turn re-resolves its
destination by id instead of trusting the Message it captured at admission.
Only two answers are terminal, and they are kept apart because they are different operator
problems: 10003 is a deleted channel, and 50001 (Missing Access) is one the bot can no longer
see. A rate limit, a 5xx, a timeout, or an abort is none of those and keeps its own error, so it
stays an ordinary send failure with its retry arms intact instead of stopping the stream.
isChannelGoneError(error) recognises both terminal answers, since a stopped stream is the same
verdict for each. The client-side ChannelNotCached is deliberately outside it: that says only
that the channel was absent from the local cache, which an uncached thread or an evicted DM entry
also produces, and the send path resolves that case with a fetch rather than reading it as a
deletion. classifySendFailure excludes it for the same reason, while still caching the
REST-confirmed 10003 as channel_gone for the admission gate.
Each terminal answer carries its own stop reason, so the log and the persisted StreamResult name
the condition that actually happened: a revoked grant reported as a deletion would send an operator
looking for a channel that still exists. Both stop reasons are internal requester ids, so they are
reaped at the end of the stream rather than aborting the next turn’s pre-stream check.
The resolved channel is written back onto the stream context. One stream sends many chunks, and only the first consults the reply target, so a context left pointing at a channel that cannot be sent into would break every later chunk.
Tip modals
Section titled “Tip modals”createTipText(locale, tipKeys, tipVars?) in embedHelper.ts builds the reusable markdown opened by
the What You Can Do button below an error (e.g. in stream/errorUi.ts and ui/interactionCore.ts).
- Each entry in
tipKeysis an atomic locale key resolved independently and rendered as its own dashed bullet (- item). Keys live undergenai.tips.*(see the Localization doc’s Tip-item keys convention). - Tips render in a read-only Discord text-display modal, so markdown and hyperlinks remain usable without adding another embed or ephemeral reply to the channel.
- Conditional tips are the caller’s job: include or omit a key inline (e.g. an OpenRouter-only
item) instead of maintaining whole-paragraph tip strings per branch. Items that resolve to empty
text are dropped, and the function returns
nullwhen nothing resolves, so the caller can skip attaching a tip button entirely. - The Official Support Server link is automatic:
genai.tips.support_server(exported asSUPPORT_SERVER_TIP_KEY) is appended as the last bullet of every rendered tip modal. Callers must not list it intipKeys; it is filtered out if they do, so it can never be duplicated or reordered. It is appended after the empty check, so a tip modal with no caller-supplied items still returnsnullrather than degrading into a support-link-only embed. - The button is disabled after
TIP_BUTTON_TIMEOUT_MS(default 24 hours). The generictextDisplayModal.tsbuilder is also available to read-only legal and help surfaces.
utils/text
Section titled “utils/text”localizer.ts: locale auto-discovery + lookupcontextBuilder.ts: public structured context routing and native orchestrationcontext/: context-builder support modules for types, template/conditioning blocks, memories, RAG, and history/media helperscontextTruncator.ts: token-budget truncation strategyprocessors/regexUtils.ts:escapeRegExpprocessors/mentionProcessor.ts: mention resolution, template variables, emoji normalizationprocessors/llmOutputProcessor.ts: LLM output cleaning, speaker-turn truncationprocessors/chunkProcessor.ts: message chunking, sentence splittingprocessors/formatters.ts: time formatting, text humanization, boolean displayprocessors/timeUtils.ts: reminder time parsing, lateness calculationemojiHelper.ts,emojiPenalty.tstimezoneHelper.ts,uncensor.ts,youTubeUrlCleaner.ts
utils/cache
Section titled “utils/cache”tomoriStateCache.tsuserCache.tsemojiStickerCache.tschannelLlmCache.ts,channelLlmCacheStore.tschannelWhitelistCache.tsshortTermMemoryCache.tsllmCache.tsopenrouterCatalog.ts: shared refresh machinery for the OpenRouter model catalogsopenrouterCapabilityCache.ts,openrouterEmbeddingModelCache.ts,openrouterImageModelCache.ts,openrouterVideoModelCache.tsgeminiCapabilityCache.tsnovelaiCapabilityCache.tsemergencyCacheClearer.ts: critical-memory cleanup for recoverable caches- lazy sync helpers (
emojiLazySync.ts,stickerLazySync.ts)
utils/security
Section titled “utils/security”secretsManager.ts:.envvs AWS Secrets Manager load pathkeyManager.ts: encryption key version managementcrypto.ts: encryption/decryption helperskeyRotation.ts: rotation workflowsrateLimiter.ts: upload quota cleanup schedulersafeDownload.ts: constrained external content downloadremoteUrlSecurity.ts: the single SSRF gate for user-supplied URLs (protocol/host policy, DNS resolution, blocklists)userRemoteFetch.ts: DNS-pinned fetch with per-hop redirect revalidation, built onremoteUrlSecurity.tscloudMetadata.ts: always-on cloud instance-metadata / link-local denylist
utils/quota
Section titled “utils/quota”imageQuotaManager.ts: per-user and server-wide image generation quotastextQuotaManager.ts: per-user and server-wide text trigger quotasvideoQuotaManager.ts: per-user and server-wide video generation quotas
utils/provider
Section titled “utils/provider”providerFactory.ts: provider auto-discovery and instance resolution
utils/mcp
Section titled “utils/mcp”mcpManager.ts: MCP lifecyclemcpExecutor.ts: MCP execution abstractionmcpConfig.ts: MCP config loading
Guild MCP URL validation lives in utils/security/remoteUrlSecurity.ts, which guards every user-supplied URL rather than MCP alone.
utils/bridges
Section titled “utils/bridges”bridgeUserId.ts: bridge ID and webhook username parsing utilitiesmatrix/: Matrix appservice bridge runtimematrix/events.ts: appservice init and Matrix inbound event surfacematrix/stateSync.ts: Matrix link cache, typing state, reminder mention surfacematrix/userMapping.ts: Matrix display-name/ID maps and persona intent surfacematrix/rooms.ts: Matrix room join/config/encryption helpersmatrix/index.ts: public Matrix exports grouped from the responsibility modules
New code should use utils/bridges for generic bridge helpers and utils/bridges/matrix for Matrix runtime operations.
utils/image and utils/storage
Section titled “utils/image and utils/storage”avatarHelper.ts,imageProcessor.ts,pngMetadata.tsavatarStorage.tsfor GCS or S3-compatible public avatar URL supportvoiceSampleStorage.tsfor GCS or S3-compatible voice sample storagecharrefStorage.tsfor NovelAI character reference storage (S3-compatible in production, local filesystem in non-production)S3_ENDPOINTenables Cloudflare R2 or another S3-compatible endpoint; when set, storage clients use path-style requests while public URLs still come from the relevant*_PUBLIC_BASE_URLvalue.
utils/misc
Section titled “utils/misc”logger.ts: structured logging facadeerrorContextStore.ts: ambient error identity (see below)ioHelper.ts: filesystem traversal helpershealthTracker.ts: runtime health signals used by/health
Ambient error context
Section titled “Ambient error context”log.error() and log.warn() accept an optional ErrorContext, but most call sites are far from
the code that knows which server or user they belong to. Threading that identity through every
signature is impractical, so errorContextStore.ts carries it out of band using an
AsyncLocalStorage scope.
The four entry points that begin a unit of work open a scope:
| Entry point | Opened in | source |
|---|---|---|
| Message chat turn | events/messageCreate/tomoriChat.ts | chat |
| Slash command | events/interactionCreate/handleCommands.ts | command |
| Scheduled reminder/task | timers/reminderProcessor.ts | reminder |
| Random trigger | timers/randomTriggerProcessor.ts | random_trigger |
Everything reached from inside a scope, at any await depth, logs with that identity attached. A provider adapter deep in a stream needs no plumbing to produce an attributable error record.
runWithErrorContext(identity, fn)opens a scope. Nested scopes inherit and override.enrichErrorContext(patch)upgrades the active scope once more IDs are known. Entry points seed Discord snowflakes; database row IDs are added after admission or user lookup resolves them.resolveErrorContext(explicit)is called by the logger. An explicit context wins per field, so a call site that names its own IDs stays authoritative.
Typed ErrorContext fields (serverId, userId, personaId) are database row IDs. Discord
snowflakes travel in metadata (serverDiscId, userDiscId, channelDiscId) alongside source
and sourceDetail, which identify the unit of work.
Timers and event handlers started outside a scope are unaffected, so background work that belongs to no server stays unattributed rather than inheriting a stale identity.
Usage Guidance
Section titled “Usage Guidance”- Prefer these shared modules over duplicating logic in commands/events.
- For user-facing responses, always pair utility usage with localization via
localizer(). - For DB writes touching cached data, invalidate the affected caches in the same code path.