export type IdentityType = 'user' | 'bot' | 'app' | 'unknown'; export interface IdentityRecord { openId: string; type: IdentityType; name?: string; email?: string; /** A successful contact API lookup, including a valid "no email" result. */ contactResolvedAt?: number; source: 'sender' | 'mention' | 'contact_api' | 'message_api' | 'bot_cross_ref' | 'bot_info'; updatedAt: number; } /** Best-effort flush on shutdown — pairs with the debounce above. */ export declare function flushIdentityCacheSync(): void; /** * Merge a partial identity record into the cache. Existing `name` and `email` * are preserved unless the incoming record carries a real value (no * clobbering). Existing `type` is only overridden when the incoming value is * more specific (anything other than `unknown`). */ export declare function recordIdentity(larkAppId: string, rec: { openId: string; type?: IdentityType; name?: string; email?: string; contactResolvedAt?: number; source?: IdentityRecord['source']; }): void; /** * Learn (open_id, name) pairs from a parsed message's mentions. Free path — * no API call. Mentions don't carry sender_type, so we leave `type` as * `unknown` and let a subsequent sender event (or bot cross-ref lookup) tighten * it. */ export declare function learnFromMentions(larkAppId: string, mentions?: Array<{ name: string; openId?: string; }>): void; export declare function getIdentity(larkAppId: string, openId: string): IdentityRecord | undefined; /** * Best-effort name resolution. Returns the cached name on hit; on miss for a * user open_id, calls `contact.v3.user.get` with a budget and updates the * cache. Bots/apps skip the API (no public contact endpoint). Failures * (permission denied, network, timeout) degrade silently to `undefined`. * * When the bot lacks `contact:user.base:readonly`, the first 99991672 from * the API trips a per-app circuit breaker so subsequent calls short-circuit * without burning quota. */ export declare function resolveName(larkAppId: string, openId: string): Promise; /** * Best-effort name resolution via `im.v1.messages.get` with `with_sender_name=true`. * Unlike the contact API this covers BOTH user and bot senders and does NOT * require `contact:user.base:readonly` — the server returns the display name * for whoever sent the given message. Used as a last-resort fallback in the * live-event path, where the event itself carries only open_id. * * Best-effort: any failure (network, permission, message not found, name * absent) degrades silently to `undefined`. Wrapped in the same short budget * as the contact path so a slow API can't stall prompt injection. On success * the name is written to the cache keyed by the resolved sender's open_id, so * later messages from the same sender hit the cache without a re-fetch. */ export declare function resolveNameViaMessage(larkAppId: string, openId: string, messageId: string, type: 'user' | 'bot'): Promise; export interface ResolvedSender { openId: string; type: 'user' | 'bot'; name?: string; email?: string; } /** * Resolve sender identity for prompt injection. * * Inputs are taken directly from the Lark event (`sender_id.open_id`, * `sender_type` ∈ {user, app, bot}). We normalize Lark's `app`/`bot` to our * prompt vocabulary (`bot`), record the sender event in the cache for future * lookups, and best-effort resolve the display name. Caller-supplied hints * (e.g. a known foreign-bot display name from `bot-openids-${appId}.json`) * win over cache. * * Identity resolution order: * 1. hint / cache — free, in-memory. * 2. contact API — users only; fills missing name/email and needs * `contact:user.base:readonly` plus `contact:user.email:readonly` for * email. A successful no-email result is negatively cached. * 3. message.get(`with_sender_name=true`) — fallback when `messageId` is * supplied and steps 1–2 came up empty. Covers users AND bots, and works * without the contact scope (the server names whoever sent that message). * This is what lets the live-event `` tag carry a name even when * contact is unavailable / out of visible range / the sender is a bot. */ export declare function resolveSender(larkAppId: string, openId: string | undefined, senderType: string | undefined, hint?: { name?: string; type?: 'user' | 'bot'; messageId?: string; }): Promise; //# sourceMappingURL=identity-cache.d.ts.map