fix(telegram-bot): incorrect interruption handling & better prompt & reply to message
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE "chat_messages" ADD COLUMN "platform_message_id" text DEFAULT '' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "chat_messages" ADD COLUMN "reply_to_id" text DEFAULT '' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "joined_chats" ADD CONSTRAINT "joined_chats_chat_id_unique" UNIQUE("chat_id");
|
||||
@@ -0,0 +1,518 @@
|
||||
{
|
||||
"id": "ac870f0c-2008-4053-b630-f3fb06ee7f8a",
|
||||
"prevId": "04759fdd-d3ec-4177-a6c3-69fc9df8105c",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.chat_messages": {
|
||||
"name": "chat_messages",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"platform": {
|
||||
"name": "platform",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"platform_message_id": {
|
||||
"name": "platform_message_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"from_id": {
|
||||
"name": "from_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"from_name": {
|
||||
"name": "from_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"in_chat_id": {
|
||||
"name": "in_chat_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"is_reply": {
|
||||
"name": "is_reply",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"reply_to_name": {
|
||||
"name": "reply_to_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"reply_to_id": {
|
||||
"name": "reply_to_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"content_vector_1536": {
|
||||
"name": "content_vector_1536",
|
||||
"type": "vector(1536)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"content_vector_1024": {
|
||||
"name": "content_vector_1024",
|
||||
"type": "vector(1024)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"content_vector_768": {
|
||||
"name": "content_vector_768",
|
||||
"type": "vector(768)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"chat_messages_content_vector_1536_index": {
|
||||
"name": "chat_messages_content_vector_1536_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "content_vector_1536",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
},
|
||||
"chat_messages_content_vector_1024_index": {
|
||||
"name": "chat_messages_content_vector_1024_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "content_vector_1024",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
},
|
||||
"chat_messages_content_vector_768_index": {
|
||||
"name": "chat_messages_content_vector_768_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "content_vector_768",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.joined_chats": {
|
||||
"name": "joined_chats",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"platform": {
|
||||
"name": "platform",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"chat_id": {
|
||||
"name": "chat_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"chat_name": {
|
||||
"name": "chat_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"joined_chats_chat_id_unique": {
|
||||
"name": "joined_chats_chat_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"chat_id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.photos": {
|
||||
"name": "photos",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"platform": {
|
||||
"name": "platform",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"file_id": {
|
||||
"name": "file_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"image_base64": {
|
||||
"name": "image_base64",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"image_path": {
|
||||
"name": "image_path",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"description_vector_1536": {
|
||||
"name": "description_vector_1536",
|
||||
"type": "vector(1536)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description_vector_1024": {
|
||||
"name": "description_vector_1024",
|
||||
"type": "vector(1024)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description_vector_768": {
|
||||
"name": "description_vector_768",
|
||||
"type": "vector(768)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"photos_description_vector_1536_index": {
|
||||
"name": "photos_description_vector_1536_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "description_vector_1536",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
},
|
||||
"photos_description_vector_1024_index": {
|
||||
"name": "photos_description_vector_1024_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "description_vector_1024",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
},
|
||||
"photos_description_vector_768_index": {
|
||||
"name": "photos_description_vector_768_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "description_vector_768",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.stickers": {
|
||||
"name": "stickers",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"platform": {
|
||||
"name": "platform",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"file_id": {
|
||||
"name": "file_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"image_base64": {
|
||||
"name": "image_base64",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"image_path": {
|
||||
"name": "image_path",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"description_vector_1536": {
|
||||
"name": "description_vector_1536",
|
||||
"type": "vector(1536)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description_vector_1024": {
|
||||
"name": "description_vector_1024",
|
||||
"type": "vector(1024)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description_vector_768": {
|
||||
"name": "description_vector_768",
|
||||
"type": "vector(768)",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"stickers_description_vector_1536_index": {
|
||||
"name": "stickers_description_vector_1536_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "description_vector_1536",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
},
|
||||
"stickers_description_vector_1024_index": {
|
||||
"name": "stickers_description_vector_1024_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "description_vector_1024",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
},
|
||||
"stickers_description_vector_768_index": {
|
||||
"name": "stickers_description_vector_768_index",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "description_vector_768",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last",
|
||||
"opclass": "vector_cosine_ops"
|
||||
}
|
||||
],
|
||||
"isUnique": false,
|
||||
"concurrently": false,
|
||||
"method": "hnsw",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,13 @@
|
||||
"when": 1742736839659,
|
||||
"tag": "0001_next_talkback",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1742980513463,
|
||||
"tag": "0002_calm_magdalene",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -225,7 +225,17 @@ async function processMessageQueue(state: BotSelf) {
|
||||
}
|
||||
|
||||
if (nextMsg.status === 'ready') {
|
||||
await recordJoinedChat(nextMsg.message.chat.id.toString(), nextMsg.message.chat.title)
|
||||
switch (nextMsg.message.chat.type) {
|
||||
case 'private':
|
||||
await recordJoinedChat(nextMsg.message.chat.id.toString(), `${nextMsg.message.from.first_name} ${nextMsg.message.from.last_name}`)
|
||||
break
|
||||
case 'channel':
|
||||
case 'group':
|
||||
case 'supergroup':
|
||||
await recordJoinedChat(nextMsg.message.chat.id.toString(), nextMsg.message.chat.title)
|
||||
break
|
||||
}
|
||||
|
||||
await recordMessage(state.bot.botInfo, nextMsg.message)
|
||||
|
||||
let unreadMessagesForThisChat = state.unreadMessages[nextMsg.message.chat.id]
|
||||
@@ -250,7 +260,7 @@ async function processMessageQueue(state: BotSelf) {
|
||||
state.logger.withField('chatId', nextMsg.message.chat.id).log('message queue processed, triggering immediate reaction')
|
||||
|
||||
// Trigger immediate processing when messages are ready
|
||||
await handleLoop(state, [], nextMsg.message.chat.id.toString())
|
||||
handleLoop(state, [], nextMsg.message.chat.id.toString())
|
||||
state.messageQueue.shift()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,11 +72,16 @@ export async function readMessage(
|
||||
+ 'All the messages you requested to read:\n'
|
||||
+ `${unreadHistoryMessageOneliner || 'No messages'}`
|
||||
+ '\n'
|
||||
+ 'Based on your personalities, imaging you have your own choice and interest over different, '
|
||||
+ 'Based on your personalities, imaging you have your own choice and interest over different topics, '
|
||||
+ 'giving the above context and chat history, would you like to participate in the conversation '
|
||||
+ 'about the topic? Or will you aggressively diss or piss off about the opinions of others?\n'
|
||||
+ 'Feel free to ignore by just sending an empty array (i.e. []).'
|
||||
+ 'If you would like to participate, send me an array of messages you would like to send without telling you willing to participate.'
|
||||
+ 'Feel free to ignore by just sending an empty array within a object with key "messages" (i.e.'
|
||||
+ '{ "messages": [] }).'
|
||||
+ 'If you would like to participate, send me an array of messages (i.e. { "messages": [] }) you would '
|
||||
+ 'like to send without telling you willing to participate.'
|
||||
+ 'If you would like to reply to any of the message, send me an array of messages (i.e. { "messages":'
|
||||
+ '["message content"], "reply_to_message_id": "1234567890" }) with the message id of the message you '
|
||||
+ 'want to reply to.'
|
||||
+ '\n'
|
||||
+ 'Choose your action.',
|
||||
),
|
||||
|
||||
@@ -4,33 +4,42 @@ import { parseMayStructuredMessage } from './message'
|
||||
|
||||
describe('parseMayStructuredMessage', () => {
|
||||
it('should return an array of messages', () => {
|
||||
const result = parseMayStructuredMessage('["Hello, world!"]')
|
||||
expect(result).toEqual(['Hello, world!'])
|
||||
const result = parseMayStructuredMessage('{"messages": ["Hello, world!"]}')
|
||||
expect(result).toMatchObject({ messages: ['Hello, world!'] })
|
||||
})
|
||||
|
||||
it('should return an array of messages from multi-line input', () => {
|
||||
const result = parseMayStructuredMessage(`[
|
||||
const result = parseMayStructuredMessage(`{"messages": [
|
||||
"Hello, world!",
|
||||
"Hello, world!"
|
||||
]`)
|
||||
expect(result).toEqual(['Hello, world!', 'Hello, world!'])
|
||||
]}`)
|
||||
expect(result).toMatchObject({ messages: ['Hello, world!', 'Hello, world!'] })
|
||||
})
|
||||
|
||||
it('should return an array of messages from multi-line input with extra whitespace', () => {
|
||||
const result = parseMayStructuredMessage(`[
|
||||
const result = parseMayStructuredMessage(`{"messages": [
|
||||
"Hello, world!",
|
||||
"Hello, world!"
|
||||
]`)
|
||||
expect(result).toEqual(['Hello, world!', 'Hello, world!'])
|
||||
]}`)
|
||||
expect(result).toMatchObject({ messages: ['Hello, world!', 'Hello, world!'] })
|
||||
})
|
||||
|
||||
it('should return an object with messages and reply_to_message_id', () => {
|
||||
const result = parseMayStructuredMessage(`{"messages": [
|
||||
"Hello, world!",
|
||||
"Hello, world!"
|
||||
], "reply_to_message_id": "1234567890"
|
||||
}`)
|
||||
expect(result).toMatchObject({ messages: ['Hello, world!', 'Hello, world!'], reply_to_message_id: '1234567890' })
|
||||
})
|
||||
|
||||
it('should return an array of messages from multi-line elements of input', () => {
|
||||
const result = parseMayStructuredMessage(`[
|
||||
const result = parseMayStructuredMessage(`{"messages": [
|
||||
"Hello,
|
||||
world!",
|
||||
"Hello,
|
||||
world!"
|
||||
]`)
|
||||
expect(result).toEqual(['Hello,\nworld!', 'Hello,\nworld!'])
|
||||
]}`)
|
||||
expect(result).toMatchObject({ messages: ['Hello,\nworld!', 'Hello,\nworld!'] })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,23 +12,15 @@ import { cancellable, sleep } from '../../../utils/promise'
|
||||
export function parseMayStructuredMessage(responseText: string) {
|
||||
const logger = useLogg('parseMayStructuredMessage').useGlobalConfig()
|
||||
|
||||
// If we get here, the task wasn't cancelled, so we can send the response
|
||||
// eslint-disable-next-line regexp/no-unused-capturing-group, regexp/no-super-linear-backtracking, regexp/confusing-quantifier
|
||||
if (/\[(\s*.*)+\]/u.test(responseText)) {
|
||||
// eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/confusing-quantifier, regexp/no-unused-capturing-group
|
||||
const result = /\[(\s*.*)+\]/u.exec(responseText)
|
||||
logger.withField('text', JSON.stringify(responseText)).withField('result', result?.[0]).log('Multiple messages detected')
|
||||
// eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/optimal-quantifier-concatenation
|
||||
const result = /^\{(("?)*.*\s*)*\}$/u.exec(responseText)
|
||||
if (result) {
|
||||
logger.withField('text', JSON.stringify(responseText)).withField('result', result).log('Multiple messages detected')
|
||||
|
||||
const array = parse(result?.[0]) as string[]
|
||||
if (array == null || !Array.isArray(array) || array.length === 0) {
|
||||
logger.withField('text', JSON.stringify(responseText)).withField('result', result?.[0]).log('No messages to send')
|
||||
return
|
||||
}
|
||||
|
||||
return array.filter(Boolean)
|
||||
return parse(result?.[0]) as ({ messages?: string[], reply_to_message_id?: string } | undefined)
|
||||
}
|
||||
|
||||
return [responseText]
|
||||
return { messages: [responseText], reply_to_message_id: undefined }
|
||||
}
|
||||
|
||||
export async function sendMayStructuredMessage(
|
||||
@@ -59,24 +51,34 @@ export async function sendMayStructuredMessage(
|
||||
return // Don't send the message, let the next processing loop handle it
|
||||
}
|
||||
|
||||
const array = parseMayStructuredMessage(responseText)
|
||||
if (array == null) {
|
||||
const structuredMessage = parseMayStructuredMessage(responseText)
|
||||
if (structuredMessage == null) {
|
||||
state.logger.log(`Not sending message to ${chatId} - no messages to send`)
|
||||
return
|
||||
}
|
||||
|
||||
state.logger.withField('texts', array).log('Sending messages')
|
||||
state.logger.withField('texts', structuredMessage).log('Sending messages')
|
||||
|
||||
// If we get here, the task wasn't cancelled, so we can send the response
|
||||
for (const item of array) {
|
||||
for (let i = 0; i < structuredMessage.messages.length; i++) {
|
||||
const item = structuredMessage.messages[i]
|
||||
|
||||
// Create cancellable typing and reply tasks
|
||||
await state.bot.api.sendChatAction(chatId, 'typing')
|
||||
await sleep(item.length * 200)
|
||||
await sleep(item.length * 50)
|
||||
|
||||
const replyTask = cancellable((async (): Promise<Message.TextMessage> => {
|
||||
try {
|
||||
const sentResult = await state.bot.api.sendMessage(chatId, item)
|
||||
return sentResult
|
||||
const validReplyToMessageId = structuredMessage.reply_to_message_id ? Number.parseInt(structuredMessage.reply_to_message_id) : undefined
|
||||
|
||||
if (i === 0 && validReplyToMessageId && !Number.isNaN(validReplyToMessageId)) {
|
||||
const sentResult = await state.bot.api.sendMessage(chatId, item, { reply_parameters: { message_id: validReplyToMessageId } })
|
||||
return sentResult
|
||||
}
|
||||
else {
|
||||
const sentResult = await state.bot.api.sendMessage(chatId, item)
|
||||
return sentResult
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
state.logger.withError(err).log('Failed to send message')
|
||||
|
||||
@@ -3,12 +3,14 @@ import { bigint, boolean, index, pgTable, text, uniqueIndex, uuid, vector } from
|
||||
export const chatMessagesTable = pgTable('chat_messages', {
|
||||
id: uuid().primaryKey().defaultRandom(),
|
||||
platform: text().notNull().default(''),
|
||||
platform_message_id: text().notNull().default(''),
|
||||
from_id: text().notNull().default(''),
|
||||
from_name: text().notNull().default(''),
|
||||
in_chat_id: text().notNull().default(''),
|
||||
content: text().notNull().default(''),
|
||||
is_reply: boolean().notNull().default(false),
|
||||
reply_to_name: text().notNull().default(''),
|
||||
reply_to_id: text().notNull().default(''),
|
||||
created_at: bigint({ mode: 'number' }).notNull().default(0).$defaultFn(() => Date.now()),
|
||||
updated_at: bigint({ mode: 'number' }).notNull().default(0).$defaultFn(() => Date.now()),
|
||||
content_vector_1536: vector({ dimensions: 1536 }),
|
||||
|
||||
@@ -4,21 +4,18 @@ import type { Action } from '../types'
|
||||
|
||||
import { env } from 'node:process'
|
||||
import { useLogg } from '@guiiai/logg'
|
||||
import { embed } from '@xsai/embed'
|
||||
import { generateText } from '@xsai/generate-text'
|
||||
import { message } from '@xsai/utils-chat'
|
||||
import { parse } from 'best-effort-json-parser'
|
||||
|
||||
import { chatMessageToOneLine, findLastNMessages, findRelevantMessages } from '../models'
|
||||
import { systemPrompt } from '../prompts/system-v1'
|
||||
import { div, ul } from '../prompts/utils'
|
||||
|
||||
export async function imagineAnAction(
|
||||
botId: string,
|
||||
_botId: string,
|
||||
unreadMessages: Record<string, Message[]>,
|
||||
currentAbortController: AbortController,
|
||||
agentMessages: LLMMessage[],
|
||||
lastInteractedNChatIds: string[],
|
||||
_lastInteractedNChatIds: string[],
|
||||
) {
|
||||
const logger = useLogg('imagineAnAction').useGlobalConfig()
|
||||
|
||||
@@ -26,41 +23,6 @@ export async function imagineAnAction(
|
||||
agentMessages = []
|
||||
}
|
||||
|
||||
lastInteractedNChatIds.map(async (chatId) => {
|
||||
const lastNMessages = await findLastNMessages(chatId, 15)
|
||||
const lastNMessagesOneliner = lastNMessages.map(msg => chatMessageToOneLine(botId, msg))
|
||||
|
||||
const lastNMessagesEmbeddingPromises = lastNMessages
|
||||
.map(async (msg) => {
|
||||
const embeddingResult = await embed({
|
||||
baseURL: env.EMBEDDING_API_BASE_URL!,
|
||||
apiKey: env.EMBEDDING_API_KEY!,
|
||||
model: env.EMBEDDING_MODEL!,
|
||||
input: chatMessageToOneLine(botId, msg),
|
||||
abortSignal: currentAbortController.signal,
|
||||
})
|
||||
|
||||
return {
|
||||
embedding: embeddingResult.embedding,
|
||||
message: msg,
|
||||
}
|
||||
})
|
||||
|
||||
const lastNMessagesEmbedding = await Promise.all(lastNMessagesEmbeddingPromises)
|
||||
const relevantChatMessages = await findRelevantMessages(botId, chatId, lastNMessagesEmbedding)
|
||||
const relevantChatMessagesOneliner = await Promise.all(relevantChatMessages.map(async msgs => msgs.join('\n')))
|
||||
|
||||
return message.user(
|
||||
div(
|
||||
'Here are a brief list of the recent interacted chat ids\' message review',
|
||||
`Last 15 messages in chat ${chatId}:`,
|
||||
ul(...lastNMessagesOneliner),
|
||||
`Relevant messages in chat ${chatId}:`,
|
||||
ul(...relevantChatMessagesOneliner),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
agentMessages.push(
|
||||
message.system(''
|
||||
+ `${systemPrompt()}`
|
||||
@@ -82,7 +44,7 @@ export async function imagineAnAction(
|
||||
},
|
||||
{
|
||||
description: `Send a message to a specific chat group. If you want to express anything to anyone or your friends in group, you can use this action.${!!env.LLM_RESPONSE_LANGUAGE}` ? `The language of the sending message should be in ${env.LLM_RESPONSE_LANGUAGE}.` : '',
|
||||
example: { action: 'sendMessage', content: '<content>', chatId: 'id of chat to send to' },
|
||||
example: { action: 'sendMessage', content: '<content>', chatId: 'id of chat to send to', reply_to_message_id: 'id of message to reply to (Optional)' },
|
||||
},
|
||||
{
|
||||
description: 'Read unread messages from a specific chat group. If you want to read the unread messages from a specific chat group, you can use this action.',
|
||||
|
||||
@@ -44,11 +44,13 @@ export async function recordMessage(botInfo: UserFromGetMe, message: Message) {
|
||||
const values: Partial<Omit<typeof chatMessagesTable.$inferSelect, 'id' | 'created_at' | 'updated_at'>> = {
|
||||
platform: 'telegram',
|
||||
from_id: message.from.id.toString(),
|
||||
platform_message_id: message.message_id.toString(),
|
||||
from_name: message.from.first_name,
|
||||
in_chat_id: message.chat.id.toString(),
|
||||
content: text,
|
||||
is_reply: !!message.reply_to_message,
|
||||
reply_to_name: replyToName === botInfo.first_name ? 'Yourself' : replyToName,
|
||||
reply_to_id: message.reply_to_message?.message_id.toString() || '',
|
||||
}
|
||||
|
||||
switch (env.EMBEDDING_DIMENSION) {
|
||||
@@ -113,12 +115,14 @@ export async function findRelevantMessages(botId: string, chatId: string, unread
|
||||
.select({
|
||||
id: chatMessagesTable.id,
|
||||
platform: chatMessagesTable.platform,
|
||||
platform_message_id: chatMessagesTable.platform_message_id,
|
||||
from_id: chatMessagesTable.from_id,
|
||||
from_name: chatMessagesTable.from_name,
|
||||
in_chat_id: chatMessagesTable.in_chat_id,
|
||||
content: chatMessagesTable.content,
|
||||
is_reply: chatMessagesTable.is_reply,
|
||||
reply_to_name: chatMessagesTable.reply_to_name,
|
||||
reply_to_id: chatMessagesTable.reply_to_id,
|
||||
created_at: chatMessagesTable.created_at,
|
||||
updated_at: chatMessagesTable.updated_at,
|
||||
similarity: sql`${similarity} AS "similarity"`,
|
||||
@@ -144,12 +148,14 @@ export async function findRelevantMessages(botId: string, chatId: string, unread
|
||||
.select({
|
||||
id: chatMessagesTable.id,
|
||||
platform: chatMessagesTable.platform,
|
||||
platform_message_id: chatMessagesTable.platform_message_id,
|
||||
from_id: chatMessagesTable.from_id,
|
||||
from_name: chatMessagesTable.from_name,
|
||||
in_chat_id: chatMessagesTable.in_chat_id,
|
||||
content: chatMessagesTable.content,
|
||||
is_reply: chatMessagesTable.is_reply,
|
||||
reply_to_name: chatMessagesTable.reply_to_name,
|
||||
reply_to_id: chatMessagesTable.reply_to_id,
|
||||
created_at: chatMessagesTable.created_at,
|
||||
updated_at: chatMessagesTable.updated_at,
|
||||
})
|
||||
@@ -167,12 +173,14 @@ export async function findRelevantMessages(botId: string, chatId: string, unread
|
||||
.select({
|
||||
id: chatMessagesTable.id,
|
||||
platform: chatMessagesTable.platform,
|
||||
platform_message_id: chatMessagesTable.platform_message_id,
|
||||
from_id: chatMessagesTable.from_id,
|
||||
from_name: chatMessagesTable.from_name,
|
||||
in_chat_id: chatMessagesTable.in_chat_id,
|
||||
content: chatMessagesTable.content,
|
||||
is_reply: chatMessagesTable.is_reply,
|
||||
reply_to_name: chatMessagesTable.reply_to_name,
|
||||
reply_to_id: chatMessagesTable.reply_to_id,
|
||||
created_at: chatMessagesTable.created_at,
|
||||
updated_at: chatMessagesTable.updated_at,
|
||||
})
|
||||
|
||||
@@ -12,10 +12,10 @@ export function chatMessageToOneLine(botId: string, message: Omit<typeof chatMes
|
||||
}
|
||||
|
||||
if (message.is_reply) {
|
||||
return `${new Date(message.created_at).toLocaleString()} ${userDisplayName} replied to ${message.reply_to_name} in same group said: ${message.content}`
|
||||
return `Message ID: ${message.platform_message_id || 'Unknown'} sent on ${new Date(message.created_at).toLocaleString()} ${userDisplayName} replied to ${message.reply_to_name} with id ${message.reply_to_id} in same group said: ${message.content}`
|
||||
}
|
||||
|
||||
return `${new Date(message.created_at).toLocaleString()} ${userDisplayName} sent in same group said: ${message.content}`
|
||||
return `Message ID: ${message.platform_message_id || 'Unknown'} sent on ${new Date(message.created_at).toLocaleString()} ${userDisplayName} sent in same group said: ${message.content}`
|
||||
}
|
||||
|
||||
export async function telegramMessageToOneLine(botId: string, message: Message) {
|
||||
@@ -23,6 +23,7 @@ export async function telegramMessageToOneLine(botId: string, message: Message)
|
||||
return ''
|
||||
}
|
||||
|
||||
const sentOn = new Date(message.date * 1000).toLocaleString()
|
||||
let userDisplayName = `User [${message.from.first_name} ${message.from.last_name} (${message.from.username})]`
|
||||
if (botId === message.from.id.toString()) {
|
||||
userDisplayName = 'Yourself'
|
||||
@@ -30,20 +31,20 @@ export async function telegramMessageToOneLine(botId: string, message: Message)
|
||||
|
||||
if (message.sticker != null) {
|
||||
const description = await findStickerDescription(message.sticker.file_id)
|
||||
return `${new Date(message.date * 1000).toLocaleString()} ${userDisplayName} sent in Group [${message.chat.title}] a sticker, and description of the sticker is ${description}`
|
||||
return `Message ID: ${message.message_id || 'Unknown'} sent on ${sentOn} ${userDisplayName} sent in Group [${message.chat.title}] a sticker, and description of the sticker is ${description}`
|
||||
}
|
||||
if (message.photo != null) {
|
||||
const description = await findPhotoDescription(message.photo[0].file_id)
|
||||
return `${new Date(message.date * 1000).toLocaleString()} ${userDisplayName} sent in Group [${message.chat.title}] a photo, and description of the photo is ${description}`
|
||||
return `Message ID: ${message.message_id || 'Unknown'} sent on ${sentOn} ${userDisplayName} sent in Group [${message.chat.title}] a photo, and description of the photo is ${description}`
|
||||
}
|
||||
if (message.reply_to_message != null) {
|
||||
if (botId === message.reply_to_message.from.id.toString()) {
|
||||
return `${new Date(message.date * 1000).toLocaleString()} ${userDisplayName} replied to your previous message ${message.reply_to_message.text || message.caption} in Group [${message.chat.title}] said: ${message.text}`
|
||||
return `Message ID: ${message.message_id || 'Unknown'} sent on ${sentOn} ${userDisplayName} replied to your previous message ${message.reply_to_message.text || message.caption} in Group [${message.chat.title}] said: ${message.text}`
|
||||
}
|
||||
else {
|
||||
return `${new Date(message.date * 1000).toLocaleString()} ${userDisplayName} replied to User [${message.reply_to_message.from.first_name} ${message.reply_to_message.from.last_name} (${message.reply_to_message.from.username})] in Group [${message.chat.title}] said: ${message.text}`
|
||||
return `Message ID: ${message.message_id || 'Unknown'} sent on ${sentOn} ${userDisplayName} replied to User [${message.reply_to_message.from.first_name} ${message.reply_to_message.from.last_name} (${message.reply_to_message.from.username})] in Group [${message.chat.title}] said: ${message.text}`
|
||||
}
|
||||
}
|
||||
|
||||
return `${new Date(message.date * 1000).toLocaleString()} ${userDisplayName} sent in Group [${message.chat.title}] said: ${message.text}`
|
||||
return `Message ID: ${message.message_id || 'Unknown'} sent on ${sentOn} ${userDisplayName} sent in Group [${message.chat.title}] said: ${message.text}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user