UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

136 lines (135 loc) 8.1 kB
import type { DiscordInstrumentationMetadata } from "#public/channels/discord/index.js"; import type { SessionAuthContext } from "#channel/types.js"; import type { SessionContext } from "#public/definitions/callback-context.js"; import type { ChannelSessionOps } from "#public/definitions/channel.js"; import type { HandleMessageStreamEvent } from "#protocol/message.js"; import { type DiscordApiOptions, type DiscordApiResponse, type DiscordCredentials, type DiscordMessageBody, type DiscordPostedMessage } from "#public/channels/discord/api.js"; import { type DiscordCommandInteraction } from "#public/channels/discord/inbound.js"; import { type DiscordWebhookVerifier } from "#public/channels/discord/verify.js"; import { type JsonObject } from "#shared/json.js"; import { type Channel } from "#public/definitions/channel.js"; type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessageStreamEvent, { type: T; }> extends { data: infer D; } ? D : undefined; /** Pre-dispatch Discord context passed to inbound command hooks. */ export interface DiscordContext { readonly discord: DiscordHandle; } /** Channel-owned Discord context returned by `context()`. */ export type DiscordChannelContext = DiscordContext & { state: DiscordChannelState; }; /** Event-handler Discord context, including session operations. */ export interface DiscordEventContext extends DiscordChannelContext, ChannelSessionOps { } /** JSON-serializable Discord channel state. */ export interface DiscordChannelState { /** Discord channel id. */ channelId: string | null; /** Discord message id once anchored, or an interaction placeholder before the first reply. */ conversationId: string | null; /** Discord guild id, when the interaction was invoked in a guild. */ guildId: string | null; /** Discord application id from the inbound interaction. */ applicationId: string | null; /** Latest interaction token available to the channel. */ interactionToken: string | null; /** Whether the channel has already edited the deferred original interaction response. */ initialResponseSent: boolean; /** Whether `conversationId` is a real Discord message id. */ hasMessageAnchor: boolean; } /** Discord channel credentials. */ export interface DiscordChannelCredentials extends DiscordCredentials { /** Custom inbound webhook verifier. When supplied, eve skips the `DISCORD_PUBLIC_KEY` fallback and delegates verification to it. */ readonly webhookVerifier?: DiscordWebhookVerifier; } /** Target accepted by `receive(discord, { target })` for proactive sessions. */ export interface DiscordReceiveTarget { readonly channelId: string; readonly conversationId?: string; readonly initialMessage?: string | DiscordMessageBody; } /** * Result of an inbound Discord command hook. Return `null` to acknowledge the * interaction without dispatching the agent. * - `auth`: session auth context for the dispatched turn, or `null` for anonymous. * - `ephemeral`: when `true`, the deferred reply is visible only to the invoking user. * - `context`: model-visible context lines appended after the Discord context block. */ export type DiscordCommandResult = { readonly auth: SessionAuthContext | null; readonly ephemeral?: boolean; readonly context?: readonly string[]; } | null; /** Sync or async {@link DiscordCommandResult}. */ export type DiscordCommandResultOrPromise = DiscordCommandResult | Promise<DiscordCommandResult>; type DiscordEventHandler<T extends HandleMessageStreamEvent["type"]> = (data: EventData<T>, channel: DiscordEventContext, ctx: SessionContext) => void | Promise<void>; type DiscordSessionFailedHandler = (data: EventData<"session.failed">, channel: DiscordEventContext) => void | Promise<void>; /** Per-event handlers for `discordChannel({ events })`. Supplied handlers override built-in defaults per key; unspecified events keep their defaults. `session.failed` receives only `(data, channel)`; every other handler also gets the session `ctx`. */ export interface DiscordChannelEvents { readonly "turn.started"?: DiscordEventHandler<"turn.started">; readonly "actions.requested"?: DiscordEventHandler<"actions.requested">; readonly "action.result"?: DiscordEventHandler<"action.result">; readonly "message.completed"?: DiscordEventHandler<"message.completed">; readonly "message.appended"?: DiscordEventHandler<"message.appended">; readonly "input.requested"?: DiscordEventHandler<"input.requested">; readonly "turn.failed"?: DiscordEventHandler<"turn.failed">; readonly "turn.completed"?: DiscordEventHandler<"turn.completed">; readonly "turn.cancelled"?: DiscordEventHandler<"turn.cancelled">; readonly "session.failed"?: DiscordSessionFailedHandler; readonly "session.completed"?: DiscordEventHandler<"session.completed">; readonly "session.waiting"?: DiscordEventHandler<"session.waiting">; readonly "authorization.required"?: DiscordEventHandler<"authorization.required">; readonly "authorization.completed"?: DiscordEventHandler<"authorization.completed">; } /** Configuration for {@link discordChannel}. */ export interface DiscordChannelConfig { readonly api?: Omit<DiscordApiOptions, "credentials">; readonly credentials?: DiscordChannelCredentials; /** Override the default interaction route path (`/eve/v1/discord`). */ readonly route?: string; /** Inbound command hook. Defaults to user-scoped Discord auth and dispatch. Return `{ auth }` to dispatch, or `null` to acknowledge without running the agent. */ onCommand?(ctx: DiscordContext, interaction: DiscordCommandInteraction): DiscordCommandResultOrPromise; readonly events?: DiscordChannelEvents; } /** Low-level Discord handle exposed to hooks and event handlers. */ export interface DiscordHandle { /** Discord application id when known. */ readonly applicationId: string | undefined; /** Discord channel id. */ readonly channelId: string; /** Current eve conversation id, usually the Discord anchor message id. */ readonly conversationId: string; /** Discord guild id when known. */ readonly guildId: string | undefined; /** Latest Discord interaction token when known. */ readonly interactionToken: string | undefined; /** Raw Discord API escape hatch. */ request(path: string, body: JsonObject, options?: DiscordRequestOptions): Promise<DiscordApiResponse>; /** Posts to the current conversation: interaction response or followup when an interaction token and application id exist, else a channel message. Splits over-length content, returning the first. */ post(message: string | DiscordMessageBody): Promise<DiscordPostedMessage>; /** Sends a bot-authenticated message to this Discord channel. */ sendChannelMessage(message: string | DiscordMessageBody): Promise<DiscordPostedMessage>; /** Edits the deferred original interaction response. */ editOriginalResponse(message: string | DiscordMessageBody): Promise<DiscordPostedMessage>; /** Creates an interaction followup message. */ followup(message: string | DiscordMessageBody): Promise<DiscordPostedMessage>; /** Triggers Discord's short-lived typing indicator. Ignores any failure. */ startTyping(): Promise<void>; } /** Options for {@link DiscordHandle.request}. */ export interface DiscordRequestOptions { /** When `true`, attaches bot-token authorization; otherwise the raw request runs unauthenticated, suiting interaction webhook endpoints. */ readonly botAuth?: boolean; /** HTTP method for the raw request. Defaults to `POST`. */ readonly method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT"; } /** Concrete return type of {@link discordChannel}. */ export interface DiscordChannel extends Channel<DiscordChannelState, DiscordReceiveTarget, DiscordInstrumentationMetadata> { } /** Discord channel factory for HTTP Interactions and proactive channel messages. */ export declare function discordChannel(config?: DiscordChannelConfig): DiscordChannel; export {};