fix: useSkillContext

This commit is contained in:
RainbowBird
2025-01-08 22:35:14 +08:00
parent a811ce41ee
commit dfd888b4b4
8 changed files with 89 additions and 46 deletions
@@ -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'
+17 -18
View File
@@ -6,7 +6,7 @@ import * as skills from '../skills'
type ActionResult = string | Promise<string>
interface Action {
export interface Action {
readonly name: string
readonly description: string
readonly schema: z.ZodObject<any>
@@ -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 {
+2 -2
View File
@@ -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<Agent> {
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 },
)
@@ -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')
+3 -1
View File
@@ -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: {
+1 -1
View File
@@ -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)
+15 -1
View File
@@ -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
*/
+49 -22
View File
@@ -110,41 +110,69 @@ export async function followPlayer(
username: string,
distance = 4,
): Promise<boolean> {
// 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<boolean> {
const start = Date.now()
const targetTime = seconds === -1 ? Infinity : start + seconds * 1000