/** * Language code validation * * The active language is derived by an LLM from what the caller says, so it * is caller-influenced data and must never reach a filesystem path or an * object index unchecked. Every entry point that accepts a language code * (context storage, phrase loading, voice lookup) narrows it through * `isValidLanguageCode` first. */ /** The language used whenever a code is missing or fails validation. */ export declare const DEFAULT_LANGUAGE = "en"; /** True for a well-formed language code, false for anything else. */ export declare function isValidLanguageCode(language: unknown): language is string; /** * Return the code when it is well-formed, otherwise `en` with a warning. * `where` names the caller so a rejected code is traceable in the logs. */ export declare function normalizeLanguage(language: unknown, where: string): string; /** Which language to reply in, and whether that differs from what was detected. */ export interface ReplyLanguageResolution { replyLanguage: string; mismatch: boolean; } /** * Narrow a detected language down to one `processOutgoing` is willing to * reply in, per `TalkerConfig.replyLanguages`. * * Detection stays unrestricted regardless of this config - a caller in any * language is still understood - this only picks the reply language. * `replyLanguages` unset or empty: unrestricted, the detected language * passes through untouched and `mismatch` is always false, so unconfigured * behavior is unchanged. Set: an exact match replies in kind; anything else * falls back to the list's first (default) entry with `mismatch: true`, so * the caller hosting the reply can prepend a short acknowledgment. * * Matching is exact, so `replyLanguages` entries must be the codes detection * actually emits (`en`, `pt-BR`, ...), the same shape `isValidLanguageCode` * accepts. `normalizeReplyLanguages` puts a configured list into that shape * once, at mount time, so `'EN'` cannot reach here and silently narrow every * reply to a language that never matches. */ export declare function resolveReplyLanguage(detectedLanguage: string, replyLanguages?: string[]): ReplyLanguageResolution; /** * Put a configured `TalkerConfig.replyLanguages` into the shape * `resolveReplyLanguage` matches against, once, at mount time. * * Matching there is exact, so an entry that is merely mis-cased (`'EN'`, * `'pt-br'`) matches nothing: every caller falls through to the list's first * entry with `mismatch: true`, and the operator sees every reply narrowed and * apologetic with no error anywhere to explain it. Casing is normalized here * rather than at match time so the fix is visible in one place and costs * nothing per request. * * An entry that cannot be a language code at all is dropped with a warning * rather than silently kept: keeping it would leave a value in the list that * can never match, and throwing would take down a mount over a typo in an * optional narrowing. A list with nothing valid left returns `undefined`, * which is the unrestricted default - the safer of the two readings, since * the alternative is replying to everyone in a code that resolves to nothing. */ export declare function normalizeReplyLanguages(replyLanguages?: string[]): string[] | undefined;