Skip to content

Commit 6b075d9

Browse files
authored
Merge pull request #371 from harmony-one/message-sliding-window
add sliding window logic + add timestamp field
2 parents 96eb425 + 36a20e7 commit 6b075d9

File tree

12 files changed

+224
-28
lines changed

12 files changed

+224
-28
lines changed

src/bot.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,19 @@ const logErrorHandler = (ex: any): void => {
509509
logger.error(ex)
510510
}
511511

512+
// bot.command('testcleanup', async (ctx) => {
513+
// await openAiBot.testCleanup(ctx as OnMessageContext)
514+
// })
515+
516+
bot.command('new', async (ctx) => {
517+
writeCommandLog(ctx as OnMessageContext).catch(logErrorHandler)
518+
await openAiBot.onStop(ctx as OnMessageContext)
519+
return await ctx.reply('Chat history reseted', {
520+
parse_mode: 'Markdown',
521+
message_thread_id: ctx.message?.message_thread_id
522+
})
523+
})
524+
512525
bot.command('more', async (ctx) => {
513526
writeCommandLog(ctx as OnMessageContext).catch(logErrorHandler)
514527
return await ctx.reply(commandsHelpText.more, {

src/helpers.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import config from './config'
2+
import { conversationManager } from './modules/llms/utils/conversationManager'
23
import { LlmModelsEnum } from './modules/llms/utils/llmModelsManager'
34
import { type DalleImageSize } from './modules/llms/utils/types'
45
import { type BotSessionData } from './modules/types'
@@ -26,7 +27,8 @@ export function createInitialSessionData (): BotSessionData {
2627
price: 0,
2728
usage: 0,
2829
isProcessingQueue: false,
29-
requestQueue: []
30+
requestQueue: [],
31+
cleanupState: conversationManager.initializeCleanupTimes()
3032
},
3133
chatGpt: {
3234
model: config.llms.model,
@@ -36,7 +38,8 @@ export function createInitialSessionData (): BotSessionData {
3638
price: 0,
3739
usage: 0,
3840
isProcessingQueue: false,
39-
requestQueue: []
41+
requestQueue: [],
42+
cleanupState: conversationManager.initializeCleanupTimes()
4043
},
4144
dalle: {
4245
numImages: config.openAi.dalle.sessionDefault.numImages,

src/modules/llms/api/athropic.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ export const anthropicCompletion = async (
4949
completion: {
5050
content: completion[0].text,
5151
role: 'assistant',
52-
model
52+
model,
53+
timestamp: Date.now()
5354
},
5455
usage: totalOutputTokens + totalInputTokens,
5556
price: 0,
@@ -92,7 +93,8 @@ export const xaiCompletion = async (
9293
completion: {
9394
content: completion[0].text,
9495
role: 'assistant',
95-
model
96+
model,
97+
timestamp: Date.now()
9698
},
9799
usage: totalOutputTokens + totalInputTokens,
98100
price: 0,
@@ -202,7 +204,8 @@ export const anthropicStreamCompletion = async (
202204
completion: {
203205
content: completion,
204206
role: 'assistant',
205-
model
207+
model,
208+
timestamp: Date.now()
206209
},
207210
usage: parseInt(totalOutputTokens, 10) + parseInt(totalInputTokens, 10),
208211
price: 0,
@@ -252,7 +255,8 @@ export const toolsChatCompletion = async (
252255
completion: {
253256
content: completion[0].text,
254257
role: 'assistant',
255-
model
258+
model,
259+
timestamp: Date.now()
256260
},
257261
usage: totalOutputTokens + totalInputTokens,
258262
price: 0,
@@ -264,7 +268,8 @@ export const toolsChatCompletion = async (
264268
completion: {
265269
content: 'Timeout error',
266270
role: 'assistant',
267-
model
271+
model,
272+
timestamp: Date.now()
268273
},
269274
usage: 0,
270275
price: 0

src/modules/llms/api/llmApi.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import axios from 'axios'
22
import config from '../../../config'
3-
import { type ChatConversation } from '../../types'
3+
import { type ChatConversationWithoutTimestamp, type ChatConversation } from '../../types'
44
import pino from 'pino'
55
import { type ChatModel } from '../utils/types'
66
import { headers } from './helper'
@@ -36,7 +36,7 @@ interface LlmAddUrlDocument {
3636
interface QueryUrlDocument {
3737
collectioName: string
3838
prompt: string
39-
conversation?: ChatConversation[]
39+
conversation?: ChatConversationWithoutTimestamp[]
4040
}
4141

4242
export const getChatModel = (modelName: string): ChatModel | undefined => {
@@ -130,7 +130,8 @@ export const llmCompletion = async (
130130
completion: {
131131
content: completion[0].message?.content,
132132
role: 'system',
133-
model
133+
model,
134+
timestamp: Date.now()
134135
},
135136
usage: totalOutputTokens + totalInputTokens,
136137
price: 0

src/modules/llms/api/openai.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ export async function alterGeneratedImg (
7979
}
8080
}
8181

82-
const prepareConversation = (conversation: ChatConversation[], model: string): ChatConversation[] => {
82+
type ConversationOutput = Omit<ChatConversation, 'timestamp' | 'model' | 'id' | 'author' | 'numSubAgents'>
83+
84+
const prepareConversation = (conversation: ChatConversation[], model: string): ConversationOutput[] => {
8385
const messages = conversation.filter(c => c.model === model).map(m => { return { content: m.content, role: m.role } })
8486
if (messages.length !== 1 || model === LlmModelsEnum.O1) {
8587
return messages
@@ -125,7 +127,8 @@ export async function chatCompletion (
125127
return {
126128
completion: {
127129
content: response.choices[0].message?.content ?? 'Error - no completion available',
128-
role: 'assistant'
130+
role: 'assistant',
131+
timestamp: Date.now()
129132
},
130133
usage: response.usage?.total_tokens, // 2010
131134
price: price * config.openAi.chatGpt.priceAdjustment,
@@ -215,7 +218,8 @@ export const streamChatCompletion = async (
215218
return {
216219
completion: {
217220
content: completion,
218-
role: 'assistant'
221+
role: 'assistant',
222+
timestamp: Date.now()
219223
},
220224
usage: outputTokens + inputTokens,
221225
price: 0,
@@ -308,7 +312,8 @@ export const streamChatVisionCompletion = async (
308312
return {
309313
completion: {
310314
content: completion,
311-
role: 'assistant'
315+
role: 'assistant',
316+
timestamp: Date.now()
312317
},
313318
usage: outputTokens + inputTokens,
314319
price: 0,
@@ -319,7 +324,7 @@ export const streamChatVisionCompletion = async (
319324

320325
export async function improvePrompt (promptText: string, model: string): Promise<string> {
321326
const prompt = `Improve this picture description using max 100 words and don't add additional text to the image: ${promptText} `
322-
const conversation = [{ role: 'user', content: prompt }]
327+
const conversation = [{ role: 'user', content: prompt, timestamp: Date.now() }]
323328
const response = await chatCompletion(conversation, model)
324329
return response.completion?.content as string ?? ''
325330
}

src/modules/llms/api/pdfHandler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export const handlePdf = async (prompt: string): Promise<PdfCompletion> => {
1919
return {
2020
completion: {
2121
content: response.data.response,
22-
role: 'system'
22+
role: 'system',
23+
timestamp: Date.now()
2324
},
2425
prompt,
2526
price: response.data.cost

src/modules/llms/api/vertex.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import axios, { type AxiosResponse } from 'axios'
22
import config from '../../../config'
3-
import { type OnMessageContext, type ChatConversation, type OnCallBackQueryData } from '../../types'
3+
import { type OnMessageContext, type ChatConversation, type OnCallBackQueryData, type ChatConversationWithoutTimestamp } from '../../types'
44
import { type LlmCompletion } from './llmApi'
55
import { type Readable } from 'stream'
66
import { GrammyError } from 'grammy'
@@ -29,7 +29,7 @@ export const vertexCompletion = async (
2929
stream: false,
3030
messages: conversation.filter(c => c.model === model)
3131
.map((msg) => {
32-
const msgFiltered: ChatConversation = { content: msg.content, model: msg.model }
32+
const msgFiltered: ChatConversationWithoutTimestamp = { content: msg.content, model: msg.model }
3333
if (model === LlmModelsEnum.CHAT_BISON) {
3434
msgFiltered.author = msg.role
3535
} else {
@@ -48,7 +48,8 @@ export const vertexCompletion = async (
4848
completion: {
4949
content: response.data._prediction_response[0][0].candidates[0].content,
5050
role: 'bot', // role replace to author attribute will be done later
51-
model
51+
model,
52+
timestamp: Date.now()
5253
},
5354
usage: totalOutputTokens + totalInputTokens,
5455
price: 0
@@ -145,7 +146,8 @@ export const vertexStreamCompletion = async (
145146
completion: {
146147
content: completion,
147148
role: 'assistant',
148-
model
149+
model,
150+
timestamp: Date.now()
149151
},
150152
usage: parseInt(totalOutputTokens, 10) + parseInt(totalInputTokens, 10),
151153
price: 0,

src/modules/llms/llmsBase.ts

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
type LLMModelsManager,
3838
type ModelVersion
3939
} from './utils/llmModelsManager'
40+
import { conversationManager } from './utils/conversationManager'
4041

4142
export abstract class LlmsBase implements PayableBot {
4243
public module: string
@@ -205,7 +206,8 @@ export abstract class LlmsBase implements PayableBot {
205206
id: ctx.message?.message_id,
206207
model,
207208
content: await preparePrompt(ctx, prompt as string),
208-
numSubAgents: 0
209+
numSubAgents: 0,
210+
timestamp: Date.now()
209211
})
210212
if (!session.isProcessingQueue) {
211213
session.isProcessingQueue = true
@@ -218,7 +220,8 @@ export abstract class LlmsBase implements PayableBot {
218220
id: ctx.message?.message_id ?? ctx.message?.message_thread_id ?? 0,
219221
model,
220222
content: prompt as string ?? '', // await preparePrompt(ctx, prompt as string),
221-
numSubAgents: supportedAgents
223+
numSubAgents: supportedAgents,
224+
timestamp: Date.now()
222225
}
223226
await this.runSubagents(ctx, msg, stream, usesTools) // prompt as string)
224227
}
@@ -230,6 +233,7 @@ export abstract class LlmsBase implements PayableBot {
230233

231234
async onChatRequestHandler (ctx: OnMessageContext | OnCallBackQueryData, stream: boolean, usesTools: boolean): Promise<void> {
232235
const session = this.getSession(ctx)
236+
session.chatConversation = conversationManager.manageConversationWindow(session.chatConversation, ctx, this.sessionDataKey)
233237
while (session.requestQueue.length > 0) {
234238
try {
235239
const msg = session.requestQueue.shift()
@@ -272,7 +276,8 @@ export abstract class LlmsBase implements PayableBot {
272276
const chat: ChatConversation = {
273277
content: enhancedPrompt || prompt,
274278
role: 'user',
275-
model: modelVersion
279+
model: modelVersion,
280+
timestamp: Date.now()
276281
}
277282
chatConversation.push(chat)
278283
const payload = {
@@ -358,7 +363,8 @@ export abstract class LlmsBase implements PayableBot {
358363
conversation.push({
359364
role: 'assistant',
360365
content: completion.completion?.content ?? '',
361-
model
366+
model,
367+
timestamp: Date.now()
362368
})
363369
return {
364370
price: price.price,
@@ -371,7 +377,8 @@ export abstract class LlmsBase implements PayableBot {
371377
conversation.push({
372378
role: 'assistant',
373379
content: response.completion?.content ?? '',
374-
model
380+
model,
381+
timestamp: Date.now()
375382
})
376383
return {
377384
price: response.price,
@@ -470,6 +477,49 @@ export abstract class LlmsBase implements PayableBot {
470477
session.price = 0
471478
}
472479

480+
async testCleanup (ctx: OnMessageContext | OnCallBackQueryData): Promise<void> {
481+
const session = this.getSession(ctx)
482+
// Force cleanup times for testing
483+
const now = new Date()
484+
const forcedCleanupTime = new Date(now)
485+
forcedCleanupTime.setHours(2, 59, 0, 0) // Set to 2:59 AM
486+
session.cleanupState = {
487+
nextCleanupTime: forcedCleanupTime.getTime() + (60 * 1000), // 3 AM
488+
lastCleanupTime: forcedCleanupTime.getTime() - (24 * 60 * 60 * 1000) // Yesterday 2:59 AM
489+
}
490+
console.log('Testing cleanup with forced times:', {
491+
nextCleanup: new Date(session.cleanupState.nextCleanupTime).toLocaleString(),
492+
lastCleanup: new Date(session.cleanupState.lastCleanupTime).toLocaleString(),
493+
currentTime: now.toLocaleString()
494+
})
495+
// Add some test messages with various timestamps
496+
if (session.chatConversation.length === 0) {
497+
const yesterday = new Date(now)
498+
yesterday.setDate(yesterday.getDate() - 1)
499+
session.chatConversation = [
500+
{
501+
role: 'user',
502+
content: 'Message from 2 days ago',
503+
model: 'test',
504+
timestamp: yesterday.getTime() - (24 * 60 * 60 * 1000)
505+
},
506+
{
507+
role: 'assistant',
508+
content: 'Message from yesterday',
509+
model: 'test',
510+
timestamp: yesterday.getTime()
511+
},
512+
{
513+
role: 'user',
514+
content: 'Message from today',
515+
model: 'test',
516+
timestamp: now.getTime()
517+
}
518+
]
519+
}
520+
await this.onChatRequestHandler(ctx, false, false)
521+
}
522+
473523
async onError (
474524
ctx: OnMessageContext | OnCallBackQueryData,
475525
e: any,

0 commit comments

Comments
 (0)