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

V3.0.5 #14

Merged
merged 30 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5860a5b
feat: interrupted tool call
meta-d Dec 11, 2024
965dfc9
feat: sensitive tools
meta-d Dec 11, 2024
35d4ea0
feat: Interrupted chat
meta-d Dec 12, 2024
c227eba
feat: human in the loop
meta-d Dec 12, 2024
bedd050
feat: reject INTERRUPTED chat
meta-d Dec 12, 2024
b3ee9c0
feat: mutiple tool calls info
meta-d Dec 12, 2024
0e12a68
feat: sensitive operation tool call
meta-d Dec 13, 2024
44f2c35
Merge branch 'develop' into v3.0.4
meta-d Dec 13, 2024
82aaa73
version 3.0.4
meta-d Dec 13, 2024
6a37d8b
feat: primary agent not sensitive
meta-d Dec 13, 2024
d1c7743
feat: conversation summarize
meta-d Dec 14, 2024
7f3e7c7
feat: long term memory
meta-d Dec 15, 2024
4eb5b4b
feat: feeback to summarize long-term memory
meta-d Dec 16, 2024
2bd4bc2
feat: fix agent primary
meta-d Dec 16, 2024
37eef2c
feat: xpert's memory page
meta-d Dec 17, 2024
8d7d0ff
feat: long term memory of xpert
meta-d Dec 17, 2024
2aa1b8a
feat: use long-term memory in chat
meta-d Dec 18, 2024
ff0cc77
feat: add findMyAll in curd service
meta-d Dec 18, 2024
6ab7736
feat: register user
meta-d Dec 18, 2024
b33162c
feat: long-term memory every user
meta-d Dec 18, 2024
2a97e95
feat: long-term memory
meta-d Dec 18, 2024
49b660e
feat: execution tools events
meta-d Dec 18, 2024
73561a6
feat: fix xpert memory
meta-d Dec 18, 2024
3431705
feat: semantic search for long-term store
meta-d Dec 19, 2024
8dd154f
feat: long-term trigger events
meta-d Dec 19, 2024
803fc7a
feat: memory profile
meta-d Dec 20, 2024
7756017
version 3.0.5
meta-d Dec 20, 2024
867226a
feat: update mysql client to 2
meta-d Dec 20, 2024
c90a8ff
feat: memory of xpert
meta-d Dec 20, 2024
6c0cc56
fix: null memory store
meta-d Dec 20, 2024
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
Prev Previous commit
Next Next commit
feat: feeback to summarize long-term memory
  • Loading branch information
meta-d committed Dec 16, 2024
commit 4eb5b4bd6527b892dc1b6eafd9e1227022307906
10 changes: 10 additions & 0 deletions apps/cloud/src/app/@core/services/chat-message-feedback.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Injectable } from '@angular/core'
import { API_PREFIX, OrganizationBaseCrudService } from '@metad/cloud/state'
import { IChatMessageFeedback } from '../types'

@Injectable({ providedIn: 'root' })
export class ChatMessageFeedbackService extends OrganizationBaseCrudService<IChatMessageFeedback> {
constructor() {
super(API_PREFIX + '/chat-message-feedback')
}
}
10 changes: 10 additions & 0 deletions apps/cloud/src/app/@core/services/chat-message.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Injectable } from '@angular/core'
import { API_PREFIX, OrganizationBaseCrudService } from '@metad/cloud/state'
import { IChatMessage } from '../types'

@Injectable({ providedIn: 'root' })
export class ChatMessageService extends OrganizationBaseCrudService<IChatMessage> {
constructor() {
super(API_PREFIX + '/chat-message')
}
}
4 changes: 3 additions & 1 deletion apps/cloud/src/app/@core/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,6 @@ export * from './xpert-agent.service'
export * from './xpert-agent-execution.service'
export * from './copilot-provider.service'
export * from './copilot-server.service'
export * from './api-key.service'
export * from './api-key.service'
export * from './chat-message.service'
export * from './chat-message-feedback.service'
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
<xpert-preview-ai-message [message]="message" class="w-full grow" />
</div>

<div class="absolute flex justify-end gap-1 right-0 -top-4">
<div class="absolute flex justify-end items-center gap-1 right-0 -top-4">

