Skip to content
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
7 changes: 5 additions & 2 deletions src/conversations/conversations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class ConversationsService {
const summaries: ConversationSummaryDto[] = [];

const check = (m: Message, role: OpenAIMessageRole) => {
return m.message.role === role && m.message.content;
return m.message.role === role && m.message.content?.trim();
};

for (const c of conversations) {
Expand Down Expand Up @@ -163,10 +163,13 @@ export class ConversationsService {
}
}
for (const msg of messages) {
if (msg.id === system_message.id) {
continue;
}
detail.mapping[msg.id] = {
id: msg.id,
message: msg.message,
parent: msg.parentId,
parent_id: msg.parentId,
children: childrenMap[msg.id] || [],
created_at: msg.createdAt.toISOString(),
status: msg.status,
Expand Down
2 changes: 1 addition & 1 deletion src/conversations/dto/conversation-detail.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface ConversationMessageMappingDto extends BaseDto {
id: string;
message: Record<string, any>;
status: MessageStatus;
parent?: string;
parent_id?: string;
children: string[];
attrs?: Record<string, any>;
}
Expand Down
4 changes: 4 additions & 0 deletions src/messages/dto/create-message.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IsOptional, IsString } from 'class-validator';
import { MessageStatus } from 'src/messages/entities/message.entity';

export class CreateMessageDto {
message: Record<string, any>;
Expand All @@ -7,6 +8,9 @@ export class CreateMessageDto {
@IsString()
parentId?: string;

@IsOptional()
status?: MessageStatus;

@IsOptional()
attrs?: Record<string, any>;
}
14 changes: 11 additions & 3 deletions src/messages/entities/message.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import { Base } from 'src/common/base.entity';

export enum MessageStatus {
PENDING = 'pending',
STREAMING = 'streaming',
SUCCESS = 'success',
STOPPED = 'stopped',
FAIL = 'fail',
INTERRUPTED = 'interrupted',
FAILED = 'failed',
}

export enum OpenAIMessageRole {
Expand All @@ -33,10 +35,16 @@ export enum OpenAIMessageRole {
TOOL = 'tool',
}

export class OpenAIMessage {
export interface OpenAIMessage {
role: OpenAIMessageRole;
content?: string;
reasoning_content?: string;
tool_calls?: Record<string, any>[];
tool_call_id?: string;
}

export interface MessageAttrs {
citations?: Record<string, any>[];
}

@Entity('messages')
Expand Down Expand Up @@ -69,5 +77,5 @@ export class Message extends Base {
status: MessageStatus;

@Column('jsonb', { nullable: true })
attrs?: Record<string, any>;
attrs?: MessageAttrs;
}
75 changes: 70 additions & 5 deletions src/messages/messages.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Message } from 'src/messages/entities/message.entity';
import {
Message,
MessageStatus,
OpenAIMessage,
} from 'src/messages/entities/message.entity';
import { CreateMessageDto } from 'src/messages/dto/create-message.dto';
import { User } from 'src/user/user.entity';
import { SearchService } from 'src/search/search.service';
Expand All @@ -14,12 +18,21 @@ export class MessagesService {
private readonly searchService: SearchService,
) {}

index(index: boolean, namespaceId: string, message: Message) {
if (index) {
this.searchService.addMessage(namespaceId, message).catch((err) => {
console.error('Failed to index message:', err);
});
}
}

async create(
namespaceId: string,
conversationId: string,
user: User,
dto: CreateMessageDto,
) {
index: boolean = true,
): Promise<Message> {
const message = this.messageRepository.create({
message: dto.message,
conversation: { id: conversationId },
Expand All @@ -28,12 +41,64 @@ export class MessagesService {
attrs: dto.attrs,
});
const savedMsg = await this.messageRepository.save(message);
this.searchService.addMessage(namespaceId, savedMsg).catch((err) => {
console.error('Failed to index message:', err);
});
this.index(index, namespaceId, savedMsg);
return savedMsg;
}

async update(
id: string,
namespaceId: string,
dto: Partial<CreateMessageDto>,
index: boolean = true,
): Promise<Message> {
const condition: Record<string, any> = { where: { id } };
if (index) {
condition.relations = ['user'];
}
const message = await this.messageRepository.findOneOrFail(condition);
Object.assign(message, dto);
const updatedMsg = await this.messageRepository.save(message);
this.index(index, namespaceId, message);
return updatedMsg;
}

add(source?: string, delta?: string): string | undefined {
return delta ? (source || '') + delta : source;
}

async updateOpenAIMessage(
id: string,
deltaMessage: Partial<OpenAIMessage>,
attrs?: Record<string, any>,
) {
const message = await this.messageRepository.findOneOrFail({
where: { id },
});

// >>> OpenAI Message
message.message.content = this.add(
message.message.content,
deltaMessage.content,
);
message.message.reasoning_content = this.add(
message.message.reasoning_content,
deltaMessage.reasoning_content,
);
if (deltaMessage.tool_calls && deltaMessage.tool_calls.length > 0) {
message.message.tool_calls = deltaMessage.tool_calls;
}
if (deltaMessage.tool_call_id) {
message.message.tool_call_id = deltaMessage.tool_call_id;
}
// <<< OpenAI Message
message.status = MessageStatus.STREAMING;
if (attrs) {
message.attrs = message.attrs || {};
Object.assign(message.attrs, attrs);
}
return await this.messageRepository.save(message);
}

async findAll(userId: string, conversationId: string) {
return await this.messageRepository.find({
where: { conversation: { id: conversationId }, user: { id: userId } },
Expand Down
5 changes: 2 additions & 3 deletions src/resources/resources.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { WizardTask } from 'src/resources/wizard.task.service';
import { SpaceType } from 'src/namespaces/entities/namespace.entity';
import { PermissionsService } from 'src/permissions/permissions.service';
import { SearchService } from 'src/search/search.service';
import { promises } from 'stream';

export interface IQuery {
namespaceId: string;
Expand Down Expand Up @@ -91,7 +90,7 @@ export class ResourcesService {
return savedResource;
});
this.searchService.addResource(savedResource).catch((err) => {
console.log('Failed to index resource:', err);
console.error('Failed to index resource:', err);
});
return {
...savedResource,
Expand Down Expand Up @@ -240,7 +239,7 @@ export class ResourcesService {
const savedNewResource = await this.resourceRepository.save(newResource);
await WizardTask.index.upsert(user, savedNewResource, this.taskRepository);
this.searchService.addResource(savedNewResource).catch((err) => {
console.log('Failed to index resource:', err);
console.error('Failed to index resource:', err);
});
return {
...savedNewResource,
Expand Down
2 changes: 1 addition & 1 deletion src/search/search.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Controller, Get, Param, Post, Query, Req } from '@nestjs/common';
import { Controller, Get, Param, Query, Req } from '@nestjs/common';
import { SearchService } from './search.service';
import { DocType } from './doc-type.enum';

Expand Down
5 changes: 4 additions & 1 deletion src/search/search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ export class SearchService implements OnModuleInit {
}

async addMessage(namespaceId: string, message: Message) {
const content = message.message.content as string;
if (!message.message.content) {
return;
}
const content = message.message.content;
const index = await this.meili.getIndex(indexUid);
const doc: IndexedMessageDto = {
type: DocType.MESSAGE,
Expand Down
35 changes: 35 additions & 0 deletions src/wizard/dto/chat-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { OpenAIMessage, OpenAIMessageRole, MessageAttrs } from 'src/messages/entities/message.entity';

export type ChatResponseType = "bos" | "delta" | "eos" | "done" | "error";

export interface ChatBaseResponse {
response_type: ChatResponseType;
}

export interface ChatBOSResponse extends ChatBaseResponse {
response_type: "bos";
role: OpenAIMessageRole;
id: string;
parentId?: string;
}

export interface ChatEOSResponse extends ChatBaseResponse {
response_type: "eos";
}

export interface ChatDeltaResponse extends ChatBaseResponse {
response_type: "delta";
message: Partial<OpenAIMessage>;
attrs?: MessageAttrs;
}

export interface ChatDoneResponse extends ChatBaseResponse {
response_type: "done";
}

export interface ChatErrorResponse extends ChatBaseResponse {
response_type: "error";
message: string;
}

export type ChatResponse = ChatBOSResponse | ChatDeltaResponse | ChatEOSResponse | ChatDoneResponse | ChatErrorResponse;
Loading