eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
136 lines (135 loc) • 8.1 kB
TypeScript
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 {};