diff --git a/package-lock.json b/package-lock.json index 47771d28..27596410 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "@babel/core": "^7.22.15", "@babel/preset-env": "^7.22.15", "@babel/preset-typescript": "^7.22.15", - "@sentry/cli": "^2.20.7", + "@sentry/cli": "^2.39.1", "@types/express": "^4.17.14", "@types/jest": "^29.5.4", "@types/node": "^18.15.11", @@ -4346,9 +4346,9 @@ } }, "node_modules/@sentry/cli": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.31.0.tgz", - "integrity": "sha512-nCESoXAG3kRUO5n3QbDYAqX6RU3z1ORjnd7a3sqijYsCGHfOpcjGdS7JYLVg5if+tXMEF5529BPXFe5Kg/J9tw==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.39.1.tgz", + "integrity": "sha512-JIb3e9vh0+OmQ0KxmexMXg9oZsR/G7HMwxt5BUIKAXZ9m17Xll4ETXTRnRUBT3sf7EpNGAmlQk1xEmVN9pYZYQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -4365,19 +4365,19 @@ "node": ">= 10" }, "optionalDependencies": { - "@sentry/cli-darwin": "2.31.0", - "@sentry/cli-linux-arm": "2.31.0", - "@sentry/cli-linux-arm64": "2.31.0", - "@sentry/cli-linux-i686": "2.31.0", - "@sentry/cli-linux-x64": "2.31.0", - "@sentry/cli-win32-i686": "2.31.0", - "@sentry/cli-win32-x64": "2.31.0" + "@sentry/cli-darwin": "2.39.1", + "@sentry/cli-linux-arm": "2.39.1", + "@sentry/cli-linux-arm64": "2.39.1", + "@sentry/cli-linux-i686": "2.39.1", + "@sentry/cli-linux-x64": "2.39.1", + "@sentry/cli-win32-i686": "2.39.1", + "@sentry/cli-win32-x64": "2.39.1" } }, "node_modules/@sentry/cli-darwin": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.31.0.tgz", - "integrity": "sha512-VM5liyxMnm4K2g0WsrRPXRCMLhaT09C7gK5Fz/CxKYh9sbMZB7KA4hV/3klkyuyw1+ECF1J66cefhNkFZepUig==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.39.1.tgz", + "integrity": "sha512-kiNGNSAkg46LNGatfNH5tfsmI/kCAaPA62KQuFZloZiemTNzhy9/6NJP8HZ/GxGs8GDMxic6wNrV9CkVEgFLJQ==", "dev": true, "optional": true, "os": [ @@ -4388,9 +4388,9 @@ } }, "node_modules/@sentry/cli-linux-arm": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.31.0.tgz", - "integrity": "sha512-AZoCN3waXEfXGCd3YSrikcX/y63oQe0Tiyapkeoifq/0QhI+2MOOrAQb60gthsXwb0UDK/XeFi3PaxyUCphzxA==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.39.1.tgz", + "integrity": "sha512-DkENbxyRxUrfLnJLXTA4s5UL/GoctU5Cm4ER1eB7XN7p9WsamFJd/yf2KpltkjEyiTuplv0yAbdjl1KX3vKmEQ==", "cpu": [ "arm" ], @@ -4405,9 +4405,9 @@ } }, "node_modules/@sentry/cli-linux-arm64": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.31.0.tgz", - "integrity": "sha512-eENJTmXoFX3uNr8xRW7Bua2Sw3V1tylQfdtS85pNjZPdbm3U8wYQSWu2VoZkK2ASOoC+17YC8jTQxq62KWnSeQ==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.39.1.tgz", + "integrity": "sha512-5VbVJDatolDrWOgaffsEM7znjs0cR8bHt9Bq0mStM3tBolgAeSDHE89NgHggfZR+DJ2VWOy4vgCwkObrUD6NQw==", "cpu": [ "arm64" ], @@ -4422,9 +4422,9 @@ } }, "node_modules/@sentry/cli-linux-i686": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.31.0.tgz", - "integrity": "sha512-cQUFb3brhLaNSIoNzjU/YASnTM1I3TDJP9XXzH0eLK9sSopCcDcc6OrYEYvdjJXZKzFv5sbc9UNMsIDbh4+rYg==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.39.1.tgz", + "integrity": "sha512-pXWVoKXCRrY7N8vc9H7mETiV9ZCz+zSnX65JQCzZxgYrayQPJTc+NPRnZTdYdk5RlAupXaFicBI2GwOCRqVRkg==", "cpu": [ "x86", "ia32" @@ -4440,9 +4440,9 @@ } }, "node_modules/@sentry/cli-linux-x64": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.31.0.tgz", - "integrity": "sha512-z1zTNg91nZJRdcGHC/bCU1KwIaifV0MLJteip9KrFDprzhJk1HtMxFOS0+OZ5/UH21CjAFmg9Pj6IAGqm3BYjA==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.39.1.tgz", + "integrity": "sha512-IwayNZy+it7FWG4M9LayyUmG1a/8kT9+/IEm67sT5+7dkMIMcpmHDqL8rWcPojOXuTKaOBBjkVdNMBTXy0mXlA==", "cpu": [ "x64" ], @@ -4457,9 +4457,9 @@ } }, "node_modules/@sentry/cli-win32-i686": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.31.0.tgz", - "integrity": "sha512-+K7fdk57aUd4CmYrQfDGYPzVyxsTnVro6IPb5QSSLpP03dL7ko5208epu4m2SyN/MkFvscy9Di3n3DTvIfDU2w==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.39.1.tgz", + "integrity": "sha512-NglnNoqHSmE+Dz/wHeIVRnV2bLMx7tIn3IQ8vXGO5HWA2f8zYJGktbkLq1Lg23PaQmeZLPGlja3gBQfZYSG10Q==", "cpu": [ "x86", "ia32" @@ -4474,9 +4474,9 @@ } }, "node_modules/@sentry/cli-win32-x64": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.31.0.tgz", - "integrity": "sha512-w5cvpZ6VVlhlyleY8TYHmrP7g48vKHnoVt5xFccfxT+HqQI/AxodvzgVvBTM2kB/sh/kHwexp6bJGWCdkGftww==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.39.1.tgz", + "integrity": "sha512-xv0R2CMf/X1Fte3cMWie1NXuHmUyQPDBfCyIt6k6RPFPxAYUgcqgMPznYwVMwWEA1W43PaOkSn3d8ZylsDaETw==", "cpu": [ "x64" ], diff --git a/package.json b/package.json index 0c69df62..8e217207 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "description": "Harmony One Telegram Bot", "main": "dist/bot.js", "scripts": { - "build": "tsc", + "build": "tsc && npm run sentry:sourcemaps", "start": "node dist/bot.js", "dev": "env-cmd ts-node-dev src/bot.ts", "test": "jest", "typeorm": "typeorm-ts-node-commonjs -d src/database/datasource.ts", "lint": "eslint . --ext .ts", - "sentry:sourcemaps": "sentry-cli sourcemaps inject --org hiddenstate --project harmony-ai-bot ./dist && sentry-cli sourcemaps upload --org hiddenstate --project harmony-ai-bot ./dist", + "sentry:sourcemaps": "sentry-cli sourcemaps inject --org harmony-23 --project harmony1bot ./dist && sentry-cli sourcemaps upload --org harmony-23 --project harmony1bot ./dist", "prepare": "husky install" }, "repository": { @@ -44,7 +44,7 @@ "@babel/core": "^7.22.15", "@babel/preset-env": "^7.22.15", "@babel/preset-typescript": "^7.22.15", - "@sentry/cli": "^2.20.7", + "@sentry/cli": "^2.39.1", "@types/express": "^4.17.14", "@types/jest": "^29.5.4", "@types/node": "^18.15.11", @@ -125,4 +125,4 @@ "web3-utils": "^4.0.5", "websocket": "^1.0.34" } -} +} \ No newline at end of file diff --git a/src/bot.ts b/src/bot.ts index e45de5df..b150b6ee 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,3 +1,4 @@ +import { Sentry } from './monitoring/instrument' import express from 'express' import asyncHandler from 'express-async-handler' import { @@ -44,9 +45,7 @@ import { run } from '@grammyjs/runner' import { runBotHeartBit } from './monitoring/monitoring' import { type BotPaymentLog } from './database/stats.service' import { TelegramPayments } from './modules/telegram_payment' -import * as Sentry from '@sentry/node' import * as Events from 'events' -import { ProfilingIntegration } from '@sentry/profiling-node' import { ES } from './es' import { hydrateFiles } from '@grammyjs/files' import { VoiceTranslateBot } from './modules/voice-translate' @@ -96,18 +95,6 @@ bot.use( }) ) -Sentry.init({ - dsn: config.sentry.dsn, - release: config.commitHash, - integrations: [ - new ProfilingIntegration() - ], - tracesSampleRate: 1.0, // Performance Monitoring. Should use 0.1 in production - profilesSampleRate: 1.0 // Set sampling rate for profiling - this is relative to tracesSampleRate -}) - -Sentry.setTags({ botName: config.botName }) - ES.init() bot.use(async (ctx: BotContext, next: NextFunction): Promise => { @@ -126,28 +113,45 @@ bot.use(async (ctx: BotContext, next: NextFunction): Promise => { paymentFiatCredits: 0 } } - const transaction = Sentry.startTransaction({ name: 'bot-command' }) - const entities = ctx.entities() + const startTime = now() + const entities = ctx.entities() let command = '' - for (const ent of entities) { - if (ent.type === 'bot_command') { - command = ent.text.substring(1) - const userId = ctx.message?.from?.id - const username = ctx.message?.from?.username - if (userId) { - Sentry.setUser({ id: userId, username }) + + await Sentry.startSpan( + { + name: 'Bot Command Processing', + op: 'bot.command' + }, + async (span) => { + // Process bot commands and set Sentry context + for (const ent of entities) { + if (ent.type === 'bot_command') { + command = ent.text.substring(1) + const userId = ctx.message?.from?.id + const username = ctx.message?.from?.username + if (userId) { + Sentry.setUser({ id: userId, username }) + } + if (command) { + Sentry.setTag('command', command) + span?.setTag('command', command) + } + break + } } - if (command) { - Sentry.setTag('command', command) + + try { + await next() + } catch (error) { + if (span) { + span.setStatus('error') + Sentry.captureException(error) + } + throw error } - // there should be only one bot command - break } - } - - await next() - transaction.finish() + ) if (ctx.transient.analytics.module) { const userId = Number(ctx.message?.from?.id ?? '0') diff --git a/src/config.ts b/src/config.ts index d942f332..d9143790 100644 --- a/src/config.ts +++ b/src/config.ts @@ -163,7 +163,10 @@ export default { }, betteruptime: { botHeartBitId: process.env.BOT_HEARTBIT_ID ?? '' }, telegramPayments: { token: process.env.TELEGRAM_PAYMENTS_TOKEN ?? '' }, - sentry: { dsn: process.env.SENTRY_DSN }, + sentry: { + dsn: process.env.SENTRY_DSN, + env: process.env.SENTRY_ENVIRONMENT ?? 'local' + }, es: { url: process.env.ES_URL ?? '', username: process.env.ES_USERNAME ?? '', diff --git a/src/modules/1country/index.ts b/src/modules/1country/index.ts index 6f2394be..f6dddd39 100644 --- a/src/modules/1country/index.ts +++ b/src/modules/1country/index.ts @@ -1,6 +1,6 @@ import { GrammyError, InlineKeyboard } from 'grammy' import { AxiosError } from 'axios' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { type Logger, pino } from 'pino' import { chatService } from '../../database/services' diff --git a/src/modules/errorhandler.ts b/src/modules/errorhandler.ts index 7068f607..14ce1029 100644 --- a/src/modules/errorhandler.ts +++ b/src/modules/errorhandler.ts @@ -1,5 +1,5 @@ import { AxiosError } from 'axios' -import * as Sentry from '@sentry/node' // Import Sentry for error capturing +import { Sentry } from '../monitoring/instrument' import { RequestState, type OnCallBackQueryData, type OnMessageContext } from './types' import { sleep } from './sd-images/utils' import { type Logger } from 'pino' @@ -9,8 +9,6 @@ import { now } from '../utils/perf' import OpenAI from 'openai' import config from '../config' -// const MAX_TRIES = 3 // Define the maximum number of retries - class ErrorHandler { public maxTries = 3 diff --git a/src/modules/hmny/index.ts b/src/modules/hmny/index.ts index daad80f3..cc8e7279 100644 --- a/src/modules/hmny/index.ts +++ b/src/modules/hmny/index.ts @@ -1,5 +1,5 @@ import { GrammyError } from 'grammy' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { type Logger, pino } from 'pino' import { type OnMessageContext, diff --git a/src/modules/llms/claudeBot.ts b/src/modules/llms/claudeBot.ts index 9b0d0559..2b5973ac 100644 --- a/src/modules/llms/claudeBot.ts +++ b/src/modules/llms/claudeBot.ts @@ -4,12 +4,12 @@ import { type OnCallBackQueryData, type ChatConversation } from '../types' -import { SupportedCommands } from './utils/helpers' import { type LlmCompletion } from './api/llmApi' import { anthropicCompletion, anthropicStreamCompletion, toolsChatCompletion } from './api/athropic' import { LlmsBase } from './llmsBase' import { type ModelVersion } from './utils/llmModelsManager' import { type ModelParameters } from './utils/types' +import { SupportedCommands } from './utils/helpers' export class ClaudeBot extends LlmsBase { constructor (payments: BotPayments) { @@ -25,9 +25,9 @@ export class ClaudeBot extends LlmsBase { ): boolean { const hasCommand = ctx.hasCommand(this.supportedCommands) - if (ctx.hasCommand(SupportedCommands.new) && this.checkModel(ctx)) { - return true - } + // if (ctx.hasCommand(SupportedCommands.new) && this.checkModel(ctx)) { + // return true + // } const chatPrefix = this.hasPrefix(ctx.message?.text ?? '') if (chatPrefix !== '') { return true @@ -79,21 +79,18 @@ export class ClaudeBot extends LlmsBase { return } - if ( - (ctx.hasCommand(SupportedCommands.new) && this.checkModel(ctx)) - ) { - await this.onStop(ctx) - await this.onChat(ctx, this.modelsEnum.CLAUDE_3_OPUS, true, false) - return - } - const model = this.getModelFromContext(ctx) if (!model) { this.logger.warn(`### unsupported model for command ${ctx.message?.text}`) return } - this.updateSessionModel(ctx, model.version) + if ((ctx.message?.text ?? '').startsWith(SupportedCommands.c0) || ctx.hasCommand(SupportedCommands.c0)) { + await this.onStop(ctx) + await this.onStop(ctx, 'chatGpt') + } + + this.updateSessionModel(ctx, model.version) const usesTools = ctx.hasCommand([this.commandsEnum.CTOOL, this.commandsEnum.STOOL]) await this.onChat(ctx, model.version, usesTools ? false : this.getStreamOption(model.version), usesTools) } diff --git a/src/modules/llms/dalleBot.ts b/src/modules/llms/dalleBot.ts index 5b63054c..e588125d 100644 --- a/src/modules/llms/dalleBot.ts +++ b/src/modules/llms/dalleBot.ts @@ -17,7 +17,7 @@ import { sendMessage } from './utils/helpers' import { type LlmCompletion } from './api/llmApi' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { LlmsBase } from './llmsBase' import config from '../../config' import { now } from '../../utils/perf' diff --git a/src/modules/llms/llmsBase.ts b/src/modules/llms/llmsBase.ts index 43b4d6a8..940c2602 100644 --- a/src/modules/llms/llmsBase.ts +++ b/src/modules/llms/llmsBase.ts @@ -25,7 +25,7 @@ import { splitTelegramMessage } from './utils/helpers' import { type LlmCompletion, deleteCollection } from './api/llmApi' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { now } from '../../utils/perf' import { type ModelParameters, type ChatModel, type LLMModel } from './utils/types' import { ErrorHandler } from '../errorhandler' @@ -153,8 +153,9 @@ export abstract class LlmsBase implements PayableBot { this.subagents = subagents } - protected getSession (ctx: OnMessageContext | OnCallBackQueryData): LlmsSessionData & ImageGenSessionData { - return (ctx.session[this.sessionDataKey as keyof BotSessionData] as LlmsSessionData & ImageGenSessionData) + protected getSession (ctx: OnMessageContext | OnCallBackQueryData, dataKey?: string): LlmsSessionData & ImageGenSessionData { + dataKey = dataKey ?? this.sessionDataKey + return (ctx.session[dataKey as keyof BotSessionData] as LlmsSessionData & ImageGenSessionData) } protected updateSessionModel (ctx: OnMessageContext | OnCallBackQueryData, model: ModelVersion): void { @@ -462,8 +463,8 @@ export abstract class LlmsBase implements PayableBot { ctx.transient.analytics.actualResponseTime = now() } - async onStop (ctx: OnMessageContext | OnCallBackQueryData): Promise { - const session = this.getSession(ctx) + async onStop (ctx: OnMessageContext | OnCallBackQueryData, sessionKey?: string): Promise { + const session = this.getSession(ctx, sessionKey) for (const c of ctx.session.collections.activeCollections) { this.logger.info(`Deleting collection ${c.collectionName}`) await deleteCollection(c.collectionName) @@ -476,6 +477,7 @@ export abstract class LlmsBase implements PayableBot { session.chatConversation = [] session.usage = 0 session.price = 0 + ctx.session.currentPrompt = config.openAi.chatGpt.chatCompletionContext } async testCleanup (ctx: OnMessageContext | OnCallBackQueryData): Promise { diff --git a/src/modules/llms/lumaBot.ts b/src/modules/llms/lumaBot.ts index 7372a339..e5156c73 100644 --- a/src/modules/llms/lumaBot.ts +++ b/src/modules/llms/lumaBot.ts @@ -10,7 +10,7 @@ import { PRICE_ADJUSTMENT, sendMessage } from './utils/helpers' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { LlmsBase } from './llmsBase' import config from '../../config' import { now } from '../../utils/perf' diff --git a/src/modules/llms/openaiBot.ts b/src/modules/llms/openaiBot.ts index 31f05e74..f40740c2 100644 --- a/src/modules/llms/openaiBot.ts +++ b/src/modules/llms/openaiBot.ts @@ -12,7 +12,7 @@ import { SupportedCommands } from './utils/helpers' import { type LlmCompletion } from './api/llmApi' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { LlmsBase } from './llmsBase' import config from '../../config' import { now } from '../../utils/perf' @@ -49,9 +49,9 @@ export class OpenAIBot extends LlmsBase { ): boolean { const commands = ['last', ...this.supportedCommands] const hasCommand = ctx.hasCommand(commands) - if (ctx.hasCommand(SupportedCommands.new) && this.checkModel(ctx)) { - return true - } + // if (ctx.hasCommand(SupportedCommands.new) && this.checkModel(ctx)) { + // return true + // } if (isMentioned(ctx)) { return true } @@ -123,16 +123,16 @@ export class OpenAIBot extends LlmsBase { return } - if ( - (ctx.hasCommand(SupportedCommands.new) || - hasNewPrefix(ctx.message?.text ?? '') || - (ctx.message?.text?.startsWith('new ') && ctx.chat?.type === 'private') && this.checkModel(ctx)) - ) { - await this.onStop(ctx) - this.updateSessionModel(ctx, this.modelsEnum.GPT_4O) - await this.onChat(ctx, this.modelsEnum.GPT_4O, true, false) - return - } + // if ( + // (ctx.hasCommand(SupportedCommands.new) || + // hasNewPrefix(ctx.message?.text ?? '') || + // (ctx.message?.text?.startsWith('new ') && ctx.chat?.type === 'private') && this.checkModel(ctx)) + // ) { + // await this.onStop(ctx) + // this.updateSessionModel(ctx, this.modelsEnum.GPT_4O) + // await this.onChat(ctx, this.modelsEnum.GPT_4O, true, false) + // return + // } const model = this.getModelFromContext(ctx) if (model) { diff --git a/src/modules/llms/utils/helpers.ts b/src/modules/llms/utils/helpers.ts index 8e8da85f..9afa406e 100644 --- a/src/modules/llms/utils/helpers.ts +++ b/src/modules/llms/utils/helpers.ts @@ -17,10 +17,10 @@ import { type ParseDate } from './types' export const PRICE_ADJUSTMENT = config.openAi.chatGpt.priceAdjustment export enum SupportedCommands { + c0 = 'c0', sum = 'sum', ctx = 'ctx', pdf = 'pdf', - new = 'new', last = 'last', on = 'on', off = 'off', diff --git a/src/modules/llms/utils/llmsData.ts b/src/modules/llms/utils/llmsData.ts index 2ae58089..ee1d7b61 100644 --- a/src/modules/llms/utils/llmsData.ts +++ b/src/modules/llms/utils/llmsData.ts @@ -39,8 +39,8 @@ export const llmData: LLMData = { fullName: 'Claude Sonnet 3.5', botName: 'ClaudeBot', version: 'claude-3-5-sonnet-20241022', - commands: ['sonnet', 'claude', 's', 'stool', 'c', 'ctool'], - prefix: ['s. ', 'c. '], + commands: ['sonnet', 'claude', 's', 'stool', 'c', 'ctool', 'c0'], + prefix: ['s. ', 'c. ', 'c0. '], apiSpec: 'https://www.anthropic.com/news/claude-3-5-sonnet', inputPrice: 0.003, outputPrice: 0.015, @@ -63,18 +63,33 @@ export const llmData: LLMData = { chargeType: 'TOKEN', stream: true }, - 'claude-3-haiku': { + // 'claude-3-haiku': { + // provider: 'claude', + // name: 'claude-3-haiku', + // fullName: 'Claude Haiku', + // botName: 'ClaudeBot', + // version: 'claude-3-haiku-20240307', + // commands: ['haiku', 'h'], + // prefix: ['h. '], + // apiSpec: 'https://www.anthropic.com/news/claude-3-family', + // inputPrice: 0.00025, + // outputPrice: 0.00125, + // maxContextTokens: 4096, + // chargeType: 'TOKEN', + // stream: true + // }, + 'claude-3-5-haiku': { provider: 'claude', - name: 'claude-3-haiku', + name: 'claude-3-5-haiku', fullName: 'Claude Haiku', botName: 'ClaudeBot', - version: 'claude-3-haiku-20240307', + version: 'claude-3-5-haiku-20241022', commands: ['haiku', 'h'], prefix: ['h. '], apiSpec: 'https://www.anthropic.com/news/claude-3-family', - inputPrice: 0.00025, - outputPrice: 0.00125, - maxContextTokens: 4096, + inputPrice: 0.001, + outputPrice: 0.005, + maxContextTokens: 8192, chargeType: 'TOKEN', stream: true }, diff --git a/src/modules/payment/index.ts b/src/modules/payment/index.ts index c0a46567..4c791411 100644 --- a/src/modules/payment/index.ts +++ b/src/modules/payment/index.ts @@ -10,7 +10,7 @@ import { LRUCache } from 'lru-cache' import { freeCreditsFeeCounter } from '../../metrics/prometheus' import { type BotPaymentLog } from '../../database/stats.service' import { sendMessage } from '../llms/utils/helpers' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { InlineKeyboard } from 'grammy' import { Callbacks } from '../types' import { type InvoiceParams } from '../../database/invoice.service' @@ -237,7 +237,7 @@ export class BotPayments { try { const web3 = new Web3(this.rpcURL) web3.eth.accounts.wallet.add(accountFrom) - + this.logger.error(`Transfering funds from ${accountFrom.address} to ${addressTo}`) const gasPrice = await web3.eth.getGasPrice() let nonce @@ -435,7 +435,6 @@ export class BotPayments { const totalPayAmount = await this.getPriceInONE(amountUSD) const { totalCreditsAmount } = await chatService.getUserCredits(accountId) const totalBalanceDelta = totalCreditsAmount.minus(totalPayAmount) - this.logger.info( `[${from.id} @${ from.username diff --git a/src/modules/qrcode/QRCodeBot.ts b/src/modules/qrcode/QRCodeBot.ts index 2c7cdcb3..da5ce10c 100644 --- a/src/modules/qrcode/QRCodeBot.ts +++ b/src/modules/qrcode/QRCodeBot.ts @@ -16,7 +16,7 @@ import { ComfyClient } from './comfy/ComfyClient' import crypto from 'crypto' import buildQRWorkflow from './comfy/buildQRWorkflow' import pino, { type Logger } from 'pino' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { now } from '../../utils/perf' enum SupportedCommands { diff --git a/src/modules/schedule/bridgeAPI.ts b/src/modules/schedule/bridgeAPI.ts index 96810f44..6e7da30f 100644 --- a/src/modules/schedule/bridgeAPI.ts +++ b/src/modules/schedule/bridgeAPI.ts @@ -1,5 +1,6 @@ import axios from 'axios' import moment from 'moment' +// import { Sentry } from '../../monitoring/instrument' import { abbreviateNumber, getPercentDiff } from './utils' import { BigNumber } from 'bignumber.js' import pino from 'pino' @@ -182,6 +183,7 @@ export const getAvgStakes = async (): Promise => { }, BigNumber(0)).div(values.length).div(10 ** 18).toNumber() } catch (e) { logger.error(e) + // Sentry.captureException(e) return 0 } } diff --git a/src/modules/schedule/harmonyApi.ts b/src/modules/schedule/harmonyApi.ts index 27b3eaa7..50c7d82b 100644 --- a/src/modules/schedule/harmonyApi.ts +++ b/src/modules/schedule/harmonyApi.ts @@ -4,6 +4,8 @@ import { abbreviateNumber, getPercentDiff } from './utils' const rpcUrl = 'https://rpc.s0.t.hmny.io' +// 'https://api.harmony.one' + const rpcRequest = async (method: string, params: any[] = []): Promise => { const { data } = await axios.post(rpcUrl, { jsonrpc: '2.0', @@ -37,17 +39,13 @@ export const getAddressBalance = async (address: string): Promise => { export const getBotFee = async (address: string, daysCount: number): Promise => { const history = await getAddressHistory(address) - - const startTimestamp = moment().subtract(daysCount, 'days').unix() - + const startTimestamp = moment().subtract(7, 'days').unix() const total = history.reduce((acc, item) => { if (item.timestamp < startTimestamp) { return acc } - return acc + item.value }, 0) - return total / Math.pow(10, 18) } diff --git a/src/modules/sd-images/index.ts b/src/modules/sd-images/index.ts index d3765bfb..f769a5f0 100644 --- a/src/modules/sd-images/index.ts +++ b/src/modules/sd-images/index.ts @@ -4,7 +4,7 @@ import { SDImagesBotBase } from './SDImagesBotBase' import { COMMAND, type IOperation, parseCtx, promptHasBadWords } from './helpers' import { getModelByParam, MODELS_CONFIGS } from './api' import { sendMessage } from '../llms/utils/helpers' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { OPERATION_STATUS, completeOperation } from './balancer' import { now } from '../../utils/perf' diff --git a/src/modules/voice-memo/index.ts b/src/modules/voice-memo/index.ts index b5765d19..940b6654 100644 --- a/src/modules/voice-memo/index.ts +++ b/src/modules/voice-memo/index.ts @@ -12,7 +12,7 @@ import { Kagi } from './kagi' import MessageMediaDocument = Api.MessageMediaDocument import { InputFile } from 'grammy' import { bot } from '../../bot' -import * as Sentry from '@sentry/node' +import { Sentry } from '../../monitoring/instrument' import { now } from '../../utils/perf' import { isAdmin } from '../llms/utils/context' import { VOICE_MEMO_FORWARDING } from '../../constants' diff --git a/src/monitoring/environments.ts b/src/monitoring/environments.ts new file mode 100644 index 00000000..2b788fb6 --- /dev/null +++ b/src/monitoring/environments.ts @@ -0,0 +1,19 @@ +import config from '../config' + +export type Environment = 'local' | 'test' | 'production' + +export function getEnvironment (): Environment { + // Use SENTRY_ENVIRONMENT if available + const sentryEnv = config.sentry.env.toLowerCase() + if (sentryEnv) { + // Validate that it's one of our expected environments + if (['local', 'test', 'production'].includes(sentryEnv)) { + return sentryEnv as Environment + } + // If invalid value, log warning and default to production + console.warn(`Invalid SENTRY_ENVIRONMENT value: ${sentryEnv}. Defaulting to production`) + return 'production' + } + // If no SENTRY_ENVIRONMENT set, assume local development + return 'local' +} diff --git a/src/monitoring/instrument.ts b/src/monitoring/instrument.ts new file mode 100644 index 00000000..c3ed90df --- /dev/null +++ b/src/monitoring/instrument.ts @@ -0,0 +1,37 @@ +import * as Sentry from '@sentry/node' +import config from '../config' +import { ProfilingIntegration } from '@sentry/profiling-node' +import { getEnvironment } from './environments' + +const env = getEnvironment() + +// Configure sample rates based on environment +const sampleRates = { + local: { + traces: 1.0, // Higher sampling in local for testing + profiles: 1.0 + }, + test: { + traces: 0.5, // Medium sampling in test + profiles: 1.0 + }, + production: { + traces: 0.1, // Lower sampling in production for performance + profiles: 1.0 + } +} + +Sentry.init({ + dsn: config.sentry.dsn, + release: config.commitHash, + environment: env, + integrations: [ + new ProfilingIntegration() + ], + tracesSampleRate: sampleRates[env].traces, + profilesSampleRate: sampleRates[env].profiles +}) + +Sentry.setTags({ botName: config.botName }) + +export { Sentry }