|
| 1 | +import { Injectable } from '@nestjs/common'; |
| 2 | +import { MessagesService } from 'omniboxd/messages/messages.service'; |
| 3 | +import { ConversationsService } from 'omniboxd/conversations/conversations.service'; |
| 4 | +import { WizardService } from 'omniboxd/wizard/wizard.service'; |
| 5 | +import { User } from 'omniboxd/user/entities/user.entity'; |
| 6 | +import { OpenAgentRequestDto } from 'omniboxd/wizard/dto/open-agent-request.dto'; |
| 7 | +import { AgentRequestDto } from 'omniboxd/wizard/dto/agent-request.dto'; |
| 8 | +import { ChatResponse } from 'omniboxd/wizard/dto/chat-response.dto'; |
| 9 | + |
| 10 | +@Injectable() |
| 11 | +export class OpenWizardService { |
| 12 | + constructor( |
| 13 | + private readonly wizardService: WizardService, |
| 14 | + private readonly messagesService: MessagesService, |
| 15 | + private readonly conversationsService: ConversationsService, |
| 16 | + ) {} |
| 17 | + |
| 18 | + async ask( |
| 19 | + userId: string, |
| 20 | + namespaceId: string, |
| 21 | + requestId: string, |
| 22 | + data: OpenAgentRequestDto, |
| 23 | + ): Promise<any> { |
| 24 | + const conversationId = await this.resolveConversationId( |
| 25 | + userId, |
| 26 | + namespaceId, |
| 27 | + data.parent_message_id, |
| 28 | + ); |
| 29 | + |
| 30 | + const agentRequest: AgentRequestDto = { |
| 31 | + ...data, |
| 32 | + conversation_id: conversationId, |
| 33 | + namespace_id: namespaceId, |
| 34 | + enable_thinking: data.enable_thinking ?? false, |
| 35 | + }; |
| 36 | + |
| 37 | + const chunks: ChatResponse[] = await this.wizardService.streamService.chat( |
| 38 | + userId, |
| 39 | + agentRequest, |
| 40 | + requestId, |
| 41 | + 'ask', |
| 42 | + ); |
| 43 | + |
| 44 | + return this.mergeChunks(chunks); |
| 45 | + } |
| 46 | + |
| 47 | + private async resolveConversationId( |
| 48 | + userId: string, |
| 49 | + namespaceId: string, |
| 50 | + parentMessageId?: string, |
| 51 | + ): Promise<string> { |
| 52 | + if (parentMessageId) { |
| 53 | + // Find conversation_id from parent_message_id |
| 54 | + const parentMessage = await this.messagesService.findOne(parentMessageId); |
| 55 | + return parentMessage.conversationId; |
| 56 | + } else { |
| 57 | + // Create a new conversation |
| 58 | + const user = { id: userId } as User; |
| 59 | + const conversation = await this.conversationsService.create( |
| 60 | + namespaceId, |
| 61 | + user, |
| 62 | + ); |
| 63 | + return conversation.id; |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + private mergeChunks(chunks: ChatResponse[]): any { |
| 68 | + const messages: any[] = []; |
| 69 | + let currentMessage: any = null; |
| 70 | + |
| 71 | + for (const chunk of chunks) { |
| 72 | + if (chunk.response_type === 'bos') { |
| 73 | + const bosChunk = chunk; |
| 74 | + currentMessage = { |
| 75 | + id: bosChunk.id, |
| 76 | + role: bosChunk.role, |
| 77 | + parent_id: bosChunk.parentId, |
| 78 | + message: { |
| 79 | + role: bosChunk.role, |
| 80 | + }, |
| 81 | + attrs: {}, |
| 82 | + }; |
| 83 | + } else if (chunk.response_type === 'delta' && currentMessage) { |
| 84 | + const deltaChunk = chunk; |
| 85 | + if (deltaChunk.message.content) { |
| 86 | + currentMessage.message.content = |
| 87 | + (currentMessage.message.content || '') + deltaChunk.message.content; |
| 88 | + } |
| 89 | + if (deltaChunk.message.reasoning_content) { |
| 90 | + currentMessage.message.reasoning_content = |
| 91 | + (currentMessage.message.reasoning_content || '') + |
| 92 | + deltaChunk.message.reasoning_content; |
| 93 | + } |
| 94 | + if (deltaChunk.message.tool_calls) { |
| 95 | + currentMessage.message.tool_calls = deltaChunk.message.tool_calls; |
| 96 | + } |
| 97 | + if (deltaChunk.message.tool_call_id) { |
| 98 | + currentMessage.message.tool_call_id = deltaChunk.message.tool_call_id; |
| 99 | + } |
| 100 | + if (deltaChunk.attrs) { |
| 101 | + currentMessage.attrs = { |
| 102 | + ...currentMessage.attrs, |
| 103 | + ...deltaChunk.attrs, |
| 104 | + }; |
| 105 | + } |
| 106 | + } else if (chunk.response_type === 'eos' && currentMessage) { |
| 107 | + messages.push(currentMessage); |
| 108 | + currentMessage = null; |
| 109 | + } else if (chunk.response_type === 'done') { |
| 110 | + // Done |
| 111 | + } else { |
| 112 | + throw new Error(`Invalid response_type = ${chunk.response_type}`); |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + return { messages }; |
| 117 | + } |
| 118 | +} |
0 commit comments