<div class="hidden group-hover:block h-[28px] p-0.5 rounded-lg bg-white border-[0.5px] border-gray-100 shadow-sm shrink-0">
<div class="shrink-0 p-1 flex items-center justify-center rounded-[6px] font-medium
Expand All @@ -107,7 +107,7 @@
<div class="shrink-0 p-1 flex items-center justify-center rounded-[6px] font-medium text-gray-500 hover:bg-gray-50 cursor-pointer hover:text-gray-700"
(click)="openExecution(message)"
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" class="mr-1 w-4 h-4" data-icon="File02" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" class="mr-1 w-4 h-4">
<g id="Icon">
<path id="Icon_2" d="M9.33366 7.3335H5.33366M6.66699 10.0002H5.33366M10.667 4.66683H5.33366M13.3337 4.5335V11.4668C13.3337 12.5869 13.3337 13.147 13.1157 13.5748C12.9239 13.9511 12.618 14.2571 12.2416 14.4488C11.8138 14.6668 11.2538 14.6668 10.1337 14.6668H5.86699C4.74689 14.6668 4.18683 14.6668 3.75901 14.4488C3.38269 14.2571 3.07673 13.9511 2.88498 13.5748C2.66699 13.147 2.66699 12.5869 2.66699 11.4668V4.5335C2.66699 3.41339 2.66699 2.85334 2.88498 2.42552C3.07673 2.04919 3.38269 1.74323 3.75901 1.55148C4.18683 1.3335 4.74689 1.3335 5.86699 1.3335H10.1337C11.2538 1.3335 11.8138 1.3335 12.2416 1.55148C12.618 1.74323 12.9239 2.04919 13.1157 2.42552C13.3337 2.85334 13.3337 3.41339 13.3337 4.5335Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
Expand All @@ -118,20 +118,42 @@
</div>
}

