UNPKG

eve

Version:

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

173 lines (172 loc) 7.87 kB
import type { SessionAuthContext } from "#channel/types.js"; import type { ActionEvent, Adapter, ChatConfig, SerializedThread, Thread, WebhookOptions } from "#compiled/chat/index.js"; import { Chat } from "#compiled/chat/index.js"; import { type Channel, type ChannelEvents, type ChannelSessionOps, type SendFn, type SendOptions, type Session } from "#public/definitions/channel.js"; type ChatSdkAdapters = Record<string, Adapter>; type ChatSdkSendInput = Parameters<SendFn<ChatSdkChannelState>>[0]; /** * Durable channel state used by `chatSdkChannel`. Stores the last Chat SDK * thread for the Eve session so event handlers can post replies without * depending on hidden Chat SDK subscription state, plus the bookkeeping the * default handlers use to stream assistant output and surface typing status. */ export interface ChatSdkChannelState extends Record<string, unknown> { thread: SerializedThread | null; /** Message id of the in-flight streamed assistant post (edit fallback). */ anchorMessageId?: string | null; /** * Whether `adapter.editMessage` works for this session. Set to `false` once * an edit throws {@link isNotImplemented}, which disables streaming edits for * the rest of the session. */ editSupported?: boolean; /** Epoch ms of the last streaming edit, used to throttle edits. */ lastEditAtMs?: number | null; /** Buffered first line of a tool-call message, surfaced as typing status. */ pendingToolCallMessage?: string | null; /** Step index the current stream anchor belongs to (resets per step). */ streamStepIndex?: number | null; } /** * Thread selector accepted by `chatSdkChannel().receive`. Pass a serialized * Chat SDK thread when possible; `threadId` plus `adapterName` is supported for * proactive sends that only have a provider-native thread id. */ export interface ChatSdkReceiveTarget { readonly adapterName?: string; readonly thread?: SerializedThread; readonly threadId?: string; } /** * Channel-owned metadata exposed to Eve instrumentation. */ export interface ChatSdkInstrumentationMetadata extends Record<string, unknown> { readonly adapterName: string | null; readonly channelId: string | null; readonly isDM: boolean | null; readonly threadId: string | null; } /** * Per-session context passed to `chatSdkChannel({ events })` handlers. `thread` * is rebuilt from persisted channel state using the configured Chat SDK * adapter, so default handlers can post back to the originating chat thread. */ export interface ChatSdkChannelContext<TAdapters extends ChatSdkAdapters = ChatSdkAdapters> { readonly bot: Chat<TAdapters>; readonly thread: Thread | null; state: ChatSdkChannelState; /** Whether streamed deltas are delivered via a post+edit fallback. */ readonly streaming: boolean; /** Minimum interval between streaming edits, in ms. */ readonly streamingEditIntervalMs: number; } /** Event-handler context for `chatSdkChannel`, including Eve session helpers. */ export interface ChatSdkEventContext<TAdapters extends ChatSdkAdapters = ChatSdkAdapters> extends ChatSdkChannelContext<TAdapters>, ChannelSessionOps { } /** * Per-event handlers for `chatSdkChannel({ events })`. Each supplied handler * replaces the built-in default for that event. */ export type ChatSdkChannelEvents<TAdapters extends ChatSdkAdapters = ChatSdkAdapters> = ChannelEvents<ChatSdkChannelContext<TAdapters>>; /** * Options for `bridge.send(...)` inside Chat SDK handlers. The `thread` * determines the Eve continuation token and the persisted channel state. */ export interface ChatSdkSendOptions { readonly auth?: SessionAuthContext | null; readonly callback?: SendOptions<ChatSdkChannelState>["callback"]; readonly mode?: SendOptions<ChatSdkChannelState>["mode"]; readonly thread: SerializedThread | Thread | string; readonly title?: string; /** * Required when `thread` is a string that does not include the Chat SDK * adapter prefix. Prefer passing the `Thread` object from the Chat SDK handler * when possible. */ readonly adapterName?: string; } /** * Configuration for {@link chatSdkChannel}. It accepts normal Chat SDK * `ChatConfig` fields, plus Eve route and event settings. */ export interface ChatSdkChannelConfig<TAdapters extends ChatSdkAdapters = ChatSdkAdapters> extends Omit<ChatConfig<TAdapters>, "adapters"> { /** Map of Chat SDK adapter name to adapter instance. */ readonly adapters: TAdapters; /** * Base route for generated adapter webhooks. Defaults to `/eve/v1`, so an * adapter named `slack` mounts at `/eve/v1/slack`. */ readonly route?: string; /** * Per-adapter route overrides. Use when a provider requires a fixed webhook * URL or when migrating an existing endpoint without changing provider * settings. */ readonly routes?: Partial<Record<Extract<keyof TAdapters, string>, string>>; /** Extra Chat SDK webhook options. Eve owns `waitUntil`. */ readonly webhook?: Omit<WebhookOptions, "waitUntil">; /** Optional Eve event handlers. Supplied handlers replace built-in defaults. */ readonly events?: ChatSdkChannelEvents<TAdapters>; /** * Prefix for default Eve HITL button action ids. Change this if your Chat SDK * app already uses the `eve_input:` prefix. */ readonly inputActionPrefix?: string; /** * Auth resolver for default HITL button clicks. Defaults to `null`; provide a * resolver when continued sessions should keep user or tenant auth. */ readonly resolveInputAuth?: (event: ActionEvent) => SessionAuthContext | null | Promise<SessionAuthContext | null>; /** * Whether the default handlers stream assistant output by posting an initial * message and editing it as deltas arrive. Defaults to `true`. Set to `false` * for adapters that only deliver a single message per turn (e.g. email), so * replies post once on completion. */ readonly streaming?: boolean; /** * Minimum interval between streaming edits, in ms. Defaults to `1000`. Only * used when `streaming` is enabled and the adapter supports editing. */ readonly streamingEditIntervalMs?: number; } /** Concrete channel value returned on `bridge.channel`. */ export interface ChatSdkChannel extends Channel<ChatSdkChannelState, ChatSdkReceiveTarget, ChatSdkInstrumentationMetadata> { } /** * Return value of {@link chatSdkChannel}. Export `channel` from * `agent/channels/<name>.ts`, then register handlers on `bot` and call `send` * from those handlers to hand work to Eve. */ export interface ChatSdkChannelBridge<TAdapters extends ChatSdkAdapters = ChatSdkAdapters> { readonly bot: Chat<TAdapters>; readonly channel: ChatSdkChannel; /** * Starts or resumes an Eve session from inside a Chat SDK webhook handler. * Use `channel.receive(...)` for proactive sends that are not handling an * inbound Chat SDK webhook. */ send(input: ChatSdkSendInput, options: ChatSdkSendOptions): Promise<Session>; } /** * Creates an Eve channel backed by one Chat SDK runtime and its adapters. * * @example * ```ts * import { createSlackAdapter } from "@chat-adapter/slack"; * import { createMemoryState } from "@chat-adapter/state-memory"; * import { chatSdkChannel } from "eve/channels/chat-sdk"; * * export const { bot, channel, send } = chatSdkChannel({ * userName: "acme", * adapters: { slack: createSlackAdapter() }, * state: createMemoryState(), * }); * * bot.onNewMention(async (thread, message) => { * await send(message.text, { thread }); * }); * ``` */ export declare function chatSdkChannel<TAdapters extends ChatSdkAdapters>(config: ChatSdkChannelConfig<TAdapters>): ChatSdkChannelBridge<TAdapters>; export {};