Skip to content

Commit

Permalink
update models context + refactor models logic to allow dynamic comman…
Browse files Browse the repository at this point in the history
…ds and prefixes definitions + fix o1 model issues with urls on promtp
  • Loading branch information
fegloff committed Oct 2, 2024
1 parent 213caa3 commit 91be87d
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 193 deletions.
13 changes: 7 additions & 6 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,15 @@ export default {
}
},
chatGpt: {
chatCompletionContext:
'You are an AI Bot powered by Harmony. Your strengths are ai api aggregation for chat, image, and voice interactions. Leveraging a suite of sophisticated subagents, you have the capability to perform tasks such as internet browsing and accessing various services. Your responses should be adaptable to the conversation while maintaining brevity, ideally not exceeding 100 words.',
chatCompletionContext: 'Reply ideally not exceeding 100 words',
// 'You are an AI Bot powered by Harmony. Your strengths are ai api aggregation for chat, image, and voice interactions. Leveraging a suite of sophisticated subagents, you have the capability to perform tasks such as internet browsing and accessing various services. Your responses should be adaptable to the conversation while maintaining brevity, ideally not exceeding 100 words.',
// 'You are an AI Bot powered dby Harmony. Your strengths are ai api aggregation for chat, image, and voice interactions, and more. You have subagents that helps you with task like browsing the internet, and other services. Respond flexibly, but try to stay within 100 words in all of your responses.',
webCrawlerContext: 'You will receive a web crawling text. Please get keys concepts, but try to stay within 4000 words in your response.',
visionCompletionContext: `You are a concise AI Bot powered by Harmony, capable of providing complete responses within a 100-word limit.
For each additional image, extend your response by 30 words. Your responses should be informative and comprehensive,
wrapping up all details without leaving them hanging. Use your flexibility to adapt to any topic, and deliver engaging and fulfilling
conversations in a succinct manner.`,
visionCompletionContext: 'Response within a 100-word limit',
// `You are a concise AI Bot powered by Harmony, capable of providing complete responses within a 100-word limit.
// For each additional image, extend your response by 30 words. Your responses should be informative and comprehensive,
// wrapping up all details without leaving them hanging. Use your flexibility to adapt to any topic, and deliver engaging and fulfilling
// conversations in a succinct manner.`,
maxTokens: parseInt(process.env.OPENAI_MAX_TOKENS ?? '800'), // telegram messages has a char limit
wordLimit: 30,
wordCountBetween: 10,
Expand Down
2 changes: 1 addition & 1 deletion src/modules/llms/api/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const streamChatCompletion = async (
model,
messages: messages as ChatCompletionMessageParam[], // OpenAI.Chat.Completions.CreateChatCompletionRequestMessage[],
stream: true,
max_tokens: limitTokens ? config.openAi.chatGpt.maxTokens : undefined,
max_completion_tokens: limitTokens ? config.openAi.chatGpt.maxTokens : undefined, // max_tokens:
temperature: config.openAi.dalle.completions.temperature || 0.8
})
let wordCount = 0
Expand Down
61 changes: 12 additions & 49 deletions src/modules/llms/claudeBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ import {
type OnCallBackQueryData,
type ChatConversation
} from '../types'
import { hasCommandPrefix, SupportedCommands } from './utils/helpers'
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'

