diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 2e4dc0ae..92669888 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -16,6 +16,12 @@ const routes: Routes = [ { path: 'profile', loadChildren: () => import('./profile/profile.module').then((m) => m.ProfileModule) }, ]), Shell.childRoutes([{ path: 'chat', loadChildren: () => import('./chat/chat.module').then((m) => m.ChatModule) }]), + + Shell.childRoutes([{ path: 'chats', loadChildren: () => import('./chat/chat.module').then((m) => m.ChatModule) }]), + Shell.childRoutes([ + { path: 'chats/:id', loadChildren: () => import('./chat/chat.module').then((m) => m.ChatModule) }, + ]), + Shell.childRoutes([ { path: 'code-reviews', diff --git a/frontend/src/app/chat/chat.component.html b/frontend/src/app/chat/chat.component.html index ddb1a3d3..e92e69e9 100644 --- a/frontend/src/app/chat/chat.component.html +++ b/frontend/src/app/chat/chat.component.html @@ -1,10 +1,38 @@ - - - Chat - - - + + + + +
+ + - - - + +
+ + + + + +
+ + + +
+
+
diff --git a/frontend/src/app/chat/chat.component.scss b/frontend/src/app/chat/chat.component.scss index e69de29b..5b16a085 100644 --- a/frontend/src/app/chat/chat.component.scss +++ b/frontend/src/app/chat/chat.component.scss @@ -0,0 +1,3 @@ +img { + border-radius: 50%; +} diff --git a/frontend/src/app/chat/chat.component.ts b/frontend/src/app/chat/chat.component.ts index fda34352..36608644 100644 --- a/frontend/src/app/chat/chat.component.ts +++ b/frontend/src/app/chat/chat.component.ts @@ -1,16 +1,65 @@ -import { Component, OnInit } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { Router } from '@angular/router'; +import { Component, OnInit, Input } from '@angular/core'; +import { FirebaseChatService } from './services/firebase/firebase-chat.service'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; +// import { FirebaseAuthService } from './services/firebase/firebase-auth.service'; +import { Message } from './model/message'; +import { Chat } from '@app/chat/model/chat'; @Component({ - selector: 'app-code-review-list', + selector: 'app-chat', templateUrl: './chat.component.html', styleUrls: ['./chat.component.scss'], }) export class ChatComponent implements OnInit { - isLoading: boolean = true; + @Input() height: string = ''; + @Input() width: string = ''; - constructor(private router: Router, private dialog: MatDialog) {} + user: any = {}; - ngOnInit() {} + chat$?: Observable; + + messages: Message[] = []; + + constructor( + public chatService: FirebaseChatService, + private route: ActivatedRoute + ) // public auth: FirebaseAuthService + {} + + ngOnInit() { + const chatId: string | null = this.route.snapshot.paramMap.get('id'); + if (!chatId) return; + // TODO: first load already existing history + // TODO: listen on changes + const source = this.chatService.getHistory(chatId); + // this.chat$ = this.chatService.buildChat(source).pipe( + // tap(res => this.integrateNewMessages(res)), + // tap(() => this.scrollBottom()) + // ); + } + + private integrateNewMessages(chat: Chat) { + const newMessages = chat.messages.filter( + (newMessage: Message) => !this.messages.some((message: Message) => this.isSameMessage(message, newMessage)) + ); + newMessages.forEach((msg) => this.messages.push(msg)); + } + + private isSameMessage(message: Message, newMessage: Message): boolean { + return ( + message.content === newMessage.content && + message.uid === newMessage.uid && + message.createdAt === newMessage.createdAt + ); + } + + trackByCreated(index: number, msg: Message) { + return msg.createdAt; + } + + private scrollBottom() { + setTimeout(() => window.scrollTo(0, document.body.scrollHeight), 500); + } } diff --git a/frontend/src/app/chat/chat.module.ts b/frontend/src/app/chat/chat.module.ts index 7500c1b9..44414c84 100644 --- a/frontend/src/app/chat/chat.module.ts +++ b/frontend/src/app/chat/chat.module.ts @@ -6,9 +6,12 @@ import { FlexLayoutModule } from '@angular/flex-layout'; import { MaterialModule } from '@app/material.module'; import { ChatRoutingModule } from '@app/chat/chat-routing.module'; import { ChatComponent } from '@app/chat/chat.component'; +import { ChatControlsComponent } from '@app/chat/chat-controls/chat-controls.component'; +import { ChatMessageComponent } from '@app/chat/chat-message/chat-message.component'; +import { ChatHeaderComponent } from '@app/chat/chat-header/chat-header.component'; @NgModule({ imports: [CommonModule, TranslateModule, FlexLayoutModule, MaterialModule, ChatRoutingModule], - declarations: [ChatComponent], + declarations: [ChatComponent, ChatControlsComponent, ChatMessageComponent, ChatHeaderComponent], }) export class ChatModule {} diff --git a/frontend/src/app/chat/model/chat.ts b/frontend/src/app/chat/model/chat.ts new file mode 100644 index 00000000..a9548bd0 --- /dev/null +++ b/frontend/src/app/chat/model/chat.ts @@ -0,0 +1,12 @@ +import { Message } from './message'; + +export interface Chat { + id?: string; + uid?: string; + createdAt: number; + count: number; + messages: Message[]; + participants: string[]; + ownerId: string; + typing: string[]; +} diff --git a/frontend/src/app/chat/model/message.ts b/frontend/src/app/chat/model/message.ts new file mode 100644 index 00000000..377b8fcc --- /dev/null +++ b/frontend/src/app/chat/model/message.ts @@ -0,0 +1,13 @@ +import { User } from './user'; + +export interface Attachment { + name: string; +} + +export interface Message { + content: string; + uid: string; + createdAt: number; + user: User; + attachments: Attachment[]; +} diff --git a/frontend/src/app/chat/model/user.ts b/frontend/src/app/chat/model/user.ts new file mode 100644 index 00000000..9f42b7e5 --- /dev/null +++ b/frontend/src/app/chat/model/user.ts @@ -0,0 +1,6 @@ +export interface User { + uid: string; + email: string; + displayName: string; + photoUrl: string; +} diff --git a/frontend/src/app/chat/services/api/api-chat.service.spec.ts b/frontend/src/app/chat/services/api/api-chat.service.spec.ts new file mode 100644 index 00000000..ea14a857 --- /dev/null +++ b/frontend/src/app/chat/services/api/api-chat.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { ApiChatService } from './api-chat.service'; + +describe('ApiChatService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: ApiChatService = TestBed.get(ApiChatService); + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/chat/services/api/api-chat.service.ts b/frontend/src/app/chat/services/api/api-chat.service.ts new file mode 100644 index 00000000..3167a4d7 --- /dev/null +++ b/frontend/src/app/chat/services/api/api-chat.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import { ChatBaseService } from '../chat-base.service'; +import { Message } from '../../model/message'; +import { Chat } from '../../model/chat'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class ApiChatService extends ChatBaseService { + constructor() { + super(); + } + + create(): Promise { + return undefined; + } + + deleteIsTyping(chatId: string): Promise { + return undefined; + } + + deleteMessage(chat: Chat, msg: Message): Promise { + return undefined; + } + + getHistory(chatId: string): Observable { + return undefined; + } + + sendIsTyping(chatId: string): Promise { + return undefined; + } + + sendMessage(chatId: string, content: string): Promise { + return undefined; + } + + buildChat(source: Observable) {} +} diff --git a/frontend/src/app/chat/services/chat-base.service.ts b/frontend/src/app/chat/services/chat-base.service.ts new file mode 100644 index 00000000..9158cf02 --- /dev/null +++ b/frontend/src/app/chat/services/chat-base.service.ts @@ -0,0 +1,27 @@ +import { Message } from '../model/message'; +import { Chat } from '../model/chat'; +import { Observable } from 'rxjs'; +import { ServicesConfig } from './services-config'; +import { Injectable, Optional } from '@angular/core'; + +export abstract class ChatBaseService { + constructor(@Optional() config?: ServicesConfig) { + if (config) { + console.log('Config:', config); + } + } + + abstract getHistory(chatId: string): Observable; + + // abstract create(): Promise; + // + // abstract sendMessage(chatId: string, content: string): Promise; + // + // abstract deleteMessage(chat: Chat, msg: Message): Promise; + // + // abstract sendIsTyping(chatId: string): Promise; + // + // abstract deleteIsTyping(chatId: string): Promise; + // + // abstract buildChat(source: Observable) ; +} diff --git a/frontend/src/app/chat/services/firebase/firebase-chat.service.ts b/frontend/src/app/chat/services/firebase/firebase-chat.service.ts new file mode 100644 index 00000000..a9262933 --- /dev/null +++ b/frontend/src/app/chat/services/firebase/firebase-chat.service.ts @@ -0,0 +1,166 @@ +import { Injectable, Optional } from '@angular/core'; +import { Router } from '@angular/router'; +import { map, tap, switchMap, flatMap } from 'rxjs/operators'; +import { Observable, combineLatest, of, merge } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { User } from '../../model/user'; +import { ChatBaseService } from '../chat-base.service'; +import { Message } from '../../model/message'; +import { Chat } from '../../model/chat'; +import { ServicesConfig } from '../services-config'; +import * as moment from 'moment'; + +@Injectable({ + providedIn: 'root', +}) +export class FirebaseChatService extends ChatBaseService { + userDictionary = {}; + + constructor( + // private auth: FirebaseAuthService, + private router: Router, + @Optional() config?: ServicesConfig + ) { + super(config); + } + + getHistory(chatId: string): Observable { + return new Observable(); + } + + getParticipatingChats() { + // return this.auth.user$.pipe( + // switchMap(user => { + // const participatingChats = this.afs + // .collection('chats', (ref: any) => + // ref.where('participants', 'array-contains', user.uid) + // ) + // .snapshotChanges(); + // return participatingChats.pipe( + // map((actions: any) => { + // return actions.map((a: any) => { + // const chatData: any = a.payload.doc.data(); + // const id = a.payload.doc.id; + // return { id, ...chatData }; + // }); + // }) + // ); + // }) + // ); + } + + async create(): Promise { + // Fetch user and wait for result + // const { uid } = await this.auth.getUser(); + const uid = 'uid'; + + // Init new chat data + const data: Chat = { + id: '12354', // TODO generate guid + createdAt: Date.now(), + count: 0, + messages: [], + participants: [uid], + ownerId: uid, + typing: [], + }; + + // Add new chat data to firestore and wait for result + // TODO save chat + + // Route to new chat in chat component + return this.router.navigate(['chats', data.id]); + } + + async sendIsTyping(chatId: string): Promise { + // const { uid } = await this.auth.getUser(); + const uid = 'uid'; + + // if (uid) { + // const ref = this.afs.collection('chats').doc(chatId); + // return ref.update({ + // typing: firebase.firestore.FieldValue.arrayUnion(uid) + // }); + // } + } + + async deleteIsTyping(chatId: string): Promise { + // const { uid } = await this.auth.getUser(); + // + // if (uid) { + // const ref = this.afs.collection('chats').doc(chatId); + // return ref.update({ + // typing: firebase.firestore.FieldValue.arrayRemove(uid) + // }); + // } + } + + async sendMessage(chatId: string, content: string): Promise { + // const { uid } = await this.auth.getUser(); + // + // const data = { + // uid, + // content, + // createdAt: firebase.firestore.Timestamp.now() + // }; + // + // if (uid) { + // const ref = this.afs.collection('chats').doc(chatId); + // return ref.update({ + // messages: firebase.firestore.FieldValue.arrayUnion(data) + // }); + // } + } + // + async deleteMessage(chat: Chat, msg: Message) { + // const { uid } = await this.auth.getUser(); + // + // const ref = this.afs.collection('chats').doc(chat.id); + // if (chat.uid === uid || msg.uid === uid) { + // delete msg.user; + // return ref.update({ + // messages: firebase.firestore.FieldValue.arrayRemove(msg) + // }); + // } + } + // + // buildChat(chat$: Observable): Observable { + // let chat: any; + // + // return chat$.pipe( + // switchMap(c => { + // chat = c; + // // Get all users in the chat -> find user data since only uid is known + // const uids = Array.from( + // new Set(c.messages.map((message: any) => message.uid)) + // ); + // const users = this.fetchUsers(uids); + // return users.length ? combineLatest(users) : of([]); + // }), + // map(users => { + // this.buildUserDictionary(users); + // // Augment message data with newly fetched user data + // chat.messages = chat.messages.map((message: any) => { + // return { + // ...message, + // createdAt: moment(message.createdAt.toDate()), + // user: this.userDictionary[message.uid] + // }; + // }); + // return chat; + // }) + // ); + // } + // + // private buildUserDictionary(users: unknown[]) { + // users.forEach(user => (this.userDictionary[(user as User).uid] = user)); + // } + // + // private fetchUsers(uids: unknown[]): Observable[] { + // return uids.map(uid => this.afs.doc(`users/${uid}`).valueChanges()); + // } + // + // getUserById(typerId) { + // return this.userDictionary[typerId]; + // } +} diff --git a/frontend/src/app/chat/services/services-config.ts b/frontend/src/app/chat/services/services-config.ts new file mode 100644 index 00000000..f8278087 --- /dev/null +++ b/frontend/src/app/chat/services/services-config.ts @@ -0,0 +1,12 @@ +export class ServicesConfig { + firebase: + | { + chat: string; + } + | undefined; + apiEndpoints: + | { + history: string; + } + | undefined; +} diff --git a/frontend/src/app/chat/services/services.module.ts b/frontend/src/app/chat/services/services.module.ts new file mode 100644 index 00000000..2ca4af19 --- /dev/null +++ b/frontend/src/app/chat/services/services.module.ts @@ -0,0 +1,27 @@ +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ChatBaseService } from './chat-base.service'; +import { ServicesConfig } from './services-config'; + +/** + * Help: https://angular.io/guide/singleton-services + */ + +@NgModule({ + declarations: [], + imports: [CommonModule], +}) +export class ServicesModule { + constructor(@Optional() @SkipSelf() parentModule?: ServicesModule) { + if (parentModule) { + throw new Error('GreetingModule is already loaded. Import it in the AppModule only'); + } + } + + static forRoot(config: ServicesConfig): ModuleWithProviders { + return { + ngModule: ServicesModule, + providers: [{ provide: ServicesConfig, useValue: config }], + }; + } +} diff --git a/src/agent/agentStateService/agentStateService.int.ts b/src/agent/agentStateService/agentStateService.int.ts index 28aa364f..22ccb7be 100644 --- a/src/agent/agentStateService/agentStateService.int.ts +++ b/src/agent/agentStateService/agentStateService.int.ts @@ -2,7 +2,7 @@ import fs from 'fs'; import { expect } from 'chai'; import { AgentContext } from '#agent/agentContextTypes'; import { AgentStateService } from '#agent/agentStateService/agentStateService'; -import { FirestoreAgentStateService } from '#agent/agentStateService/firestoreAgentStateService'; +import { FirestoreAgentStateService } from '#modules/firestore/firestoreAgentStateService'; describe('AgentStateService Integration Tests', () => { let service: AgentStateService; diff --git a/src/app.ts b/src/app.ts index c00d9af9..b383efe2 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,17 +1,17 @@ import { AgentStateService } from '#agent/agentStateService/agentStateService'; import { FileAgentStateService } from '#agent/agentStateService/fileAgentStateService'; -import { FirestoreAgentStateService } from '#agent/agentStateService/firestoreAgentStateService'; import { InMemoryAgentStateService } from '#agent/agentStateService/inMemoryAgentStateService'; import { RouteDefinition } from '#fastify/fastifyApp'; -import { FirestoreLlmCallService } from '#llm/llmCallService/firestoreLlmCallService'; import { InMemoryLlmCallService } from '#llm/llmCallService/inMemoryLlmCallService'; import { LlmCallService } from '#llm/llmCallService/llmCallService'; +import { FirestoreAgentStateService } from '#modules/firestore/firestoreAgentStateService'; +import { FirestoreCodeReviewService } from '#modules/firestore/firestoreCodeReviewService'; +import { FirestoreLlmCallService } from '#modules/firestore/firestoreLlmCallService'; +import { FirestoreUserService } from '#modules/firestore/firestoreUserService'; import { logger } from '#o11y/logger'; import { CodeReviewService } from '#swe/codeReview/codeReviewService'; -import { FirestoreCodeReviewService } from '#swe/codeReview/firestoreCodeReviewService'; import { InMemoryCodeReviewService } from '#swe/codeReview/memoryCodeReviewService'; import { FileUserService } from '#user/userService/fileUserService'; -import { FirestoreUserService } from '#user/userService/firestoreUserService'; import { InMemoryUserService } from '#user/userService/inMemoryUserService'; import { UserService } from '#user/userService/userService'; import { FileFunctionCacheService } from './cache/fileFunctionCacheService'; diff --git a/src/chat/chatTypes.ts b/src/chat/chatTypes.ts new file mode 100644 index 00000000..d6c8ac28 --- /dev/null +++ b/src/chat/chatTypes.ts @@ -0,0 +1,13 @@ +import { LlmMessage } from '#llm/llm'; + +export interface Chat { + id: string; + /** When a chat is branched from the original thread by deleting/updating messages etc */ + parentId?: string; + messages: LlmMessage[]; +} + +export interface ChatService { + loadChat(chatId: string): Promise; + saveChat(chatId: string, messages: LlmMessage[]): Promise; +} diff --git a/src/fastify/hooks.ts b/src/fastify/hooks.ts index 93830fd0..48f9a175 100644 --- a/src/fastify/hooks.ts +++ b/src/fastify/hooks.ts @@ -1,6 +1,6 @@ import { FastifyInstance } from 'fastify'; +import { DEFAULT_HEALTHCHECK } from '#fastify/fastifyApp'; import { sendBadRequest } from './responses'; -import {DEFAULT_HEALTHCHECK} from "#fastify/fastifyApp"; export interface RouteInterface { method: string | string[]; diff --git a/src/agent/agentStateService/firestoreAgentStateService.ts b/src/modules/firestore/firestoreAgentStateService.ts similarity index 97% rename from src/agent/agentStateService/firestoreAgentStateService.ts rename to src/modules/firestore/firestoreAgentStateService.ts index 0bd7fdbf..d95e9a44 100644 --- a/src/agent/agentStateService/firestoreAgentStateService.ts +++ b/src/modules/firestore/firestoreAgentStateService.ts @@ -2,11 +2,11 @@ import { DocumentSnapshot, Firestore } from '@google-cloud/firestore'; import { LlmFunctions } from '#agent/LlmFunctions'; import { deserializeAgentContext, serializeContext } from '#agent/agentContextLocalStorage'; import { AgentContext, AgentRunningState } from '#agent/agentContextTypes'; +import { AgentStateService } from '#agent/agentStateService/agentStateService'; import { functionFactory } from '#functionSchema/functionDecorators'; import { logger } from '#o11y/logger'; import { span } from '#o11y/trace'; import { firestoreDb } from '../../firestore'; -import { AgentStateService } from './agentStateService'; /** * Google Firestore implementation of AgentStateService diff --git a/src/modules/firestore/firestoreChatService.ts b/src/modules/firestore/firestoreChatService.ts new file mode 100644 index 00000000..638c47c6 --- /dev/null +++ b/src/modules/firestore/firestoreChatService.ts @@ -0,0 +1,57 @@ +import { Firestore } from '@google-cloud/firestore'; +import { Chat, ChatService } from '#chat/chatTypes'; +import { LlmMessage } from '#llm/llm'; +import { logger } from '#o11y/logger'; +import { span } from '#o11y/trace'; +import { firestoreDb } from '../../firestore'; + +/** + * Google Firestore implementation of ChatService + */ +export class FirestoreChatService implements ChatService { + private db: Firestore; + + constructor() { + this.db = firestoreDb(); + } + + @span() + async loadChat(chatId: string): Promise { + try { + const docRef = this.db.doc(`Chats/${chatId}`); + const docSnap = await docRef.get(); + + if (!docSnap.exists) { + logger.warn(`Chat with id ${chatId} not found`); + throw new Error(`Chat with id ${chatId} not found`); + } + + const data = docSnap.data(); + return { + id: chatId, + parentId: data.parentId, + messages: data.messages, + }; + } catch (error) { + logger.error(error, `Error loading chat ${chatId}`); + throw error; + } + } + + @span() + async saveChat(chatId: string, messages: LlmMessage[]): Promise { + try { + const docRef = this.db.doc(`Chats/${chatId}`); + const chat: Chat = { + id: chatId, + messages, + }; + + await docRef.set(chat, { merge: true }); + return chat; + } catch (error) { + logger.error(error, `Error saving chat ${chatId}`); + throw error; + } + } +} diff --git a/src/swe/codeReview/firestoreCodeReviewService.test.ts b/src/modules/firestore/firestoreCodeReviewService.test.ts similarity index 100% rename from src/swe/codeReview/firestoreCodeReviewService.test.ts rename to src/modules/firestore/firestoreCodeReviewService.test.ts diff --git a/src/swe/codeReview/firestoreCodeReviewService.ts b/src/modules/firestore/firestoreCodeReviewService.ts similarity index 98% rename from src/swe/codeReview/firestoreCodeReviewService.ts rename to src/modules/firestore/firestoreCodeReviewService.ts index 19bf8bcd..bb3bb080 100644 --- a/src/swe/codeReview/firestoreCodeReviewService.ts +++ b/src/modules/firestore/firestoreCodeReviewService.ts @@ -2,7 +2,6 @@ import { DocumentSnapshot, Firestore } from '@google-cloud/firestore'; import { logger } from '#o11y/logger'; import { CodeReviewConfig } from '#swe/codeReview/codeReviewModel'; import { CodeReviewService } from '#swe/codeReview/codeReviewService'; -import { envVar } from '#utils/env-var'; import { firestoreDb } from '../../firestore'; export class FirestoreCodeReviewService implements CodeReviewService { diff --git a/src/llm/llmCallService/firestoreLlmCallService.test.ts b/src/modules/firestore/firestoreLlmCallService.test.ts similarity index 98% rename from src/llm/llmCallService/firestoreLlmCallService.test.ts rename to src/modules/firestore/firestoreLlmCallService.test.ts index 84e5d120..a550dce5 100644 --- a/src/llm/llmCallService/firestoreLlmCallService.test.ts +++ b/src/modules/firestore/firestoreLlmCallService.test.ts @@ -3,9 +3,9 @@ import { expect } from 'chai'; import sinon from 'sinon'; import { logger } from '#o11y/logger'; -import { FirestoreLlmCallService } from '#llm/llmCallService/firestoreLlmCallService'; import { CreateLlmRequest, LlmCall } from '#llm/llmCallService/llmCall'; import { LlmCallService } from '#llm/llmCallService/llmCallService'; +import { FirestoreLlmCallService } from '#modules/firestore/firestoreLlmCallService'; const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST; diff --git a/src/llm/llmCallService/firestoreLlmCallService.ts b/src/modules/firestore/firestoreLlmCallService.ts similarity index 100% rename from src/llm/llmCallService/firestoreLlmCallService.ts rename to src/modules/firestore/firestoreLlmCallService.ts diff --git a/src/user/userService/firestoreUserService.test.ts b/src/modules/firestore/firestoreUserService.test.ts similarity index 95% rename from src/user/userService/firestoreUserService.test.ts rename to src/modules/firestore/firestoreUserService.test.ts index 4effd16e..cc822ed3 100644 --- a/src/user/userService/firestoreUserService.test.ts +++ b/src/modules/firestore/firestoreUserService.test.ts @@ -1,11 +1,11 @@ import { fail } from 'node:assert'; import axios from 'axios'; import { assert, expect } from 'chai'; -import { FirestoreLlmCallService } from '#llm/llmCallService/firestoreLlmCallService'; +import { FirestoreLlmCallService } from '#modules/firestore/firestoreLlmCallService'; import { logger } from '#o11y/logger'; -import { User } from '../user'; +import { User } from '#user/user'; +import { InMemoryUserService } from '#user/userService/inMemoryUserService'; import { FirestoreUserService } from './firestoreUserService'; -import { InMemoryUserService } from './inMemoryUserService'; const emulatorHost = process.env.FIRESTORE_EMULATOR_HOST; diff --git a/src/user/userService/firestoreUserService.ts b/src/modules/firestore/firestoreUserService.ts similarity index 97% rename from src/user/userService/firestoreUserService.ts rename to src/modules/firestore/firestoreUserService.ts index ce75339f..081d2fac 100644 --- a/src/user/userService/firestoreUserService.ts +++ b/src/modules/firestore/firestoreUserService.ts @@ -2,10 +2,10 @@ import { DocumentSnapshot, Firestore } from '@google-cloud/firestore'; import { LlmCall } from '#llm/llmCallService/llmCall'; import { logger } from '#o11y/logger'; import { span } from '#o11y/trace'; +import { User } from '#user/user'; import { isSingleUser } from '#user/userService/userContext'; +import { UserService } from '#user/userService/userService'; import { envVar } from '#utils/env-var'; -import { User } from '../user'; -import { UserService } from './userService'; /*** Google Firestore implementation of UserService*/ export class FirestoreUserService implements UserService { diff --git a/tsconfig.json b/tsconfig.json index 7425d321..86e3effc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,9 @@ "baseUrl": "./", "paths": { "#agent/*": ["./src/agent/*"], + "#chat/*": ["./src/chat/*"], "#fastify/*": ["./src/fastify/*"], + "#firestore*": ["./src/modules/firestore*"], "#functionSchema/*": ["./src/functionSchema/*"], "#functions/*": ["./src/functions/*"], "#llm/*": ["./src/llm/*"], @@ -29,6 +31,7 @@ "#o11y/*": ["./src/o11y/*"], "#services/*": ["./src/services/*"], "#modules/*": ["./src/modules/*"], + "#slack/*": ["./src/modules/slack/*"], "#swe/*": ["./src/swe/*"], "#user/*": ["./src/user/*"], "#utils/*": ["./src/utils/*"]