From dfd888b4b44be13d7db603be976589bbb081f6f7 Mon Sep 17 00:00:00 2001 From: RainbowBird Date: Wed, 8 Jan 2025 22:35:14 +0800 Subject: [PATCH] fix: useSkillContext --- services/minecraft/src/agents/actions.test.ts | 2 +- services/minecraft/src/agents/actions.ts | 35 +++++---- services/minecraft/src/agents/openai.ts | 4 +- services/minecraft/src/components/aichat.ts | 1 + services/minecraft/src/composables/bot.ts | 4 +- services/minecraft/src/main.ts | 2 +- services/minecraft/src/skills/base.ts | 16 ++++- services/minecraft/src/skills/movement.ts | 71 +++++++++++++------ 8 files changed, 89 insertions(+), 46 deletions(-) diff --git a/services/minecraft/src/agents/actions.test.ts b/services/minecraft/src/agents/actions.test.ts index 350ab6386..fea5b5da2 100644 --- a/services/minecraft/src/agents/actions.test.ts +++ b/services/minecraft/src/agents/actions.test.ts @@ -1,9 +1,9 @@ import { messages, system, user } from 'neuri/openai' -import { sleep } from 'src/utils/helper' import { beforeAll, describe, expect, it } from 'vitest' import { createBot, useBot } from '../composables/bot' import { botConfig, initEnv } from '../composables/config' import { genActionAgentPrompt, genQueryAgentPrompt } from '../prompts/agent' +import { sleep } from '../utils/helper' import { initLogger } from '../utils/logger' import { initAgent } from './openai' diff --git a/services/minecraft/src/agents/actions.ts b/services/minecraft/src/agents/actions.ts index a9a9d51b5..74324c1c2 100644 --- a/services/minecraft/src/agents/actions.ts +++ b/services/minecraft/src/agents/actions.ts @@ -6,7 +6,7 @@ import * as skills from '../skills' type ActionResult = string | Promise -interface Action { +export interface Action { readonly name: string readonly description: string readonly schema: z.ZodObject @@ -105,23 +105,22 @@ export const actionsList: Action[] = [ // } // }, - // getStopAction(): Action { - // return { - // name: 'stop', - // description: 'Force stop all actions and commands that are currently executing.', - // schema: z.object({}), - // perform: (ctx: BotContext) => async () => { - // await ctx.actions.stop() - // ctx.clearBotLogs() - // ctx.actions.cancelResume() - // ctx.bot.emit('idle') - // let msg = 'Agent stopped.' - // if (ctx.self_prompter.on) - // msg += ' Self-prompting still active.' - // return msg - // }, - // } - // }, + { + name: 'stop', + description: 'Force stop all actions and commands that are currently executing.', + schema: z.object({}), + perform: (ctx: SkillContext) => async () => { + // await ctx.actions.stop() + // ctx.clearBotLogs() + // ctx.actions.cancelResume() + // ctx.bot.emit('idle') + ctx.shouldInterrupt = true + const msg = 'Agent stopped.' + // if (ctx.self_prompter.on) + // msg += ' Self-prompting still active.' + return msg + }, + }, // getStfuAction(): Action { // return { diff --git a/services/minecraft/src/agents/openai.ts b/services/minecraft/src/agents/openai.ts index 7efc10168..b94623317 100644 --- a/services/minecraft/src/agents/openai.ts +++ b/services/minecraft/src/agents/openai.ts @@ -3,7 +3,7 @@ import type { BotContext } from '../composables/bot' import { useLogg } from '@guiiai/logg' import { agent, neuri } from 'neuri' import { openaiConfig } from '../composables/config' -import { createSkillContext } from '../skills' +import { useSkillContext } from '../skills' import { actionsList } from './actions' let neuriAgent: Neuri | undefined @@ -47,7 +47,7 @@ export async function initActionAgent(ctx: BotContext): Promise { async ({ parameters }) => { logger.withFields({ name: action.name, parameters }).log('Calling action') ctx.memory.actions.push(action) - return action.perform(createSkillContext(ctx))(...Object.values(parameters)) + return action.perform(useSkillContext(ctx))(...Object.values(parameters)) }, { description: action.description }, ) diff --git a/services/minecraft/src/components/aichat.ts b/services/minecraft/src/components/aichat.ts index 5463db2bb..7f6aef685 100644 --- a/services/minecraft/src/components/aichat.ts +++ b/services/minecraft/src/components/aichat.ts @@ -11,6 +11,7 @@ export function createAiChatComponent(ctx: BotContext): ComponentLifecycle { ctx.memory.chatHistory.push(system(genActionAgentPrompt(ctx))) + // todo: get system message const onChat = formBotChat(ctx, async (username, message) => { logger.withFields({ username, message }).log('Chat message received') diff --git a/services/minecraft/src/composables/bot.ts b/services/minecraft/src/composables/bot.ts index aca5dbcc9..f2e4a0128 100644 --- a/services/minecraft/src/composables/bot.ts +++ b/services/minecraft/src/composables/bot.ts @@ -1,5 +1,5 @@ import type { Message } from 'neuri/openai' -import type { Action } from 'src/agents/actions' +import type { Action } from '../agents/actions' import type { BotInternalEventHandlers, BotInternalEvents } from './events' import { useLogg } from '@guiiai/logg' import mineflayer, { type Bot, type BotOptions } from 'mineflayer' @@ -51,6 +51,7 @@ export interface ComponentLifecycle { cleanup: () => void } +// todo: reconnect export function createBot(options: BotOptions): Bot { logger.withFields({ options }).log('Creating bot') ctx = { @@ -68,6 +69,7 @@ export function createBot(options: BotOptions): Bot { }, memory: { chatHistory: [], + actions: [], }, status: new Map(), health: { diff --git a/services/minecraft/src/main.ts b/services/minecraft/src/main.ts index 909bc1249..90695593b 100644 --- a/services/minecraft/src/main.ts +++ b/services/minecraft/src/main.ts @@ -16,7 +16,7 @@ import { createTicker } from './utils/ticker' const logger = useLogg('main').useGlobalConfig() async function main() { - initLogger() + initLogger() // todo: save logs to file initEnv() createBot(botConfig) diff --git a/services/minecraft/src/skills/base.ts b/services/minecraft/src/skills/base.ts index e10c69e82..8bbcdd9bb 100644 --- a/services/minecraft/src/skills/base.ts +++ b/services/minecraft/src/skills/base.ts @@ -1,5 +1,19 @@ import type { Bot } from 'mineflayer' -import type { BotContext } from 'src/composables/bot' +import type { BotContext } from '../composables/bot' +import { useLogg } from '@guiiai/logg' + +let ctx: SkillContext | undefined +const logger = useLogg('skills').useGlobalConfig() + +export function useSkillContext(botCtx: BotContext): SkillContext { + if (!ctx) { + logger.log('Creating skill context') + ctx = createSkillContext(botCtx) + } + + return ctx +} + /** * Context for skill execution */ diff --git a/services/minecraft/src/skills/movement.ts b/services/minecraft/src/skills/movement.ts index 1dcac8974..115d054aa 100644 --- a/services/minecraft/src/skills/movement.ts +++ b/services/minecraft/src/skills/movement.ts @@ -110,41 +110,69 @@ export async function followPlayer( username: string, distance = 4, ): Promise { + // const player = ctx.bot.players[username]?.entity + // if (!player) { + // log(ctx, `Could not find player ${username}`) + // return false + // } + + // const movements = new Movements(ctx.bot) + // ctx.bot.pathfinder.setMovements(movements) + // ctx.bot.pathfinder.setGoal(new goals.GoalNear(player.position.x, player.position.y, player.position.z, distance)) + + // log(ctx, `Started following ${username}`) + + // const followInterval = setInterval(() => { + // const target = ctx.bot.players[username]?.entity + // if (!target) { + // log(ctx, 'Lost sight of player') + // clearInterval(followInterval) + // return + // } + + // const { x, y, z } = target.position + // ctx.bot.pathfinder.setGoal(new goals.GoalNear(x, y, z, distance)) + // }, 1000) + + // while (!ctx.shouldInterrupt) { + // await new Promise(resolve => setTimeout(resolve, 500)) + + // if (ctx.allowCheats && ctx.bot.entity.position.distanceTo(player.position) > 100) { + // await goToPlayer(ctx, username) + // } + // } + + // // TODO: need global status management + // clearInterval(followInterval) + // ctx.bot.pathfinder.stop() + // return true + const player = ctx.bot.players[username]?.entity if (!player) { - log(ctx, `Could not find player ${username}`) return false } const movements = new Movements(ctx.bot) ctx.bot.pathfinder.setMovements(movements) - ctx.bot.pathfinder.setGoal(new goals.GoalNear(player.position.x, player.position.y, player.position.z, distance)) - - log(ctx, `Started following ${username}`) - - const followInterval = setInterval(() => { - const target = ctx.bot.players[username]?.entity - if (!target) { - log(ctx, 'Lost sight of player') - clearInterval(followInterval) - return - } - - const { x, y, z } = target.position - ctx.bot.pathfinder.setGoal(new goals.GoalNear(x, y, z, distance)) - }, 1000) + ctx.bot.pathfinder.setGoal(new goals.GoalFollow(player, distance), true) + log(ctx, `You are now actively following player ${username}.`) while (!ctx.shouldInterrupt) { await new Promise(resolve => setTimeout(resolve, 500)) - if (ctx.allowCheats && ctx.bot.entity.position.distanceTo(player.position) > 100) { + if (ctx.allowCheats && ctx.bot.entity.position.distanceTo(player.position) > 100 && player.onGround) { await goToPlayer(ctx, username) } - } - // TODO: need global status management - // clearInterval(followInterval) - // ctx.bot.pathfinder.stop() + // if (ctx.bot.modes?.isOn('unstuck')) { + // const isNearby = ctx.bot.entity.position.distanceTo(player.position) <= distance + 1 + // if (isNearby) { + // ctx.bot.modes.pause('unstuck') + // } else { + // ctx.bot.modes.unpause('unstuck') + // } + // } + } return true } @@ -184,7 +212,6 @@ export async function moveAwayFromEntity( return true } - export async function stay(ctx: SkillContext, seconds = 30): Promise { const start = Date.now() const targetTime = seconds === -1 ? Infinity : start + seconds * 1000