Skip to content
Open
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
8 changes: 7 additions & 1 deletion common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions foundations/server/packages/middleware/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"eslint-plugin-svelte": "^2.35.1"
},
"dependencies": {
"@hcengineering/ai-bot": "workspace:^0.7.0",
"@hcengineering/core": "workspace:^0.7.24",
"@hcengineering/contact": "workspace:^0.7.0",
"@hcengineering/platform": "workspace:^0.7.19",
Expand Down
5 changes: 2 additions & 3 deletions foundations/server/packages/middleware/src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.
//

import { getAiBotAccountEmail } from '@hcengineering/ai-bot'
import core, {
type MeasureContext,
type Tx,
Expand All @@ -28,8 +29,6 @@ import {
type PipelineContext
} from '@hcengineering/server-core'

export const aiBotAccountEmail = 'huly.ai.bot@hc.engineering'

/**
* @public
*/
Expand All @@ -49,7 +48,7 @@ export class IdentityMiddleware extends BaseMiddleware implements Middleware {
tx (ctx: MeasureContext<SessionData>, txes: Tx[]): Promise<TxMiddlewareResult> {
const account = ctx.contextData.account

if (account.uuid === systemAccountUuid || account.fullSocialIds.some((it) => it.value === aiBotAccountEmail)) {
if (account.uuid === systemAccountUuid || account.fullSocialIds.some((it) => it.value === getAiBotAccountEmail())) {
// TODO: We need to enhance allowed list in case of user service, on behalf of user activities.

// We pass for system accounts and services.
Expand Down
4 changes: 2 additions & 2 deletions foundations/server/packages/middleware/src/pluginConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
type TxMiddlewareResult,
type PipelineContext
} from '@hcengineering/server-core'
import { aiBotAccountEmail } from './identity'
import { getAiBotAccountEmail } from '@hcengineering/ai-bot'

/**
* @public
Expand All @@ -50,7 +50,7 @@ export class PluginConfigurationMiddleware extends BaseMiddleware implements Mid

tx (ctx: MeasureContext<SessionData>, txes: Tx[]): Promise<TxMiddlewareResult> {
const account = ctx.contextData.account
if (account.uuid === systemAccountUuid || account.fullSocialIds.some((it) => it.value === aiBotAccountEmail)) {
if (account.uuid === systemAccountUuid || account.fullSocialIds.some((it) => it.value === getAiBotAccountEmail())) {
// We pass for system accounts and services.
return this.provideTx(ctx, txes)
}
Expand Down
18 changes: 18 additions & 0 deletions plugins/ai-bot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ export * from './rest'
export const aiBotId = 'ai-bot' as Plugin

export const aiBotAccountEmail = 'huly.ai.bot@hc.engineering'

let _aiBotAccountEmail: string = aiBotAccountEmail

export function getAiBotAccountEmail (): string {
return _aiBotAccountEmail
}

export function setAiBotAccountEmail (email: string): void {
_aiBotAccountEmail = email
}

export function getAiBotEmailSocialKey (): string {
return buildSocialIdString({
type: SocialIdType.EMAIL,
value: _aiBotAccountEmail
})
}

export const aiBotEmailSocialKey = buildSocialIdString({
type: SocialIdType.EMAIL,
value: aiBotAccountEmail
Expand Down
1 change: 1 addition & 0 deletions pods/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@hcengineering/postgres": "workspace:^0.7.22",
"@hcengineering/rpc": "workspace:^0.7.17",
"@hcengineering/server": "workspace:^0.7.17",
"@hcengineering/ai-bot": "workspace:^0.7.0",
"@hcengineering/server-ai-bot": "workspace:^0.7.0",
"@hcengineering/server-calendar": "workspace:^0.7.0",
"@hcengineering/server-core": "workspace:^0.7.18",
Expand Down
4 changes: 4 additions & 0 deletions pods/server/src/__start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//

// Add this to the VERY top of the first file loaded in your app
import { setAiBotAccountEmail } from '@hcengineering/ai-bot'
import { Analytics } from '@hcengineering/analytics'
import { configureAnalytics, createOpenTelemetryMetricsContext, SplitLogger } from '@hcengineering/analytics-service'
import contactPlugin from '@hcengineering/contact'
Expand Down Expand Up @@ -85,6 +86,9 @@ setMetadata(serverNotification.metadata.MailUrl, config.mailUrl ?? '')
setMetadata(serverNotification.metadata.MailAuthToken, config.mailAuthToken)
setMetadata(serverNotification.metadata.WebPushUrl, config.webPushUrl)
setMetadata(serverAiBot.metadata.EndpointURL, process.env.AI_BOT_URL)
if (process.env.AI_BOT_EMAIL !== undefined) {
setAiBotAccountEmail(process.env.AI_BOT_EMAIL)
}
Comment thread
ArtyomSavchenko marked this conversation as resolved.
setMetadata(serverCalendar.metadata.EndpointURL, process.env.CALENDAR_URL)
setMetadata(serverCard.metadata.CommunicationEnabled, process.env.COMMUNICATION_API_ENABLED === 'true')

Expand Down
8 changes: 4 additions & 4 deletions server-plugins/ai-bot-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import core, {
} from '@hcengineering/core'
import { TriggerControl } from '@hcengineering/server-core'
import { getAccountBySocialKey } from '@hcengineering/server-contact'
import { aiBotEmailSocialKey, AIEventRequest } from '@hcengineering/ai-bot'
import { getAiBotEmailSocialKey, AIEventRequest } from '@hcengineering/ai-bot'
import chunter, { ChatMessage, DirectMessage, ThreadMessage } from '@hcengineering/chunter'
import contact from '@hcengineering/contact'

Expand Down Expand Up @@ -64,7 +64,7 @@ async function OnUserStatus (txes: TxCUD<UserStatus>[], control: TriggerControl)
}

const socialIdentity = (
await control.findAll(control.ctx, contact.class.SocialIdentity, { key: aiBotEmailSocialKey }, { limit: 1 })
await control.findAll(control.ctx, contact.class.SocialIdentity, { key: getAiBotEmailSocialKey() }, { limit: 1 })
)[0]

if (socialIdentity === undefined) {
Expand All @@ -82,7 +82,7 @@ async function OnMessageSend (originTxs: TxCreateDoc<ChatMessage>[], control: Tr
}
const { account } = control.ctx.contextData
const primaryIdentity = (
await control.findAll(control.ctx, contact.class.SocialIdentity, { key: aiBotEmailSocialKey }, { limit: 1 })
await control.findAll(control.ctx, contact.class.SocialIdentity, { key: getAiBotEmailSocialKey() }, { limit: 1 })
)[0]

if (primaryIdentity === undefined) return []
Expand Down Expand Up @@ -165,7 +165,7 @@ async function getMessageDoc (message: ChatMessage, control: TriggerControl): Pr

async function isDirectAvailable (direct: DirectMessage, control: TriggerControl): Promise<boolean> {
const { members } = direct
const account = await getAccountBySocialKey(control, aiBotEmailSocialKey)
const account = await getAccountBySocialKey(control, getAiBotEmailSocialKey())

if (account == null) {
return false
Expand Down
3 changes: 3 additions & 0 deletions services/ai-bot/pod-ai-bot/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.
//

import { aiBotAccountEmail } from '@hcengineering/ai-bot'
import OpenAI from 'openai'

interface Config {
Expand All @@ -26,6 +27,7 @@ interface Config {
AvatarPath: string
AvatarName: string
AvatarContentType: string
Email: string
Password: string
OpenAIKey: string
OpenAIModel: OpenAI.ChatModel
Expand Down Expand Up @@ -58,6 +60,7 @@ const config: Config = (() => {
AvatarPath: process.env.AVATAR_PATH ?? './assets/avatar.png',
AvatarName: process.env.AVATAR_NAME ?? 'huly_ai_bot_avatar',
AvatarContentType: process.env.AVATAR_CONTENT_TYPE ?? 'image/png',
Email: process.env.AI_BOT_EMAIL ?? aiBotAccountEmail,
Password: process.env.PASSWORD ?? 'password',
OpenAIKey: process.env.OPENAI_API_KEY ?? '',
OpenAIModel: (process.env.OPENAI_MODEL ?? 'gpt-4o-mini') as OpenAI.ChatModel,
Expand Down
2 changes: 2 additions & 0 deletions services/ai-bot/pod-ai-bot/src/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { setAiBotAccountEmail } from '@hcengineering/ai-bot'
import { setMetadata } from '@hcengineering/platform'
import serverClient, { withRetry } from '@hcengineering/server-client'
import { initStatisticsContext } from '@hcengineering/server-core'
Expand All @@ -30,6 +31,7 @@ import { getAccountUuid } from './utils/account'
import { updateDeepgramBilling } from './billing'

export const start = async (): Promise<void> => {
setAiBotAccountEmail(config.Email)
setMetadata(serverToken.metadata.Secret, config.ServerSecret)
setMetadata(serverToken.metadata.Service, 'ai-bot-service')
setMetadata(serverClient.metadata.UserAgent, config.ServiceID)
Expand Down
12 changes: 6 additions & 6 deletions services/ai-bot/pod-ai-bot/src/utils/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from '@hcengineering/core'
import { generateToken } from '@hcengineering/server-token'
import { getAccountClient, withRetry } from '@hcengineering/server-client'
import { aiBotAccountEmail, aiBotEmailSocialKey } from '@hcengineering/ai-bot'
import { getAiBotAccountEmail, getAiBotEmailSocialKey } from '@hcengineering/ai-bot'
import { MeasureContext, PersonUuid, systemAccountUuid } from '@hcengineering/core'

import config from '../config'
Expand Down Expand Up @@ -105,7 +105,7 @@ export async function tryAssignToWorkspace (workspace: WorkspaceUuid, ctx: Measu

await withRetry(
async () => {
await accountClient.assignWorkspace(aiBotAccountEmail, workspace, AccountRole.User)
await accountClient.assignWorkspace(getAiBotAccountEmail(), workspace, AccountRole.User)
},
(_, attempt) => attempt >= ASSIGN_WORKSPACE_ATTEMPTS,
ASSIGN_WORKSPACE_DELAY
Expand All @@ -121,7 +121,7 @@ export async function tryAssignToWorkspace (workspace: WorkspaceUuid, ctx: Measu
}

async function confirmAccount (uuid: PersonUuid): Promise<void> {
const token = generateToken(uuid, undefined, { service: 'aibot', confirmEmail: aiBotAccountEmail })
const token = generateToken(uuid, undefined, { service: 'aibot', confirmEmail: getAiBotAccountEmail() })
const client = getAccountClient(token)
try {
await client.confirm()
Expand All @@ -135,17 +135,17 @@ let account: AccountUuid | undefined
export async function getAccountUuid (ctx?: MeasureContext): Promise<AccountUuid | undefined> {
if (account !== undefined) return account

const token = generateToken(systemAccountUuid, undefined, { service: 'aibot', confirmEmail: aiBotAccountEmail })
const token = generateToken(systemAccountUuid, undefined, { service: 'aibot', confirmEmail: getAiBotAccountEmail() })
const accountClient = getAccountClient(token)
const personUuid = await accountClient.findPersonBySocialKey(aiBotEmailSocialKey)
const personUuid = await accountClient.findPersonBySocialKey(getAiBotEmailSocialKey())

if (personUuid !== undefined) {
await confirmAccount(personUuid)
account = personUuid as AccountUuid
return account
}

const result = await accountClient.signUp(aiBotAccountEmail, config.Password, config.FirstName, config.LastName)
const result = await accountClient.signUp(getAiBotAccountEmail(), config.Password, config.FirstName, config.LastName)

if (result !== undefined) {
await confirmAccount(result.account)
Expand Down
4 changes: 2 additions & 2 deletions services/ai-bot/pod-ai-bot/src/utils/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import core, { Client, Ref, TxOperations, AccountUuid } from '@hcengineering/cor
import { createClient } from '@hcengineering/server-client'
import contact, { Employee, Person } from '@hcengineering/contact'
import chunter, { DirectMessage } from '@hcengineering/chunter'
import { aiBotEmailSocialKey } from '@hcengineering/ai-bot'
import { getAiBotEmailSocialKey } from '@hcengineering/ai-bot'
import notification from '@hcengineering/notification'

export async function connectPlatform (token: string, endpoint: string): Promise<Client> {
Expand All @@ -40,7 +40,7 @@ export async function getDirect (
account: AccountUuid,
aiPerson?: Ref<Person>
): Promise<Ref<DirectMessage> | undefined> {
const aibotAccount = await getAccountBySocialKey(client, aiBotEmailSocialKey)
const aibotAccount = await getAccountBySocialKey(client, getAiBotEmailSocialKey())
if (aibotAccount == null) return undefined

const existingDm = (await client.findAll(chunter.class.DirectMessage, { members: aibotAccount })).find((dm) =>
Expand Down