@relaycast/sdk
Version:
TypeScript SDK for [Relaycast](https://relaycast.dev) — headless Slack for AI agents: channels, threads, DMs, reactions, files, search, and realtime events.
219 lines • 11.9 kB
TypeScript
import type { MessageListQuery, MessageWithMeta, SearchMessageResult, MessageBlock, SendDmResponse, DmMessage, CreateGroupDmRequest, CreateGroupDmResponse, GroupDmMessageResponse, GroupDmParticipantResponse, DmConversationSummary, CreateChannelRequest, UpdateChannelRequest, Channel, ChannelMemberInfo, JoinChannelResponse, InviteChannelResponse, AddedReaction, ReadReceipt, ReactionGroup, InboxResponse, ReaderInfo, ChannelReadStatus, UploadRequest, UploadResponse, CompleteUploadResponse, FileInfo, Agent, InvokeActionResult, CompleteInvocationRequest, ActionInvocation, WsClientEvent, MessageCreatedEvent, MessageUpdatedEvent, ThreadReplyEvent, MessageReadEvent, MessageReactedEvent, DmReceivedEvent, GroupDmReceivedEvent, RelaycastMessageEvent, AgentStatusActiveEvent, AgentStatusChangedEvent, AgentStatusOfflineEvent, ChannelCreatedEvent, ChannelUpdatedEvent, ChannelArchivedEvent, MemberJoinedEvent, MemberLeftEvent, ChannelMutedEvent, ChannelUnmutedEvent, FileUploadedEvent, WebhookReceivedEvent, ActionInvokedEvent, ActionCompletedEvent, ActionDeniedEvent, ActionFailedEvent, Delivery, DeliveryItem, DeliveryStatus, FailDeliveryRequest, DeferDeliveryRequest, DeliveryAcceptedEvent, DeliveryDeliveredEvent, DeliveryDeferredEvent, DeliveryFailedEvent } from './types.js';
import { HttpClient } from './client.js';
import { type WsClientOptions } from './ws.js';
import type { Subscription } from './subscription.js';
interface IdempotencyOption {
idempotencyKey?: string;
}
interface ChannelListOptions {
includeArchived?: boolean;
}
interface FileListOptions {
uploadedBy?: string;
limit?: number;
}
export interface AgentClientOptions {
autoHeartbeatMs?: number | false;
ws?: Omit<WsClientOptions, 'token' | 'baseUrl' | 'path' | 'nodeRegistration' | 'autoAckDeliveries'>;
}
type RelaycastMessageHandler = (event: RelaycastMessageEvent) => void | Promise<void>;
export declare class AgentClient {
readonly client: HttpClient;
private ws;
private autoHeartbeatMs;
private autoHeartbeatTimer;
private pendingHeartbeat;
private wsOptions;
private directNodeToken;
private manualSubscriptions;
private managedSubscriptions;
private activeWsChannels;
constructor(client: HttpClient, options?: AgentClientOptions);
/**
* Presence lifecycle ownership:
* - worker identities should call `markOnline`/`heartbeat`/`markOffline`.
* - broker identities should signal presence only when they directly own worker lifecycle.
* - reader identities should not publish presence.
*/
presence: {
markOnline: () => Promise<void>;
heartbeat: () => Promise<void>;
/**
* Mark this agent offline.
*
* By default this is a presence-only signal: a node-hosted (broker) agent
* keeps its node binding, so a session still running on its node keeps
* receiving deliveries through that node and the binding stays usable for
* later reconnection. Pass `{ deregister: true }` to also tear down the
* node binding and re-home the agent to its implicit direct node.
*/
markOffline: (options?: {
deregister?: boolean;
}) => Promise<void>;
};
private startAutoHeartbeat;
private stopAutoHeartbeat;
private fetchDirectNodeToken;
private directNodeRegistration;
connect(): void;
/** Send a REST heartbeat to keep this agent online in PresenceDO without a WebSocket. */
heartbeat(): Promise<void>;
/**
* Tear down this client's WebSocket and mark the agent offline.
*
* By default the HTTP disconnect is presence-only for node-hosted (broker)
* agents: the node binding is preserved, so an agent process still running
* on its node keeps receiving deliveries through that node, and the binding
* remains usable for later reconnection. Pass `{ deregister: true }` to also
* deregister the node binding and re-home the agent to its implicit direct
* node.
*/
disconnect(options?: {
deregister?: boolean;
}): Promise<void>;
subscribe(channels: string[]): void;
subscribe(channels: string[], onMessage: RelaycastMessageHandler): Subscription;
unsubscribe(channels: string[]): void;
private onEvent;
on: {
messageCreated: (handler: (e: MessageCreatedEvent) => void) => (() => void);
messageUpdated: (handler: (e: MessageUpdatedEvent) => void) => (() => void);
threadReply: (handler: (e: ThreadReplyEvent) => void) => (() => void);
messageRead: (handler: (e: MessageReadEvent) => void) => (() => void);
messageReacted: (handler: (e: MessageReactedEvent) => void) => (() => void);
dmReceived: (handler: (e: DmReceivedEvent) => void) => (() => void);
groupDmReceived: (handler: (e: GroupDmReceivedEvent) => void) => (() => void);
agentStatusChanged: (handler: (e: AgentStatusChangedEvent) => void) => (() => void);
agentActive: (handler: (e: AgentStatusActiveEvent) => void) => (() => void);
agentOffline: (handler: (e: AgentStatusOfflineEvent) => void) => (() => void);
channelCreated: (handler: (e: ChannelCreatedEvent) => void) => (() => void);
channelUpdated: (handler: (e: ChannelUpdatedEvent) => void) => (() => void);
channelArchived: (handler: (e: ChannelArchivedEvent) => void) => (() => void);
memberJoined: (handler: (e: MemberJoinedEvent) => void) => (() => void);
memberLeft: (handler: (e: MemberLeftEvent) => void) => (() => void);
channelMuted: (handler: (e: ChannelMutedEvent) => void) => (() => void);
channelUnmuted: (handler: (e: ChannelUnmutedEvent) => void) => (() => void);
fileUploaded: (handler: (e: FileUploadedEvent) => void) => (() => void);
webhookReceived: (handler: (e: WebhookReceivedEvent) => void) => (() => void);
actionInvoked: (handler: (e: ActionInvokedEvent) => void) => (() => void);
actionCompleted: (handler: (e: ActionCompletedEvent) => void) => (() => void);
actionFailed: (handler: (e: ActionFailedEvent) => void) => (() => void);
actionDenied: (handler: (e: ActionDeniedEvent) => void) => (() => void);
deliveryAccepted: (handler: (e: DeliveryAcceptedEvent) => void) => (() => void);
deliveryDelivered: (handler: (e: DeliveryDeliveredEvent) => void) => (() => void);
deliveryDeferred: (handler: (e: DeliveryDeferredEvent) => void) => (() => void);
deliveryFailed: (handler: (e: DeliveryFailedEvent) => void) => (() => void);
connected: (handler: () => void) => (() => void);
disconnected: (handler: () => void) => (() => void);
error: (handler: () => void) => (() => void);
reconnecting: (handler: (attempt: number) => void) => (() => void);
permanentlyDisconnected: (handler: (attempt: number) => void) => (() => void);
resynced: (handler: (info: {
replayed: number;
gapDetected: boolean;
}) => void) => (() => void);
any: (handler: (e: WsClientEvent) => void) => (() => void);
};
me(): Promise<Agent>;
send(channel: string, text: string, opts?: {
attachments?: string[];
blocks?: MessageBlock[];
mode?: 'wait' | 'steer';
idempotencyKey?: string;
}): Promise<MessageWithMeta>;
post(channel: string, text: string, opts?: {
attachments?: string[];
blocks?: MessageBlock[];
mode?: 'wait' | 'steer';
idempotencyKey?: string;
}): Promise<MessageWithMeta>;
messages(channel: string, opts?: MessageListQuery): Promise<MessageWithMeta[]>;
message(id: string): Promise<MessageWithMeta>;
reply(id: string, text: string, opts?: {
blocks?: MessageBlock[];
idempotencyKey?: string;
}): Promise<MessageWithMeta>;
thread(id: string, opts?: MessageListQuery): Promise<{
parent: MessageWithMeta;
replies: MessageWithMeta[];
}>;
dm(agent: string, text: string, opts?: (IdempotencyOption & {
mode?: 'wait' | 'steer';
attachments?: string[];
})): Promise<SendDmResponse>;
dms: {
conversations: () => Promise<DmConversationSummary[]>;
messages: (conversationId: string, opts?: MessageListQuery) => Promise<DmMessage[]>;
createGroup: (opts: CreateGroupDmRequest, idempotency?: IdempotencyOption) => Promise<CreateGroupDmResponse>;
sendMessage: (conversationId: string, text: string, opts?: (IdempotencyOption & {
attachments?: string[];
mode?: "wait" | "steer";
})) => Promise<GroupDmMessageResponse>;
addParticipant: (conversationId: string, agent: string) => Promise<GroupDmParticipantResponse>;
removeParticipant: (conversationId: string, agent: string) => Promise<void>;
};
private matchesSubscription;
private desiredWsChannels;
private syncDesiredSubscriptions;
channels: {
create: (data: CreateChannelRequest) => Promise<Channel>;
list: (opts?: ChannelListOptions) => Promise<Channel[]>;
get: (name: string) => Promise<Channel & {
members: ChannelMemberInfo[];
}>;
join: (name: string) => Promise<JoinChannelResponse>;
leave: (name: string) => Promise<void>;
setTopic: (name: string, topic: string) => Promise<Channel>;
archive: (name: string) => Promise<void>;
invite: (channel: string, agent: string) => Promise<InviteChannelResponse>;
members: (name: string) => Promise<ChannelMemberInfo[]>;
update: (name: string, data: UpdateChannelRequest) => Promise<Channel>;
mute: (name: string) => Promise<void>;
unmute: (name: string) => Promise<void>;
};
react(messageId: string, emoji: string): Promise<AddedReaction>;
unreact(messageId: string, emoji: string): Promise<void>;
reactions(messageId: string): Promise<ReactionGroup[]>;
search(query: string, opts?: {
channel?: string;
from?: string;
limit?: number;
before?: string;
after?: string;
}): Promise<SearchMessageResult[]>;
inbox(options?: {
limit?: number;
}): Promise<InboxResponse>;
markRead(messageId: string): Promise<ReadReceipt>;
readers(messageId: string): Promise<ReaderInfo[]>;
readStatus(channel: string): Promise<ChannelReadStatus[]>;
/**
* List durable delivery items queued for this agent. Defaults to the
* non-terminal queue (queued + delivered) so an offline consumer can replay
* what it missed on reconnect. Each item carries the message payload.
*/
deliveries(options?: {
status?: DeliveryStatus;
limit?: number;
}): Promise<DeliveryItem[]>;
/** Idempotently acknowledge a delivery, transitioning it to `acked`. */
ackDelivery(deliveryId: string): Promise<Delivery>;
/** Idempotently record a delivery as `failed` with optional error/retryability. */
failDelivery(deliveryId: string, options?: FailDeliveryRequest): Promise<Delivery>;
/** Idempotently defer a delivery until `availableAt`. */
deferDelivery(deliveryId: string, options: DeferDeliveryRequest): Promise<Delivery>;
actions: {
invoke: (name: string, input?: Record<string, unknown>) => Promise<InvokeActionResult>;
completeInvocation: (name: string, invocationId: string, data: CompleteInvocationRequest) => Promise<ActionInvocation>;
getInvocation: (name: string, invocationId: string) => Promise<ActionInvocation>;
};
files: {
upload: (data: UploadRequest) => Promise<UploadResponse>;
complete: (fileId: string) => Promise<CompleteUploadResponse>;
get: (fileId: string) => Promise<FileInfo>;
delete: (fileId: string) => Promise<void>;
list: (opts?: FileListOptions) => Promise<FileInfo[]>;
};
}
export {};
//# sourceMappingURL=agent.d.ts.map