Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add AI related user events #1400

Merged
merged 7 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import {
SendMessageOptions,
AscDesc,
PartialUpdateMemberAPIResponse,
AIState,
} from './types';
import { Role } from './permissions';
import { DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE } from './constants';
Expand Down Expand Up @@ -787,6 +788,43 @@ export class Channel<StreamChatGenerics extends ExtendableGenerics = DefaultGene
}
}

/**
* Sends an event to update the AI state for a specific message.
* Typically used by the server connected to the AI service to notify clients of state changes.
*
* @param messageId - The ID of the message associated with the AI state.
* @param state - The new state of the AI process (e.g., thinking, generating).
* @param options - Optional parameters, such as `ai_message`, to include additional details in the event.
*/
async updateAIState(messageId: string, state: AIState, options: { ai_message?: string } = {}) {
await this.sendEvent({
...options,
type: 'ai_indicator.update',
message_id: messageId,
ai_state: state,
} as Event<StreamChatGenerics>);
}

/**
* Sends an event to notify watchers to clear the typing/thinking UI when the AI response starts streaming.
* Typically used by the server connected to the AI service to inform clients that the AI response has started.
*/
async clearAIIndicator() {
await this.sendEvent({
type: 'ai_indicator.clear',
kanat marked this conversation as resolved.
Show resolved Hide resolved
} as Event<StreamChatGenerics>);
}

/**
* Sends an event to stop AI response generation, leaving the message in its current state.
* Triggered by the user to halt the AI response process.
*/
async stopAIResponse() {
await this.sendEvent({
type: 'ai_indicator.stop',
kanat marked this conversation as resolved.
Show resolved Hide resolved
} as Event<StreamChatGenerics>);
}

/**
* stopTyping - Sets last typing to null and sends the typing.stop event
* @see {@link https://getstream.io/chat/docs/typing_indicators/?language=js|Docs}
Expand Down
4 changes: 4 additions & 0 deletions src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export const EVENT_MAP = {
'user.updated': true,
'user.watching.start': true,
'user.watching.stop': true,
// AI events
'ai_indicator.update': true,
kanat marked this conversation as resolved.
Show resolved Hide resolved
'ai_indicator.stop': true,
'ai_indicator.clear': true,

// local events
'channels.queried': true,
Expand Down
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,8 @@ export type ConnectionChangeEvent = {

export type Event<StreamChatGenerics extends ExtendableGenerics = DefaultGenerics> = StreamChatGenerics['eventType'] & {
type: EventTypes;
ai_message?: string;
ai_state?: AIState;
channel?: ChannelResponse<StreamChatGenerics>;
channel_id?: string;
channel_type?: string;
Expand All @@ -1270,6 +1272,7 @@ export type Event<StreamChatGenerics extends ExtendableGenerics = DefaultGeneric
me?: OwnUserResponse<StreamChatGenerics>;
member?: ChannelMemberResponse<StreamChatGenerics>;
message?: MessageResponse<StreamChatGenerics>;
message_id?: string;
mode?: string;
online?: boolean;
parent_id?: string;
Expand Down Expand Up @@ -3543,3 +3546,10 @@ export type GetUserModerationReportOptions = {
include_user_blocks?: boolean;
include_user_mutes?: boolean;
};

export type AIState =
| 'AI_STATE_ERROR'
| 'AI_STATE_CHECKING_SOURCES'
| 'AI_STATE_THINKING'
| 'AI_STATE_GENERATING'
| (string & {});
Loading