From 63643b9832bf8d534ea1700812f902a13b0eaa30 Mon Sep 17 00:00:00 2001 From: RainbowBird Date: Fri, 7 Feb 2025 01:36:26 +0800 Subject: [PATCH] refactor: config --- .../src/agents/action/adapter.test.ts | 8 +- .../minecraft/src/agents/action/tools.test.ts | 10 +-- services/minecraft/src/agents/chat/llm.ts | 4 +- services/minecraft/src/composables/config.ts | 73 ++++++++++++------- services/minecraft/src/composables/neuri.ts | 6 +- .../src/libs/llm-agent/completion.ts | 4 +- .../minecraft/src/libs/llm-agent/handler.ts | 4 +- .../minecraft/src/libs/llm-agent/index.ts | 4 +- services/minecraft/src/main.ts | 10 ++- 9 files changed, 73 insertions(+), 50 deletions(-) diff --git a/services/minecraft/src/agents/action/adapter.test.ts b/services/minecraft/src/agents/action/adapter.test.ts index 08c9cf303..828a0c54c 100644 --- a/services/minecraft/src/agents/action/adapter.test.ts +++ b/services/minecraft/src/agents/action/adapter.test.ts @@ -2,16 +2,16 @@ import { messages, system, user } from 'neuri/openai' import { beforeAll, describe, expect, it } from 'vitest' import { initBot, useBot } from '../../composables/bot' -import { botConfig, initEnv, openaiConfig } from '../../composables/config' +import { config, initEnv } from '../../composables/config' import { createNeuriAgent } from '../../composables/neuri' +import { generateSystemBasicPrompt } from '../../libs/llm-agent/prompt' import { initLogger } from '../../utils/logger' -import { generateSystemBasicPrompt } from '../prompt/llm-agent' describe('openAI agent', { timeout: 0 }, () => { beforeAll(() => { initLogger() initEnv() - initBot({ botConfig }) + initBot({ botConfig: config.bot }) }) it('should initialize the agent', async () => { @@ -26,7 +26,7 @@ describe('openAI agent', { timeout: 0 }, () => { user('Hello, who are you?'), ), async (c) => { - const completion = await c.reroute('query', c.messages, { model: openaiConfig.model }) + const completion = await c.reroute('query', c.messages, { model: config.openai.model }) return await completion?.firstContent() }, ) diff --git a/services/minecraft/src/agents/action/tools.test.ts b/services/minecraft/src/agents/action/tools.test.ts index 1f6add120..14af19f8e 100644 --- a/services/minecraft/src/agents/action/tools.test.ts +++ b/services/minecraft/src/agents/action/tools.test.ts @@ -2,17 +2,17 @@ import { messages, system, user } from 'neuri/openai' import { beforeAll, describe, expect, it } from 'vitest' import { initBot, useBot } from '../../composables/bot' -import { botConfig, initEnv, openaiConfig } from '../../composables/config' +import { config, initEnv } from '../../composables/config' import { createNeuriAgent } from '../../composables/neuri' +import { generateActionAgentPrompt } from '../../libs/llm-agent/prompt' import { sleep } from '../../utils/helper' import { initLogger } from '../../utils/logger' -import { generateActionAgentPrompt } from '../prompt/llm-agent' describe('actions agent', { timeout: 0 }, () => { beforeAll(() => { initLogger() initEnv() - initBot({ botConfig }) + initBot({ botConfig: config.bot }) }) it('should choose right query command', async () => { @@ -25,7 +25,7 @@ describe('actions agent', { timeout: 0 }, () => { system(generateActionAgentPrompt(bot)), user('What\'s your status?'), ), async (c) => { - const completion = await c.reroute('query', c.messages, { model: openaiConfig.model }) + const completion = await c.reroute('query', c.messages, { model: config.openai.model }) return await completion?.firstContent() }) @@ -46,7 +46,7 @@ describe('actions agent', { timeout: 0 }, () => { system(generateActionAgentPrompt(bot)), user('goToPlayer: luoling8192'), ), async (c) => { - const completion = await c.reroute('action', c.messages, { model: openaiConfig.model }) + const completion = await c.reroute('action', c.messages, { model: config.openai.model }) return await completion?.firstContent() }) diff --git a/services/minecraft/src/agents/chat/llm.ts b/services/minecraft/src/agents/chat/llm.ts index 6b97f3b54..ae4672e0c 100644 --- a/services/minecraft/src/agents/chat/llm.ts +++ b/services/minecraft/src/agents/chat/llm.ts @@ -5,7 +5,7 @@ import { useLogg } from '@guiiai/logg' import { agent } from 'neuri' import { system, user } from 'neuri/openai' -import { openaiConfig } from '../../composables/config' +import { config as appConfig } from '../../composables/config' import { toRetriable } from '../../utils/helper' import { generateChatAgentPrompt } from './adapter' @@ -43,7 +43,7 @@ export async function generateChatResponse( const handleCompletion = async (c: any): Promise => { const completion = await c.reroute('chat', c.messages, { - model: config.model ?? openaiConfig.model, + model: config.model ?? appConfig.openai.model, }) if (!completion || 'error' in completion) { diff --git a/services/minecraft/src/composables/config.ts b/services/minecraft/src/composables/config.ts index 81c7ec330..e53f25bf4 100644 --- a/services/minecraft/src/composables/config.ts +++ b/services/minecraft/src/composables/config.ts @@ -13,13 +13,28 @@ interface OpenAIConfig { reasoningModel: string } -interface EnvConfig { +interface AiriConfig { + wsBaseUrl: string + clientName: string +} + +interface Config { openai: OpenAIConfig bot: BotOptions + airi: AiriConfig +} + +// Helper functions for type-safe environment variable parsing +function getEnvVar(key: string, defaultValue: string): string { + return env[key] || defaultValue +} + +function getEnvNumber(key: string, defaultValue: number): number { + return Number.parseInt(env[key] || String(defaultValue)) } // Default configurations -const defaultConfig: EnvConfig = { +const defaultConfig: Config = { openai: { apiKey: '', baseUrl: '', @@ -27,41 +42,45 @@ const defaultConfig: EnvConfig = { reasoningModel: '', }, bot: { - username: '', - host: '', - port: 0, + username: 'airi-bot', + host: 'localhost', + port: 25565, password: '', version: '1.20', }, + airi: { + wsBaseUrl: 'ws://localhost:6121/ws', + clientName: 'minecraft-bot', + }, } -// Exported configurations -export const botConfig: BotOptions = { ...defaultConfig.bot } -export const openaiConfig: OpenAIConfig = { ...defaultConfig.openai } +// Create a singleton config instance +export const config: Config = { ...defaultConfig } -// Load environment variables into config +// Initialize environment configuration export function initEnv(): void { logger.log('Initializing environment variables') - const config: EnvConfig = { - openai: { - apiKey: env.OPENAI_API_KEY || defaultConfig.openai.apiKey, - baseUrl: env.OPENAI_API_BASEURL || defaultConfig.openai.baseUrl, - model: env.OPENAI_MODEL || defaultConfig.openai.model, - reasoningModel: env.OPENAI_REASONING_MODEL || defaultConfig.openai.reasoningModel, - }, - bot: { - username: env.BOT_USERNAME || defaultConfig.bot.username, - host: env.BOT_HOSTNAME || defaultConfig.bot.host, - port: Number.parseInt(env.BOT_PORT || '49415'), - password: env.BOT_PASSWORD || defaultConfig.bot.password, - version: env.BOT_VERSION || defaultConfig.bot.version, - }, + // Update config with environment variables + config.openai = { + apiKey: getEnvVar('OPENAI_API_KEY', defaultConfig.openai.apiKey), + baseUrl: getEnvVar('OPENAI_API_BASEURL', defaultConfig.openai.baseUrl), + model: getEnvVar('OPENAI_MODEL', defaultConfig.openai.model), + reasoningModel: getEnvVar('OPENAI_REASONING_MODEL', defaultConfig.openai.reasoningModel), } - // Update exported configs - Object.assign(openaiConfig, config.openai) - Object.assign(botConfig, config.bot) + config.bot = { + username: getEnvVar('BOT_USERNAME', defaultConfig.bot.username as string), + host: getEnvVar('BOT_HOSTNAME', defaultConfig.bot.host as string), + port: getEnvNumber('BOT_PORT', defaultConfig.bot.port as number), + password: getEnvVar('BOT_PASSWORD', defaultConfig.bot.password as string), + version: getEnvVar('BOT_VERSION', defaultConfig.bot.version as string), + } - logger.withFields({ openaiConfig }).log('Environment variables initialized') + config.airi = { + wsBaseUrl: getEnvVar('AIRI_WS_BASEURL', defaultConfig.airi.wsBaseUrl), + clientName: getEnvVar('AIRI_CLIENT_NAME', defaultConfig.airi.clientName), + } + + logger.withFields({ config }).log('Environment variables initialized') } diff --git a/services/minecraft/src/composables/neuri.ts b/services/minecraft/src/composables/neuri.ts index 08ee32b6d..1a00f7098 100644 --- a/services/minecraft/src/composables/neuri.ts +++ b/services/minecraft/src/composables/neuri.ts @@ -7,7 +7,7 @@ import { neuri } from 'neuri' import { createActionNeuriAgent } from '../agents/action/adapter' import { createChatNeuriAgent } from '../agents/chat/llm' import { createPlanningNeuriAgent } from '../agents/planning/adapter' -import { openaiConfig } from './config' +import { config } from './config' let neuriAgent: Neuri | undefined const agents = new Set>() @@ -26,8 +26,8 @@ export async function createNeuriAgent(mineflayer: Mineflayer): Promise { neuriAgent = await n.build({ provider: { - apiKey: openaiConfig.apiKey, - baseURL: openaiConfig.baseUrl, + apiKey: config.openai.apiKey, + baseURL: config.openai.baseUrl, }, }) diff --git a/services/minecraft/src/libs/llm-agent/completion.ts b/services/minecraft/src/libs/llm-agent/completion.ts index 084055b39..dbb5a2c32 100644 --- a/services/minecraft/src/libs/llm-agent/completion.ts +++ b/services/minecraft/src/libs/llm-agent/completion.ts @@ -5,13 +5,13 @@ import type { MineflayerWithAgents } from './types' import { assistant } from 'neuri/openai' -import { openaiConfig } from '../../composables/config' +import { config } from '../../composables/config' export async function handleLLMCompletion(context: NeuriContext, bot: MineflayerWithAgents, logger: ReturnType): Promise { logger.log('rerouting...') const completion = await context.reroute('action', context.messages, { - model: openaiConfig.model, + model: config.openai.model, }) as ChatCompletion | { error: { message: string } } & ChatCompletion if (!completion || 'error' in completion) { diff --git a/services/minecraft/src/libs/llm-agent/handler.ts b/services/minecraft/src/libs/llm-agent/handler.ts index 7e8df465b..5c57cd121 100644 --- a/services/minecraft/src/libs/llm-agent/handler.ts +++ b/services/minecraft/src/libs/llm-agent/handler.ts @@ -4,7 +4,7 @@ import type { LLMConfig, LLMResponse } from './types' import { useLogg } from '@guiiai/logg' -import { openaiConfig } from '../../composables/config' +import { config } from '../../composables/config' import { toRetriable } from '../../utils/helper' export abstract class BaseLLMHandler { @@ -18,7 +18,7 @@ export abstract class BaseLLMHandler { messages: Message[], ): Promise { const completion = await context.reroute(route, messages, { - model: this.config.model ?? openaiConfig.model, + model: this.config.model ?? config.openai.model, }) as ChatCompletion | ChatCompletion & { error: { message: string } } if (!completion || 'error' in completion) { diff --git a/services/minecraft/src/libs/llm-agent/index.ts b/services/minecraft/src/libs/llm-agent/index.ts index 0d178a52f..a8b690568 100644 --- a/services/minecraft/src/libs/llm-agent/index.ts +++ b/services/minecraft/src/libs/llm-agent/index.ts @@ -4,7 +4,7 @@ import type { LLMAgentOptions, MineflayerWithAgents } from './types' import { useLogg } from '@guiiai/logg' import { system } from 'neuri/openai' -import { openaiConfig } from '../../composables/config' +import { config } from '../../composables/config' import { ChatMessageHandler } from '../mineflayer' import { handleChatMessage } from './chat' import { createAgentContainer } from './container' @@ -19,7 +19,7 @@ export function LLMAgent(options: LLMAgentOptions): MineflayerPlugin { // Create container and get required services const container = createAgentContainer({ neuri: options.agent, - model: openaiConfig.model, + model: config.openai.model, }) const actionAgent = container.resolve('actionAgent') diff --git a/services/minecraft/src/main.ts b/services/minecraft/src/main.ts index 7afe316df..a912d13ea 100644 --- a/services/minecraft/src/main.ts +++ b/services/minecraft/src/main.ts @@ -9,7 +9,7 @@ import { plugin as MineflayerPVP } from 'mineflayer-pvp' import { plugin as MineflayerTool } from 'mineflayer-tool' import { initBot } from './composables/bot' -import { botConfig, initEnv } from './composables/config' +import { config, initEnv } from './composables/config' import { createNeuriAgent } from './composables/neuri' import { LLMAgent } from './libs/llm-agent' import { wrapPlugin } from './libs/mineflayer' @@ -22,7 +22,7 @@ async function main() { initEnv() const { bot } = await initBot({ - botConfig, + botConfig: config.bot, plugins: [ wrapPlugin(MineflayerArmorManager), wrapPlugin(MineflayerAutoEat), @@ -33,7 +33,11 @@ async function main() { ], }) - const airiClient = new Client({ name: 'minecraft-bot', url: 'ws://localhost:6121/ws' }) + // Connect airi server + const airiClient = new Client({ + name: config.airi.clientName, + url: config.airi.wsBaseUrl, + }) // Dynamically load LLMAgent after the bot is initialized const agent = await createNeuriAgent(bot)