export class ClaudeBot extends LlmsBase {
private readonly opusPrefix: string[]
private readonly claudeModels: ModelVersion[]

constructor (payments: BotPayments) {
super(payments, 'ClaudeBot', 'llms')
this.opusPrefix = this.modelManager.getPrefixByModel(this.modelsEnum.CLAUDE_3_OPUS) ?? []
}

public getEstimatedPrice (ctx: any): number {
Expand All @@ -25,18 +24,7 @@ export class ClaudeBot extends LlmsBase {
public isSupportedEvent (
ctx: OnMessageContext | OnCallBackQueryData
): boolean {
const hasCommand = ctx.hasCommand([
this.commandsEnum.CLAUDE,
this.commandsEnum.OPUS,
this.commandsEnum.O,
this.commandsEnum.C,
this.commandsEnum.CTOOL,
this.commandsEnum.STOOL,
this.commandsEnum.CLAUDES,
this.commandsEnum.SONNET,
this.commandsEnum.S,
this.commandsEnum.HAIKU,
this.commandsEnum.H])
const hasCommand = ctx.hasCommand(this.supportedCommands)

if (ctx.hasCommand(SupportedCommands.new) && this.checkModel(ctx)) {
return true
Expand All @@ -48,12 +36,6 @@ export class ClaudeBot extends LlmsBase {
return hasCommand
}

hasPrefix (prompt: string): string {
return (
hasCommandPrefix(prompt, this.opusPrefix)
)
}

async chatStreamCompletion (
conversation: ChatConversation[],
model: ModelVersion,
Expand Down Expand Up @@ -87,42 +69,23 @@ export class ClaudeBot extends LlmsBase {
this.logger.warn(`### unsupported command ${ctx.message?.text}`)
return
}
if (ctx.hasCommand([this.commandsEnum.CTOOL])) {
this.updateSessionModel(ctx, this.modelsEnum.CLAUDE_3_OPUS)
await this.onChat(ctx, this.modelsEnum.CLAUDE_3_OPUS, false, true)
return
}
if (ctx.hasCommand([this.commandsEnum.STOOL])) {
this.updateSessionModel(ctx, this.modelsEnum.CLAUDE_35_SONNET)
await this.onChat(ctx, this.modelsEnum.CLAUDE_35_SONNET, false, true)
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
}
if (ctx.hasCommand([
this.commandsEnum.CLAUDE,
this.commandsEnum.OPUS,
this.commandsEnum.O,
this.commandsEnum.C]) ||
(hasCommandPrefix(ctx.message?.text ?? '', this.opusPrefix) !== '')
) {
this.updateSessionModel(ctx, this.modelsEnum.CLAUDE_3_OPUS)
await this.onChat(ctx, this.modelsEnum.CLAUDE_3_OPUS, true, false)
return
}
if (ctx.hasCommand([this.commandsEnum.CLAUDES, this.commandsEnum.SONNET, this.commandsEnum.S])) {
this.updateSessionModel(ctx, this.modelsEnum.CLAUDE_35_SONNET)
await this.onChat(ctx, this.modelsEnum.CLAUDE_35_SONNET, true, false)

const model = this.getModelFromContext(ctx)
if (!model) {
this.logger.warn(`### unsupported model for command ${ctx.message?.text}`)
return
}
if (ctx.hasCommand([this.commandsEnum.HAIKU, this.commandsEnum.H])) {
this.updateSessionModel(ctx, this.modelsEnum.CLAUDE_3_HAIKU)
await this.onChat(ctx, this.modelsEnum.CLAUDE_3_HAIKU, false, false)
}
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)
}
}
59 changes: 53 additions & 6 deletions src/modules/llms/llmsBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
import { type LlmCompletion, deleteCollection } from './api/llmApi'
import * as Sentry from '@sentry/node'
import { now } from '../../utils/perf'
import { type LLMModel } from './utils/types'
import { type ChatModel, type LLMModel } from './utils/types'
import { ErrorHandler } from '../errorhandler'
import { SubagentBase } from '../subagents/subagentBase'
import {
Expand All @@ -48,7 +48,11 @@ export abstract class LlmsBase implements PayableBot {
protected commandsEnum = LlmCommandsEnum
protected subagents: SubagentBase[]
protected botSuspended: boolean
protected supportedModels: LLMModel[] // LlmsModelsEnum[]
protected supportedModels: LLMModel[]
protected supportedCommands: string[]
protected supportedPrefixes: string[]
protected botName: string

errorHandler: ErrorHandler

constructor (payments: BotPayments,
Expand All @@ -57,6 +61,7 @@ export abstract class LlmsBase implements PayableBot {
subagents?: SubagentBase[]
) {
this.module = module
this.botName = module
this.logger = pino({
name: this.module,
transport: {
Expand All @@ -70,9 +75,29 @@ export abstract class LlmsBase implements PayableBot {
this.payments = payments
this.subagents = subagents ?? []
this.errorHandler = new ErrorHandler()
this.supportedModels = this.initSupportedModels()
this.supportedCommands = this.initSupportedCommands()
this.supportedPrefixes = this.initSupportedPrefixes()
}

private initSupportedModels (): LLMModel[] {
return this.modelManager.getModelsByBot(this.botName)
}

private initSupportedCommands (): string[] {
return this.supportedModels
.filter(model => model.botName === this.botName)
.flatMap(model => model.commands)
}

private initSupportedPrefixes (): string[] {
return this.supportedModels
.filter(model => model.botName === this.botName)
.flatMap(model => this.modelManager.getPrefixByModel(model.version) ?? [])
}

public abstract onEvent (ctx: OnMessageContext | OnCallBackQueryData, refundCallback: (reason?: string) => void): Promise<void>

public abstract isSupportedEvent (
ctx: OnMessageContext | OnCallBackQueryData
): boolean
Expand All @@ -92,7 +117,29 @@ export abstract class LlmsBase implements PayableBot {
usesTools: boolean
): Promise<LlmCompletion>

protected abstract hasPrefix (prompt: string): string
// protected abstract hasPrefix (prompt: string): string
protected hasPrefix (prompt: string): string {
return this.supportedPrefixes.find(prefix => prompt.toLocaleLowerCase().startsWith(prefix)) ?? ''
}

protected getStreamOption (model: ModelVersion): boolean {
const foundModel = this.supportedModels.find(m => m.version === model) as ChatModel | undefined
return foundModel?.stream ?? false
}

protected getModelFromContext (ctx: OnMessageContext | OnCallBackQueryData): LLMModel | undefined {
for (const model of this.supportedModels) {
if (model.botName !== this.botName) continue
if (ctx.hasCommand(model.commands)) {
return model
}
const prefix = this.modelManager.getPrefixByModel(model.version)
if (prefix && prefix.some(p => (ctx.message?.text ?? '').startsWith(p))) {
return model
}
}
return undefined
}

addSubagents (subagents: SubagentBase[]): void {
this.subagents = subagents
Expand All @@ -110,7 +157,7 @@ export abstract class LlmsBase implements PayableBot {
return !!this.supportedModels.find(model => model.version === ctx.session.currentModel)
}

protected async runSubagents (ctx: OnMessageContext | OnCallBackQueryData, msg: ChatConversation): Promise<void> {
protected async runSubagents (ctx: OnMessageContext | OnCallBackQueryData, msg: ChatConversation, stream: boolean, usesTools: boolean): Promise<void> {
const session = this.getSession(ctx)
await Promise.all(this.subagents.map(async (agent: SubagentBase) =>
await agent.run(ctx, msg)))
Expand All @@ -119,7 +166,7 @@ export abstract class LlmsBase implements PayableBot {
session.requestQueue.push(msg)
if (!session.isProcessingQueue) {
session.isProcessingQueue = true
await this.onChatRequestHandler(ctx, true, false).then(() => {
await this.onChatRequestHandler(ctx, stream, usesTools).then(() => {
session.isProcessingQueue = false
})
}
Expand Down Expand Up @@ -167,7 +214,7 @@ export abstract class LlmsBase implements PayableBot {
content: prompt as string ?? '', // await preparePrompt(ctx, prompt as string),
numSubAgents: supportedAgents
}
await this.runSubagents(ctx, msg) // prompt as string)
await this.runSubagents(ctx, msg, stream, usesTools) // prompt as string)
}
ctx.transient.analytics.actualResponseTime = now()
} catch (e: any) {
Expand Down
58 changes: 27 additions & 31 deletions src/modules/llms/openaiBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
RequestState
} from '../types'
import {
hasCommandPrefix,
hasNewPrefix,
isMentioned,
sendMessage,
Expand All @@ -30,7 +29,7 @@ export class OpenAIBot extends LlmsBase {

constructor (payments: BotPayments, subagents?: SubagentBase[]) {
super(payments, 'OpenAIBot', 'chatGpt', subagents)
this.gpt4oPrefix = this.modelManager.getPrefixByModel(this.modelsEnum.GPT_4O) ?? []
// this.gpt4oPrefix = this.modelManager.getPrefixByModel(this.modelsEnum.GPT_4O) ?? []
if (!config.openAi.dalle.isEnabled) {
this.logger.warn('DALL·E 2 Image Bot is disabled in config')
}
Expand All @@ -49,7 +48,7 @@ export class OpenAIBot extends LlmsBase {
public isSupportedEvent (
ctx: OnMessageContext | OnCallBackQueryData
): boolean {
const commands = ['last', ...this.modelManager.getCommandsByProvider('openai')]
const commands = ['last', ...this.supportedCommands]
const hasCommand = ctx.hasCommand(commands)
if (ctx.hasCommand(SupportedCommands.new) && this.checkModel(ctx)) {
return true
Expand Down Expand Up @@ -90,7 +89,8 @@ export class OpenAIBot extends LlmsBase {

hasPrefix (prompt: string): string {
return (
hasCommandPrefix(prompt, this.gpt4oPrefix) || hasNewPrefix(prompt) // hasDallePrefix(prompt)
this.supportedPrefixes.find(prefix => prompt.toLocaleLowerCase().startsWith(prefix)) ??
hasNewPrefix(prompt) // hasDallePrefix(prompt)
)
}

Expand All @@ -106,19 +106,9 @@ export class OpenAIBot extends LlmsBase {
return
}

if (
ctx.hasCommand([
this.commandsEnum.CHAT,
this.commandsEnum.ASK,
this.commandsEnum.GPT,
this.commandsEnum.GPTO
]) ||
hasCommandPrefix(ctx.message?.text ?? '', this.gpt4oPrefix) ||
isMentioned(ctx) ||
((ctx.message?.text?.startsWith('chat ') ??
if ((ctx.message?.text?.startsWith('chat ') ??
ctx.message?.text?.startsWith('ask ')) &&
ctx.chat?.type === 'private')
) {
ctx.chat?.type === 'private') {
this.updateSessionModel(ctx, this.modelsEnum.GPT_4O)
await this.onChat(ctx, this.modelsEnum.GPT_4O, true, false)
return
Expand All @@ -140,30 +130,36 @@ export class OpenAIBot extends LlmsBase {
return
}

if (ctx.hasCommand(this.commandsEnum.ASK35)) {
this.updateSessionModel(ctx, this.modelsEnum.GPT_35_TURBO)
await this.onChat(ctx, this.modelsEnum.GPT_35_TURBO, true, false)
return
}
// if (ctx.hasCommand(this.commandsEnum.ASK35)) {
// this.updateSessionModel(ctx, this.modelsEnum.GPT_35_TURBO)
// await this.onChat(ctx, this.modelsEnum.GPT_35_TURBO, true, false)
// return
// }

// if (ctx.hasCommand(this.commandsEnum.GPT4)) {
// this.updateSessionModel(ctx, this.modelsEnum.GPT_4)
// await this.onChat(ctx, this.modelsEnum.GPT_4, true, false)
// return
// }

// if (ctx.hasCommand([this.commandsEnum.O1, this.commandsEnum.ASK1])) {
// this.updateSessionModel(ctx, this.modelsEnum.O1)
// await this.onChat(ctx, this.modelsEnum.O1, false, false)
// return
// }

if (ctx.hasCommand(this.commandsEnum.GPT4)) {
this.updateSessionModel(ctx, this.modelsEnum.GPT_4)
await this.onChat(ctx, this.modelsEnum.GPT_4, true, false)
const model = this.getModelFromContext(ctx)
if (model) {
this.updateSessionModel(ctx, model.version)
await this.onChat(ctx, model.version, this.getStreamOption(model.version), false)
return
}

// if (ctx.hasCommand(this.commandsEnum.ASK32)) {
// this.updateSessionModel(ctx, this.modelsEnum.GPT_4_32K)
// await this.onChat(ctx, this.modelsEnum.GPT_4_32K, true, false)
// return
// }

if (ctx.hasCommand([this.commandsEnum.O1, this.commandsEnum.ASK1])) {
this.updateSessionModel(ctx, this.modelsEnum.O1)
await this.onChat(ctx, this.modelsEnum.O1, false, false)
return
}

if (ctx.hasCommand(SupportedCommands.last)) {
await this.onLast(ctx)
return
Expand Down
Loading

0 comments on commit 91be87d

Please sign in to comment.