feat(minecraft): add giveUp tool with cooldown suppression

This commit is contained in:
Rin
2026-02-18 11:14:37 +08:00
committed by Neko Ayaka
parent b02d4a9b8b
commit e69e6608b8
3 changed files with 55 additions and 0 deletions
@@ -37,6 +37,16 @@ export const actionsList: Action[] = [
return `Sent message: "${message}"`
},
},
{
name: 'giveUp',
description: 'Admit you are currently stuck and pause autonomous retries for a cooldown window.',
execution: 'sync',
schema: z.object({
reason: z.string().min(1).describe('Short explanation of why you are stuck.'),
cooldown_seconds: z.number().int().min(10).max(600).default(45).describe('How long to pause retries before re-evaluating.'),
}),
perform: () => (reason: string, cooldown_seconds: number): string => `Gave up for ${cooldown_seconds}s: ${reason}`,
},
// {\n // name: 'setReflexMode',
// description: 'Set (or clear) your reflex mode override. Use work/wander to disable idle-only reflex behaviors. Set override to null to return to automatic mode selection.',
// execution: 'sequential',
@@ -44,6 +44,8 @@ export class Brain {
private queue: QueuedEvent[] = []
private isProcessing = false
private currentCancellationToken: CancellationToken | undefined
private giveUpUntil = 0
private giveUpReason: string | undefined
private lastContextView: string | undefined
private conversationHistory: Message[] = []
@@ -68,6 +70,13 @@ export class Brain {
this.deps.taskExecutor.on('action:completed', async ({ action, result }) => {
this.deps.logger.log('INFO', `Brain: Action completed: ${action.tool}`)
if (action.tool === 'giveUp') {
const secondsRaw = Number(action.params?.cooldown_seconds ?? 45)
const cooldownSeconds = Number.isFinite(secondsRaw) ? Math.min(600, Math.max(10, Math.floor(secondsRaw))) : 45
this.giveUpUntil = Date.now() + cooldownSeconds * 1000
this.giveUpReason = typeof action.params?.reason === 'string' ? action.params.reason : undefined
}
this.enqueueEvent(bot, {
type: 'feedback',
payload: { status: 'success', action, result },
@@ -139,6 +148,10 @@ export class Brain {
// --- Cognitive Cycle ---
private async processEvent(bot: MineflayerWithAgents, event: BotEvent): Promise<void> {
this.resumeFromGiveUpIfNeeded(event)
if (this.shouldSuppressDuringGiveUp(event))
return
// 0. Build Context View
const snapshot = this.deps.reflexManager.getContextSnapshot()
const view = buildConsciousContextView(snapshot)
@@ -314,8 +327,39 @@ export class Brain {
// Note: We don't update this.lastContextView here; caller does it after building message
}
if (this.giveUpUntil > Date.now()) {
const remainingSec = Math.max(0, Math.ceil((this.giveUpUntil - Date.now()) / 1000))
parts.push(`[STATE] giveUp active (${remainingSec}s left). reason=${this.giveUpReason ?? 'unknown'}`)
}
parts.push('[RUNTIME] Globals are refreshed every turn: snapshot, self, environment, social, threat, attention, event, now, mem, lastRun, lastAction.')
return parts.join('\n\n')
}
private shouldSuppressDuringGiveUp(event: BotEvent): boolean {
if (Date.now() >= this.giveUpUntil)
return false
if (event.type !== 'perception')
return true
const signal = event.payload as PerceptionSignal
return signal.type !== 'chat_message'
}
private resumeFromGiveUpIfNeeded(event: BotEvent): void {
if (Date.now() >= this.giveUpUntil)
return
if (event.type !== 'perception')
return
const signal = event.payload as PerceptionSignal
if (signal.type !== 'chat_message')
return
this.giveUpUntil = 0
this.giveUpReason = undefined
}
}
@@ -109,6 +109,7 @@ Examples:
- Treat action results as potentially unreliable; check outcomes against \`snapshot\`/feedback before committing to the next step.
- Prefer deterministic scripts: no random branching unless needed.
- Keep per-turn scripts short and focused on one tactical objective.
- If you hit repeated failures with no progress, call \`await giveUp({ reason, cooldown_seconds })\` once instead of retry-spamming.
# Rules
- **Native Reasoning**: You can think before outputting your action.