mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-29 13:05:08 +02:00
Move bot (#6268)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
||||
@@ -0,0 +1 @@
|
||||
tsdoc-metadata.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "@hcengineering/server-ai-bot-resources",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*",
|
||||
"types/**/*",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"author": "Hardcore Engineering Inc.",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"format": "format src",
|
||||
"test": "jest --passWithNoTests --silent",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:test": "jest --passWithNoTests --silent",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.1.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/activity": "^0.6.0",
|
||||
"@hcengineering/chunter": "^0.6.20",
|
||||
"@hcengineering/contact": "^0.6.24",
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/mongo": "^0.6.1",
|
||||
"@hcengineering/notification": "^0.6.23",
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/server-activity-resources": "^0.6.0",
|
||||
"@hcengineering/server-core": "^0.6.1",
|
||||
"@hcengineering/server-templates": "^0.6.0",
|
||||
"@hcengineering/templates": "^0.6.11",
|
||||
"@hcengineering/ai-bot": "^0.6.0",
|
||||
"@hcengineering/server-ai-bot": "^0.6.0",
|
||||
"@hcengineering/analytics-collector": "^0.6.0",
|
||||
"mongodb": "^6.8.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { MeasureContext, WorkspaceId } from '@hcengineering/core'
|
||||
import { getMongoClient, MongoClientReference } from '@hcengineering/mongo'
|
||||
import { AIBotServiceAdapter, WorkspaceInfoRecord } from '@hcengineering/server-ai-bot'
|
||||
import { Collection, Db, MongoClient } from 'mongodb'
|
||||
|
||||
class AIBotAdapter implements AIBotServiceAdapter {
|
||||
private readonly workspacesInfoCollection: Collection<WorkspaceInfoRecord>
|
||||
private readonly db: Db
|
||||
closed = false
|
||||
|
||||
constructor (
|
||||
private readonly _client: MongoClientReference,
|
||||
private readonly client: MongoClient,
|
||||
private readonly _metrics: MeasureContext,
|
||||
private readonly dbName: string
|
||||
) {
|
||||
this.db = client.db(dbName)
|
||||
this.workspacesInfoCollection = this.db.collection<WorkspaceInfoRecord>('workspacesInfo')
|
||||
}
|
||||
|
||||
async processWorkspace (workspace: WorkspaceId): Promise<void> {
|
||||
if (this.closed) {
|
||||
return
|
||||
}
|
||||
const existsRecord = await this.workspacesInfoCollection.findOne({
|
||||
workspace: workspace.name,
|
||||
productId: workspace.productId
|
||||
})
|
||||
|
||||
if (existsRecord != null && !existsRecord.active) {
|
||||
await this.workspacesInfoCollection.updateOne(
|
||||
{ workspace: workspace.name, productId: workspace.productId },
|
||||
{ $set: { active: true } }
|
||||
)
|
||||
} else if (existsRecord == null) {
|
||||
const record: WorkspaceInfoRecord = {
|
||||
workspace: workspace.name,
|
||||
productId: workspace.productId,
|
||||
active: true
|
||||
}
|
||||
|
||||
await this.workspacesInfoCollection.insertOne(record)
|
||||
}
|
||||
}
|
||||
|
||||
async close (): Promise<void> {
|
||||
this.closed = true
|
||||
this._client.close()
|
||||
}
|
||||
|
||||
metrics (): MeasureContext {
|
||||
return this._metrics
|
||||
}
|
||||
}
|
||||
|
||||
export async function createAIBotAdapter (url: string, db: string, metrics: MeasureContext): Promise<any> {
|
||||
const _client = getMongoClient(url)
|
||||
|
||||
return new AIBotAdapter(_client, await _client.getClient(), metrics, db)
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, {
|
||||
AccountRole,
|
||||
AttachedDoc,
|
||||
Data,
|
||||
Doc,
|
||||
Ref,
|
||||
toWorkspaceString,
|
||||
Tx,
|
||||
TxCollectionCUD,
|
||||
TxCreateDoc,
|
||||
TxCUD,
|
||||
TxProcessor,
|
||||
TxUpdateDoc,
|
||||
UserStatus
|
||||
} from '@hcengineering/core'
|
||||
import { TriggerControl } from '@hcengineering/server-core'
|
||||
import chunter, { ChatMessage, DirectMessage, ThreadMessage } from '@hcengineering/chunter'
|
||||
import aiBot, { aiBotAccountEmail, AIBotResponseEvent } from '@hcengineering/ai-bot'
|
||||
import serverAIBot, { AIBotServiceAdapter, serverAiBotId } from '@hcengineering/server-ai-bot'
|
||||
import contact, { PersonAccount } from '@hcengineering/contact'
|
||||
import { ActivityInboxNotification, MentionInboxNotification } from '@hcengineering/notification'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import analytics from '@hcengineering/analytics-collector'
|
||||
|
||||
async function processWorkspace (control: TriggerControl): Promise<void> {
|
||||
const adapter = control.serviceAdaptersManager.getAdapter(serverAiBotId) as AIBotServiceAdapter | undefined
|
||||
|
||||
if (adapter !== undefined) {
|
||||
await adapter.processWorkspace(control.workspace)
|
||||
} else {
|
||||
console.error('Cannot find server adapter: ', serverAiBotId)
|
||||
}
|
||||
}
|
||||
|
||||
async function isDirectAvailable (direct: DirectMessage, control: TriggerControl): Promise<boolean> {
|
||||
const { members } = direct
|
||||
|
||||
if (!members.includes(aiBot.account.AIBot)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const personAccounts = await control.modelDb.findAll(contact.class.PersonAccount, {
|
||||
_id: { $in: members as Ref<PersonAccount>[] }
|
||||
})
|
||||
const persons = new Set(personAccounts.map((account) => account.person))
|
||||
|
||||
return persons.size === 2
|
||||
}
|
||||
|
||||
async function isAvailableDoc (doc: Doc, control: TriggerControl): Promise<boolean> {
|
||||
if (doc._class === chunter.class.DirectMessage) {
|
||||
return await isDirectAvailable(doc as DirectMessage, control)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
async function getMessageDoc (message: ChatMessage, control: TriggerControl): Promise<Doc | undefined> {
|
||||
if (control.hierarchy.isDerived(message._class, chunter.class.ThreadMessage)) {
|
||||
const thread = message as ThreadMessage
|
||||
const _id = thread.objectId
|
||||
const _class = thread.objectClass
|
||||
|
||||
return (await control.findAll(_class, { _id }))[0]
|
||||
} else {
|
||||
const _id = message.attachedTo
|
||||
const _class = message.attachedToClass
|
||||
|
||||
return (await control.findAll(_class, { _id }))[0]
|
||||
}
|
||||
}
|
||||
|
||||
async function getMessageData (
|
||||
doc: Doc,
|
||||
message: ChatMessage,
|
||||
control: TriggerControl
|
||||
): Promise<Data<AIBotResponseEvent> | undefined> {
|
||||
if (!(await isAvailableDoc(doc, control))) {
|
||||
return
|
||||
}
|
||||
|
||||
return {
|
||||
objectId: message.attachedTo,
|
||||
objectClass: message.attachedToClass,
|
||||
objectSpace: doc.space,
|
||||
collection: message.collection,
|
||||
messageClass: message._class,
|
||||
message: message.message,
|
||||
user: message.createdBy ?? message.modifiedBy
|
||||
}
|
||||
}
|
||||
|
||||
async function getThreadMessageData (
|
||||
doc: Doc,
|
||||
message: ThreadMessage,
|
||||
control: TriggerControl
|
||||
): Promise<Data<AIBotResponseEvent> | undefined> {
|
||||
if (!(await isAvailableDoc(doc, control))) {
|
||||
return
|
||||
}
|
||||
|
||||
return {
|
||||
objectId: message.attachedTo,
|
||||
objectClass: message.attachedToClass,
|
||||
objectSpace: message.space,
|
||||
collection: message.collection,
|
||||
messageClass: message._class,
|
||||
message: message.message,
|
||||
user: message.createdBy ?? message.modifiedBy
|
||||
}
|
||||
}
|
||||
|
||||
// Note: temporally commented until open ai will be added
|
||||
// async function createAIBotEvent (message: ChatMessage, control: TriggerControl): Promise<Tx[]> {
|
||||
// const doc = await getMessageDoc(message, control)
|
||||
//
|
||||
// if (doc === undefined) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// let data: Data<AIBotResponseEvent> | undefined
|
||||
//
|
||||
// if (control.hierarchy.isDerived(message._class, chunter.class.ThreadMessage)) {
|
||||
// data = await getThreadMessageData(doc, message as ThreadMessage, control)
|
||||
// } else {
|
||||
// data = await getMessageData(doc, message, control)
|
||||
// }
|
||||
//
|
||||
// if (data === undefined) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// const eventTx = control.txFactory.createTxCreateDoc(aiBot.class.AIBotResponseEvent, message.space, data)
|
||||
//
|
||||
// await processWorkspace(control)
|
||||
//
|
||||
// return [eventTx]
|
||||
// return []
|
||||
// }
|
||||
|
||||
async function getThreadParent (control: TriggerControl, message: ChatMessage): Promise<Ref<ChatMessage> | undefined> {
|
||||
if (!control.hierarchy.isDerived(message.attachedToClass, chunter.class.ChatMessage)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const parentInfo = (
|
||||
await control.findAll(message.attachedToClass, {
|
||||
_id: message.attachedTo as Ref<ChatMessage>,
|
||||
[aiBot.mixin.TransferredMessage]: { $exists: true }
|
||||
})
|
||||
)[0]
|
||||
|
||||
if (parentInfo !== undefined) {
|
||||
return control.hierarchy.as(parentInfo, aiBot.mixin.TransferredMessage).messageId
|
||||
}
|
||||
|
||||
return message.attachedTo as Ref<ChatMessage>
|
||||
}
|
||||
|
||||
function getSupportWorkspaceId (): string | undefined {
|
||||
const supportWorkspaceId = getMetadata(serverAIBot.metadata.SupportWorkspaceId)
|
||||
|
||||
if (supportWorkspaceId === '') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return supportWorkspaceId
|
||||
}
|
||||
|
||||
async function onBotDirectMessageSend (control: TriggerControl, message: ChatMessage): Promise<Tx[]> {
|
||||
const supportWorkspaceId = getSupportWorkspaceId()
|
||||
|
||||
if (supportWorkspaceId === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
const direct = (await getMessageDoc(message, control)) as DirectMessage
|
||||
|
||||
if (direct === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
const isAvailable = await isDirectAvailable(direct, control)
|
||||
|
||||
if (!isAvailable) {
|
||||
return []
|
||||
}
|
||||
|
||||
const account = control.modelDb.findAllSync(contact.class.PersonAccount, {
|
||||
_id: (message.createdBy ?? message.modifiedBy) as Ref<PersonAccount>
|
||||
})[0]
|
||||
|
||||
if (account === undefined || account.role !== AccountRole.Owner) {
|
||||
return []
|
||||
}
|
||||
|
||||
let data: Data<AIBotResponseEvent> | undefined
|
||||
|
||||
if (control.hierarchy.isDerived(message._class, chunter.class.ThreadMessage)) {
|
||||
data = await getThreadMessageData(direct, message as ThreadMessage, control)
|
||||
} else {
|
||||
data = await getMessageData(direct, message, control)
|
||||
}
|
||||
|
||||
if (data === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
const eventTx = control.txFactory.createTxCreateDoc(aiBot.class.AIBotTransferEvent, message.space, {
|
||||
messageClass: data.messageClass,
|
||||
message: message.message,
|
||||
collection: data.collection,
|
||||
toWorkspace: supportWorkspaceId,
|
||||
toEmail: account.email,
|
||||
fromWorkspace: toWorkspaceString(control.workspace),
|
||||
messageId: message._id,
|
||||
parentMessageId: await getThreadParent(control, message)
|
||||
})
|
||||
|
||||
await processWorkspace(control)
|
||||
|
||||
return [eventTx]
|
||||
}
|
||||
|
||||
async function onSupportWorkspaceMessage (control: TriggerControl, message: ChatMessage): Promise<Tx[]> {
|
||||
const supportWorkspaceId = getSupportWorkspaceId()
|
||||
|
||||
if (supportWorkspaceId === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (toWorkspaceString(control.workspace) !== supportWorkspaceId) {
|
||||
return []
|
||||
}
|
||||
|
||||
const channel = await getMessageDoc(message, control)
|
||||
|
||||
if (channel === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (!control.hierarchy.hasMixin(channel, analytics.mixin.AnalyticsChannel)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const mixin = control.hierarchy.as(channel, analytics.mixin.AnalyticsChannel)
|
||||
const { workspace, email } = mixin
|
||||
|
||||
let data: Data<AIBotResponseEvent> | undefined
|
||||
|
||||
if (control.hierarchy.isDerived(message._class, chunter.class.ThreadMessage)) {
|
||||
data = await getThreadMessageData(channel, message as ThreadMessage, control)
|
||||
} else {
|
||||
data = await getMessageData(channel, message, control)
|
||||
}
|
||||
|
||||
if (data === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
await processWorkspace(control)
|
||||
|
||||
return [
|
||||
control.txFactory.createTxCreateDoc(aiBot.class.AIBotTransferEvent, message.space, {
|
||||
messageClass: data.messageClass,
|
||||
message: message.message,
|
||||
collection: data.collection,
|
||||
toEmail: email,
|
||||
toWorkspace: workspace,
|
||||
fromWorkspace: toWorkspaceString(control.workspace),
|
||||
messageId: message._id,
|
||||
parentMessageId: await getThreadParent(control, message)
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
export async function OnMessageSend (
|
||||
originTx: TxCollectionCUD<Doc, AttachedDoc>,
|
||||
control: TriggerControl
|
||||
): Promise<Tx[]> {
|
||||
const { hierarchy } = control
|
||||
const tx = TxProcessor.extractTx(originTx) as TxCreateDoc<ChatMessage>
|
||||
if (tx._class !== core.class.TxCreateDoc || !hierarchy.isDerived(tx.objectClass, chunter.class.ChatMessage)) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (tx.modifiedBy === aiBot.account.AIBot || tx.modifiedBy === core.account.System) {
|
||||
return []
|
||||
}
|
||||
|
||||
const isThread = hierarchy.isDerived(tx.objectClass, chunter.class.ThreadMessage)
|
||||
const message = TxProcessor.createDoc2Doc(tx)
|
||||
|
||||
const docClass = isThread ? (message as ThreadMessage).objectClass : message.attachedToClass
|
||||
|
||||
if (!hierarchy.isDerived(docClass, chunter.class.ChunterSpace)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const res: Tx[] = []
|
||||
|
||||
if (docClass === chunter.class.DirectMessage) {
|
||||
const txes = await onBotDirectMessageSend(control, message)
|
||||
res.push(...txes)
|
||||
}
|
||||
|
||||
if (docClass === chunter.class.Channel) {
|
||||
const txes = await onSupportWorkspaceMessage(control, message)
|
||||
res.push(...txes)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
export async function OnMention (tx: TxCreateDoc<MentionInboxNotification>, control: TriggerControl): Promise<Tx[]> {
|
||||
// Note: temporally commented until open ai will be added
|
||||
// if (tx.objectClass !== notification.class.MentionInboxNotification || tx._class !== core.class.TxCreateDoc) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// const mention = TxProcessor.createDoc2Doc(tx)
|
||||
//
|
||||
// if (mention.user !== aiBot.account.AIBot) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// if (!control.hierarchy.isDerived(mention.mentionedInClass, chunter.class.ChatMessage)) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// const message = (
|
||||
// await control.findAll<ChatMessage>(mention.mentionedInClass, { _id: mention.mentionedIn as Ref<ChatMessage> })
|
||||
// )[0]
|
||||
//
|
||||
// if (message === undefined) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// await createAIBotEvent(message, control)
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export async function OnMessageNotified (
|
||||
tx: TxCreateDoc<ActivityInboxNotification>,
|
||||
control: TriggerControl
|
||||
): Promise<Tx[]> {
|
||||
// Note: temporally commented until open ai will be added
|
||||
// if (tx.objectClass !== notification.class.ActivityInboxNotification || tx._class !== core.class.TxCreateDoc) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// const doc = TxProcessor.createDoc2Doc(tx)
|
||||
//
|
||||
// if (doc.user !== aiBot.account.AIBot) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// if (!control.hierarchy.isDerived(doc.attachedToClass, chunter.class.ChatMessage)) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// const personAccount = await control.modelDb.findOne(contact.class.PersonAccount, { email: aiBotAccountEmail })
|
||||
//
|
||||
// if (personAccount === undefined) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// const message = (
|
||||
// await control.findAll<ChatMessage>(doc.attachedToClass, { _id: doc.attachedTo as Ref<ChatMessage> })
|
||||
// )[0]
|
||||
//
|
||||
// if (message === undefined) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// if (isDocMentioned(personAccount.person, message.message)) {
|
||||
// return await createAIBotEvent(message, control)
|
||||
// }
|
||||
//
|
||||
// if (!control.hierarchy.isDerived(message._class, chunter.class.ThreadMessage)) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// const thread = message as ThreadMessage
|
||||
// TODO: do we really need to find parent???
|
||||
// const parent = (await control.findAll(thread.attachedToClass, { _id: thread.attachedTo }))[0]
|
||||
//
|
||||
// if (parent === undefined) {
|
||||
// return []
|
||||
// }
|
||||
//
|
||||
// if (parent.createdBy === aiBot.account.AIBot) {
|
||||
// return await createAIBotEvent(message, control)
|
||||
// }
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export async function OnUserStatus (originTx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const tx = TxProcessor.extractTx(originTx) as TxCUD<UserStatus>
|
||||
|
||||
if (
|
||||
tx.objectClass !== core.class.UserStatus ||
|
||||
![core.class.TxCreateDoc, core.class.TxUpdateDoc].includes(tx._class)
|
||||
) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (tx._class === core.class.TxUpdateDoc) {
|
||||
const updateTx = tx as TxUpdateDoc<UserStatus>
|
||||
const val = updateTx.operations.online
|
||||
if (val !== true) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const account = control.modelDb.findAllSync(contact.class.PersonAccount, { email: aiBotAccountEmail })[0]
|
||||
|
||||
if (account !== undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
await processWorkspace(control)
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
trigger: {
|
||||
OnMessageSend,
|
||||
OnMention,
|
||||
OnMessageNotified,
|
||||
OnUserStatus
|
||||
}
|
||||
})
|
||||
|
||||
export * from './adapter'
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
"rigPackageName": "@hcengineering/platform-rig"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
roots: ["./src"],
|
||||
coverageReporters: ["text-summary", "html"]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@hcengineering/server-ai-bot",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"svelte": "src/index.ts",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*",
|
||||
"types/**/*",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"author": "Hardcore Engineering Inc.",
|
||||
"scripts": {
|
||||
"build": "compile",
|
||||
"build:watch": "compile",
|
||||
"format": "format src",
|
||||
"test": "jest --passWithNoTests --silent",
|
||||
"_phase:build": "compile transpile src",
|
||||
"_phase:test": "jest --passWithNoTests --silent",
|
||||
"_phase:format": "format src",
|
||||
"_phase:validate": "compile validate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "^0.6.0",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/node": "~20.11.16",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-standard-with-typescript": "^40.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.1.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/ai-bot": "^0.6.0",
|
||||
"@hcengineering/platform": "^0.6.11",
|
||||
"@hcengineering/core": "^0.6.32",
|
||||
"@hcengineering/server-core": "^0.6.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Metadata, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { TriggerFunc } from '@hcengineering/server-core'
|
||||
|
||||
export * from './types'
|
||||
export const serverAiBotId = 'server-ai-bot' as Plugin
|
||||
|
||||
export default plugin(serverAiBotId, {
|
||||
metadata: {
|
||||
SupportWorkspaceId: '' as Metadata<string>
|
||||
},
|
||||
trigger: {
|
||||
OnMessageSend: '' as Resource<TriggerFunc>,
|
||||
OnMention: '' as Resource<TriggerFunc>,
|
||||
OnUserStatus: '' as Resource<TriggerFunc>,
|
||||
OnMessageNotified: '' as Resource<TriggerFunc>
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { ServiceAdapter } from '@hcengineering/server-core'
|
||||
import { WorkspaceId } from '@hcengineering/core'
|
||||
|
||||
export interface AIBotServiceAdapter extends ServiceAdapter {
|
||||
processWorkspace: (workspace: WorkspaceId) => Promise<void>
|
||||
}
|
||||
|
||||
export interface WorkspaceInfoRecord {
|
||||
workspace: string
|
||||
productId: string
|
||||
active: boolean
|
||||
avatarPath?: string
|
||||
avatarLastModified?: number
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"declarationDir": "./types",
|
||||
"tsBuildInfoFile": ".build/build.tsbuildinfo"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user