<div class="hidden group-hover:flex shrink-0 items-center px-1 bg-white border-[0.5px] border-gray-100 shadow-md text-gray-500 rounded-lg">
<div class="flex items-center justify-center mr-0.5 w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer"
[matTooltip]="'like'"
matTooltipPosition="above"
>
<i class="ri-thumb-up-line"></i>
</div>
<div class="flex items-center justify-center w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer"
[matTooltip]="'dislike'"
matTooltipPosition="above"
>
<i class="ri-thumb-down-line"></i>
@if (getFeedback(message.id); as feedback) {
@if (feedback.rating === eFeedbackRatingEnum.LIKE) {
<div class="flex items-center justify-center m-1 w-6 h-6 rounded-md cursor-pointer bg-primary-100 text-primary-500 hover:bg-primary-100 hover:text-primary-600"
[matTooltip]="'Cancel like'"
matTooltipPosition="above"
(click)="cancelFeedback(message, feedback.id)"
>
<i class="ri-thumb-up-line"></i>
</div>
} @else if (feedback.rating === eFeedbackRatingEnum.DISLIKE) {
<div class="flex items-center justify-center m-1 w-6 h-6 rounded-md cursor-pointer bg-red-100 text-red-500 hover:bg-red-200 hover:text-red-600"
[matTooltip]="'Cancel dislike'"
matTooltipPosition="above"
(click)="cancelFeedback(message, feedback.id)"
>
<i class="ri-thumb-down-line"></i>
</div>
}
} @else {
<div class="hidden group-hover:flex shrink-0 items-center p-1 bg-white border-[0.5px] border-gray-100 shadow-md text-gray-500 rounded-lg">
<div class="flex items-center justify-center mr-0.5 w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer"
[matTooltip]="'like'"
matTooltipPosition="above"
(click)="feedback(message, eFeedbackRatingEnum.LIKE)"
>
<i class="ri-thumb-up-line"></i>
</div>
<div class="flex items-center justify-center w-6 h-6 rounded-md hover:bg-black/5 hover:text-gray-800 cursor-pointer"
[matTooltip]="'dislike'"
matTooltipPosition="above"
(click)="feedback(message, eFeedbackRatingEnum.DISLIKE)"
>
<i class="ri-thumb-down-line"></i>
</div>
</div>
</div>
}
<!--
<div class="hidden group-hover:block h-[28px] p-0.5 rounded-lg bg-white border-[0.5px] border-gray-100 shadow-sm shrink-0">
<div class="box-border p-0.5 flex items-center justify-center rounded-md bg-white cursor-pointer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import { TranslateModule } from '@ngx-translate/core'
import {
ChatConversationService,
ChatMessageEventTypeEnum,
ChatMessageFeedbackRatingEnum,
ChatMessageFeedbackService,
ChatMessageTypeEnum,
CopilotBaseMessage,
CopilotChatMessage,
getErrorMessage,
IChatMessage,
ToastrService,
uuid,
XpertAgentExecutionService,
Expand Down Expand Up @@ -49,12 +52,14 @@ import { XpertPreviewAiMessageComponent } from './ai-message/message.component'
})
export class XpertStudioPreviewComponent {
eExecutionStatusEnum = XpertAgentExecutionStatusEnum
eFeedbackRatingEnum = ChatMessageFeedbackRatingEnum

readonly xpertService = inject(XpertService)
readonly apiService = inject(XpertStudioApiService)
readonly executionService = inject(XpertExecutionService)
readonly conversationService = inject(ChatConversationService)
readonly agentExecutionService = inject(XpertAgentExecutionService)
readonly messageFeedbackService = inject(ChatMessageFeedbackService)
readonly studioComponent = inject(XpertStudioComponent)
readonly #toastr = inject(ToastrService)
readonly #destroyRef = inject(DestroyRef)
Expand All @@ -77,6 +82,7 @@ export class XpertStudioPreviewComponent {
readonly output = signal('')

readonly conversation = this.executionService.conversation
readonly feedbacks = this.executionService.feedbacks

readonly currentMessage = signal<Partial<CopilotChatMessage>>(null)
readonly messages = computed<CopilotChatMessage[]>(() => {
Expand Down Expand Up @@ -251,4 +257,46 @@ export class XpertStudioPreviewComponent {
this.chat({ reject: true })
this.executionService.conversation.update((state) => ({ ...state, status: 'busy' }))
}

feedback(message: IChatMessage, rating: ChatMessageFeedbackRatingEnum) {
this.messageFeedbackService
.create({
messageId: message.id,
conversationId: message.conversationId,
rating
})
.subscribe({
next: (feedback) => {
this.executionService.feedbacks.update((state) => ({
...(state ?? {}),
[message.id]: feedback
}))
this.#toastr.success('PAC.Messages.UpdatedSuccessfully', {Default: 'Updated successfully'})
},
error: (error) => {
this.#toastr.error(getErrorMessage(error))
}
})
}

cancelFeedback(message: IChatMessage, id: string) {
this.messageFeedbackService
.delete(id)
.subscribe({
next: () => {
this.executionService.feedbacks.update((state) => ({
...(state ?? {}),
[message.id]: null
}))
this.#toastr.success('PAC.Messages.UpdatedSuccessfully', {Default: 'Updated successfully'})
},
error: (error) => {
this.#toastr.error(getErrorMessage(error))
}
})
}

getFeedback(id: string) {
return this.feedbacks()?.[id]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@ import { computed, effect, inject, Injectable, signal } from '@angular/core'
import { toObservable } from '@angular/core/rxjs-interop'
import {
ChatConversationService,
ChatMessageFeedbackService,
CopilotChatMessage,
IChatConversation,
IChatMessageFeedback,
IXpertAgentExecution,
} from 'apps/cloud/src/app/@core'
import { of, switchMap } from 'rxjs'
import { combineLatest, of, switchMap } from 'rxjs'

@Injectable()
export class XpertExecutionService {
readonly conversationService = inject(ChatConversationService)
readonly feedbackService = inject(ChatMessageFeedbackService)

readonly conversationId = signal<string>(null)

readonly conversation = signal<IChatConversation>(null)
readonly feedbacks = signal<Record<string, IChatMessageFeedback>>(null)

readonly #messages = signal<Partial<CopilotChatMessage>[]>([])

Expand Down Expand Up @@ -53,9 +57,16 @@ export class XpertExecutionService {

// Subsribe conversation
private conversationSub = toObservable(this.conversationId).pipe(
switchMap((id) => id ? this.conversationService.getById(this.conversationId(), { relations: ['_messages'] }) : of(null))
).subscribe((conv) => {
switchMap((id) => id ? combineLatest([
this.conversationService.getById(this.conversationId(), { relations: ['_messages'] }),
this.feedbackService.getAll({ where: { conversationId: this.conversationId(), } })
]) : of([]))
).subscribe(([conv, feedbacks]) => {
this.conversation.set(conv)
this.feedbacks.set(feedbacks?.items.reduce((acc, feedback) => {
acc[feedback.messageId] = feedback
return acc
}, {}))
})

constructor() {
Expand Down
15 changes: 14 additions & 1 deletion packages/contracts/src/ai/chat-message-feedback.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,28 @@ import { IBasePerTenantAndOrganizationEntityModel } from '../base-entity.model'
import { IChatMessage } from './chat-message.model'
import { IChatConversation } from './chat.model'

export enum ChatMessageFeedbackRatingEnum {
LIKE = 'like',
DISLIKE = 'dislike'
}

export type TSummaryJob = {
jobId: number | string;
status: string
progress?: number
}

/**
*
*/
export interface IChatMessageFeedback extends IBasePerTenantAndOrganizationEntityModel {

rating: string
rating: ChatMessageFeedbackRatingEnum

content?: string

summaryJob: TSummaryJob

// Many to one
/**
* Chat conversation
Expand Down
25 changes: 15 additions & 10 deletions packages/server-ai/src/chat-conversation/conversation.module.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import { forwardRef, Module } from '@nestjs/common'
import { SharedModule } from '@metad/server-core'
import { BullModule } from '@nestjs/bull'
import { Module, forwardRef } from '@nestjs/common'
import { CqrsModule } from '@nestjs/cqrs'
import { TypeOrmModule } from '@nestjs/typeorm'
import { RouterModule } from 'nest-router'
import { ChatConversation } from './conversation.entity'
import { TenantModule } from '@metad/server-core'
import { SharedModule } from '@metad/server-core'
import { CopilotCheckpointModule } from '../copilot-checkpoint'
import { CommandHandlers } from './commands/handlers'
import { ChatConversationController } from './conversation.controller'
import { ChatConversation } from './conversation.entity'
import { ChatConversationService } from './conversation.service'
import { CommandHandlers } from './commands/handlers'
import { QueryHandlers } from './queries/handlers'
import { ConversationSummaryProcessor } from './summary.job'
import { ChatMessageModule } from '../chat-message/chat-message.module'

@Module({
imports: [
RouterModule.forRoutes([{ path: '/chat-conversation', module: ChatConversationModule }]),
forwardRef(() => TypeOrmModule.forFeature([ChatConversation])),
forwardRef(() => TenantModule),
TypeOrmModule.forFeature([ChatConversation]),
SharedModule,
CqrsModule,
CopilotCheckpointModule

BullModule.registerQueue({
name: 'conversation-summary'
}),
forwardRef(() => ChatMessageModule)
],
controllers: [ChatConversationController],
providers: [ChatConversationService, ...CommandHandlers, ...QueryHandlers]
providers: [ChatConversationService, ConversationSummaryProcessor, ...CommandHandlers, ...QueryHandlers],
exports: [ChatConversationService]
})
export class ChatConversationModule {}
29 changes: 24 additions & 5 deletions packages/server-ai/src/chat-conversation/conversation.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { PaginationParams, TenantOrganizationAwareCrudService } from '@metad/server-core'
import { PaginationParams, RequestContext, TenantOrganizationAwareCrudService } from '@metad/server-core'
import { InjectQueue } from '@nestjs/bull'
import { Injectable, Logger } from '@nestjs/common'
import { CommandBus, QueryBus } from '@nestjs/cqrs'
import { InjectRepository } from '@nestjs/typeorm'
import { Queue } from 'bull'
import { DeepPartial, Repository } from 'typeorm'
import { FindAgentExecutionsQuery } from '../xpert-agent-execution/queries'
import { ChatConversation } from './conversation.entity'
Expand All @@ -13,11 +15,12 @@ export class ChatConversationService extends TenantOrganizationAwareCrudService<

constructor(
@InjectRepository(ChatConversation)
chatRepository: Repository<ChatConversation>,
repository: Repository<ChatConversation>,
readonly commandBus: CommandBus,
readonly queryBus: QueryBus
readonly queryBus: QueryBus,
@InjectQueue('conversation-summary') private summaryQueue: Queue
) {
super(chatRepository)
super(repository)
}

async findAllByXpert(xpertId: string, options: PaginationParams<ChatConversation>) {
Expand All @@ -32,7 +35,10 @@ export class ChatConversationService extends TenantOrganizationAwareCrudService<
async findOneDetail(id: string, options: DeepPartial<PaginationParams<ChatConversation>>) {
// Split executions relation
const { relations } = options ?? {}
const entity = await this.findOne(id, { ...(options ?? {}), relations: relations?.filter((_) => _ !== 'executions') })
const entity = await this.findOne(id, {
...(options ?? {}),
relations: relations?.filter((_) => _ !== 'executions')
})

let executions = null
if (relations?.includes('executions')) {
Expand All @@ -47,4 +53,17 @@ export class ChatConversationService extends TenantOrganizationAwareCrudService<
executions
})
}

async triggerSummary(conversationId: string, messageId: string, feedbackId?: string) {
return await this.summaryQueue.add({
conversationId,
messageId,
userId: RequestContext.currentUserId(),
feedbackId
})
}

async getJob(id: number | string ) {
return await this.summaryQueue.getJob(id)
}
}
Loading