feat: integrated as Airi client

This commit is contained in:
Neko Ayaka
2025-01-16 16:27:42 +08:00
parent f09fdbb270
commit e203ecea96
2 changed files with 49 additions and 3 deletions
+4 -1
View File
@@ -1,6 +1,7 @@
import process, { exit } from 'node:process'
import { useLogg } from '@guiiai/logg'
import { Client } from '@proj-airi/server-sdk'
import MineflayerArmorManager from 'mineflayer-armor-manager'
import { loader as MineflayerAutoEat } from 'mineflayer-auto-eat'
import { plugin as MineflayerCollectBlock } from 'mineflayer-collectblock'
@@ -33,9 +34,11 @@ async function main() {
],
})
const airiClient = new Client({ name: 'minecraft-bot', url: 'ws://localhost:6121/ws' })
// Dynamically load LLMAgent after bot is initialized
const agent = await initAgent(bot)
await bot.loadPlugin(LLMAgent({ agent }))
await bot.loadPlugin(LLMAgent({ agent, airiClient }))
process.on('SIGINT', () => {
bot.stop()
+45 -2
View File
@@ -1,13 +1,14 @@
import type { Client } from '@proj-airi/server-sdk'
import type { Neuri } from 'neuri'
import type { MineflayerPlugin } from '../libs/mineflayer/plugin'
import type { MineflayerPlugin } from '../libs/mineflayer/plugin'
import { useLogg } from '@guiiai/logg'
import { assistant, system, user } from 'neuri/openai'
import { toRetriable } from 'src/utils/reliability'
import { formBotChat } from '../libs/mineflayer/message'
import { genActionAgentPrompt, genStatusPrompt } from '../prompts/agent'
export function LLMAgent(options: { agent: Neuri }): MineflayerPlugin {
export function LLMAgent(options: { agent: Neuri, airiClient: Client }): MineflayerPlugin {
return {
async created(bot) {
const agent = options.agent
@@ -59,6 +60,48 @@ export function LLMAgent(options: { agent: Neuri }): MineflayerPlugin {
}
})
options.airiClient.onEvent('input:text:voice', async (event) => {
logger.withFields({ user: event.data.discord?.guildMember, message: event.data.transcription }).log('Chat message received')
const statusPrompt = await genStatusPrompt(bot)
bot.memory.chatHistory.push(system(statusPrompt))
bot.memory.chatHistory.push(user(`${'NekoMeowww'}: ${event.data.transcription}`))
// logger.withFields({ chatHistory: bot.memory.chatHistory }).log('chatHistory')
logger.withFields({ statusPrompt }).log('statusPrompt')
const content = await agent.handleStateless([...bot.memory.chatHistory], async (c) => {
logger.log('thinking...')
const handleCompletion = async (c: any): Promise<string> => {
const completion = await c.reroute('action', c.messages, { model: 'openai/gpt-4o-mini' }) || { error: { message: 'Unknown error' } }
if (!completion || 'error' in completion) {
logger.withFields(c).error('Completion')
throw new Error(completion?.error?.message ?? 'Unknown error')
}
const content = await completion?.firstContent()
logger.withFields({ usage: completion.usage, content }).log('output')
bot.memory.chatHistory.push(assistant(content))
return content
}
const retirableHandler = toRetriable<any, string>(
3, // retryLimit
1000, // delayInterval in ms
handleCompletion,
)
return await retirableHandler(c)
})
if (content) {
logger.withFields({ content }).log('responded')
bot.bot.chat(content)
}
})
bot.bot.on('chat', onChat)
},
}