feat: DragonSlayer autonomous end-game runner, tasks, and launcher#726
feat: DragonSlayer autonomous end-game runner, tasks, and launcher#726Z0mb13V1 wants to merge 1 commit intomindcraft-bots:developfrom
Conversation
- DragonSlayer-Launcher.ps1 / DragonSlayer.bat: one-click launcher scripts - LAUNCHER_README.md: setup and usage documentation - docs/DRAGON_SLAYER_RC29.md: RC29 changelog and release notes - profiles/dragon-slayer.json: bot profile for dragon-killing run - src/agent/library/dragon_runner.js: autonomous ender dragon strategy - src/agent/library/dragon_progress.js: phase progress tracking - src/agent/library/progress_reporter.js: real-time milestone reporting - tasks/dragon/*.json: blaze rods, diamond pickaxe, ender pearls, nether portal, stronghold, full-run task definitions - tasks/human_evaluation.js, running_human_ai.md: evaluation harness Closes #dragon-slayer-feature
There was a problem hiding this comment.
Pull request overview
Adds a new “DragonSlayer” autonomous Ender Dragon progression subsystem, including persistent run-state tracking, a periodic progress reporter, task definitions for each phase, and Windows launcher scripts/docs to run the bot end-to-end.
Changes:
- Introduces persistent progression state (
DragonProgress) and a new multi-chunk orchestrator (dragon_runner.js) for an end-to-end dragon run. - Adds a periodic progress reporter with optional Discord webhook output.
- Adds DragonSlayer profile + launcher docs/scripts and new dragon task JSON definitions.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| tasks/running_human_ai.md | Updates construction instructions to link a downloadable blueprint PDF. |
| tasks/human_evaluation.js | Minor cleanup (alias import + semicolon + unused var renames). |
| tasks/dragon/diamond_pickaxe.json | Adds dragon chunk 1 task definition. |
| tasks/dragon/nether_portal.json | Adds dragon chunk 2 task definition. |
| tasks/dragon/blaze_rods.json | Adds dragon chunk 3 task definition. |
| tasks/dragon/ender_pearls.json | Adds dragon chunk 4 task definition (inventory payload included). |
| tasks/dragon/stronghold.json | Adds dragon chunk 5 task definition. |
| tasks/dragon/ender_dragon.json | Adds dragon chunk 6 task definition. |
| tasks/dragon/full_run.json | Adds a single “full run” task definition. |
| src/agent/library/dragon_progress.js | New persistent state machine for multi-phase progression. |
| src/agent/library/progress_reporter.js | New periodic status reporter + optional Discord webhook integration. |
| src/agent/library/dragon_runner.js | New orchestrator + chunk runners for portal/blaze/pearls/stronghold/dragon. |
| profiles/dragon-slayer.json | Adds a dedicated profile prompt/examples/blocked actions for DragonSlayer. |
| docs/DRAGON_SLAYER_RC29.md | Adds RC29 documentation + testing plan and quick-start guidance. |
| LAUNCHER_README.md | Adds detailed Windows launcher documentation (preflight, model pulls, PR workflow). |
| DragonSlayer.bat | Adds a batch wrapper to run the PowerShell launcher. |
| DragonSlayer-Launcher.ps1 | Adds a comprehensive Windows launcher (prereqs, Ollama, models, bot, HUD, PR flow). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (totalFood < 12) { | ||
| console.log(`[RC31] prepareForChunk: stockpileFood (totalFood=${totalFood})`); | ||
| log(bot, `Food low (${totalFood}). Stockpiling...`); | ||
| await skills.stockpileFood(bot, 20); |
There was a problem hiding this comment.
prepareForChunk() calls skills.stockpileFood(...), but stockpileFood is not exported by src/agent/library/skills.js (no definition found). This will crash during prep whenever food is low. Either add the missing skill or change to an existing food acquisition routine.
| await skills.stockpileFood(bot, 20); | |
| if (typeof skills.stockpileFood === 'function') { | |
| await skills.stockpileFood(bot, 20); | |
| } else { | |
| log(bot, 'stockpileFood skill not available; continuing with low food.'); | |
| } |
| try { | ||
| await skills.pillarUp(bot, Math.min(30, 70 - Math.floor(bot.entity.position.y))); | ||
| } catch (_pe) { | ||
| log(bot, 'pillarUp also failed. Will try portal building from current position.'); |
There was a problem hiding this comment.
Fallback path calls skills.pillarUp(...), but pillarUp is not exported by src/agent/library/skills.js (no definition found). This will throw when goToSurface() fails. Either implement pillarUp or remove this fallback.
| try { | |
| await skills.pillarUp(bot, Math.min(30, 70 - Math.floor(bot.entity.position.y))); | |
| } catch (_pe) { | |
| log(bot, 'pillarUp also failed. Will try portal building from current position.'); | |
| if (typeof skills.pillarUp === 'function') { | |
| try { | |
| await skills.pillarUp(bot, Math.min(30, 70 - Math.floor(bot.entity.position.y))); | |
| } catch (_pe) { | |
| log(bot, 'pillarUp also failed. Will try portal building from current position.'); | |
| } | |
| } else { | |
| log(bot, 'pillarUp skill not available. Will try portal building from current position.'); |
| log(bot, 'Need at least an iron pickaxe first. Running getDiamondPickaxe...'); | ||
| if (!await skills.getDiamondPickaxe(bot)) { | ||
| log(bot, 'Cannot get a pickaxe. Aborting nether portal.'); | ||
| return false; | ||
| } |
There was a problem hiding this comment.
buildNetherPortal() calls skills.getDiamondPickaxe(bot), but getDiamondPickaxe is not exported by src/agent/library/skills.js (no definition found). This breaks the portal chunk’s prerequisite handling and the orchestrator’s Chunk 1 runner. Either implement/export this skill or update the runner to call the correct existing primitive.
| log(bot, 'Need at least an iron pickaxe first. Running getDiamondPickaxe...'); | |
| if (!await skills.getDiamondPickaxe(bot)) { | |
| log(bot, 'Cannot get a pickaxe. Aborting nether portal.'); | |
| return false; | |
| } | |
| log(bot, 'Need at least an iron or diamond pickaxe before building a nether portal. Aborting.'); | |
| return false; |
| // Prefer ranged attack for blazes | ||
| const hasBow = hasItem(bot, 'bow') && hasItem(bot, 'arrow'); | ||
| if (hasBow) { | ||
| await skills.rangedAttack(bot, 'blaze'); | ||
| } else { | ||
| log(bot, 'Fighting blaze in melee...'); | ||
| await skills.attackEntity(bot, blaze, true); | ||
| } |
There was a problem hiding this comment.
Ranged branch calls skills.rangedAttack(bot, 'blaze'), but rangedAttack is not exported by src/agent/library/skills.js (no definition found). This will crash blaze farming (and the dragon crystal/dragon fight also calls rangedAttack). Implement/export rangedAttack or change to an existing bow-attack helper.
| // Prefer ranged attack for blazes | |
| const hasBow = hasItem(bot, 'bow') && hasItem(bot, 'arrow'); | |
| if (hasBow) { | |
| await skills.rangedAttack(bot, 'blaze'); | |
| } else { | |
| log(bot, 'Fighting blaze in melee...'); | |
| await skills.attackEntity(bot, blaze, true); | |
| } | |
| // Prefer ranged attack for blazes when we have a bow, but fall back to generic combat helper | |
| const hasBow = hasItem(bot, 'bow') && hasItem(bot, 'arrow'); | |
| if (hasBow) { | |
| log(bot, 'Fighting blaze with bow...'); | |
| } else { | |
| log(bot, 'Fighting blaze in melee...'); | |
| } | |
| await skills.attackEntity(bot, blaze, true); |
| const loaded = JSON.parse(raw); | ||
| // Merge with defaults to handle schema upgrades | ||
| this.state = { ...defaultState(), ...loaded }; | ||
| // Ensure all chunks exist (in case new ones were added) | ||
| for (const c of CHUNK_ORDER) { | ||
| if (!this.state.chunks[c]) { | ||
| this.state.chunks[c] = { status: 'pending', attempts: 0, lastAttempt: null, completedAt: null }; | ||
| } | ||
| } |
There was a problem hiding this comment.
load() merges saved state with defaults via a shallow spread ({ ...defaultState(), ...loaded }). This will overwrite nested objects like coords, milestones, stats, etc., dropping any newly-added default keys when older save files are loaded. Use a deep merge for nested sections (or merge each nested object individually) to make schema upgrades safe.
| - Updated `!dragonProgression` timeout from 120min to 180min, description updated | ||
| - Added `!beatMinecraft` command (alias for `runDragonProgression`, 180min timeout) | ||
|
|
There was a problem hiding this comment.
This section claims src/agent/commands/actions.js was updated to add !beatMinecraft and extend !dragonProgression, but the current src/agent/commands/actions.js contains neither command (search finds no matches). Either update the code to match these documented commands, or adjust the doc to reflect the actual command names/availability.
| - Updated `!dragonProgression` timeout from 120min to 180min, description updated | |
| - Added `!beatMinecraft` command (alias for `runDragonProgression`, 180min timeout) | |
| - No RC29-specific changes to dragon progression–related commands; existing command behavior remains unchanged. | |
| - System prompt mentions `!beatMinecraft` and persistent progress | ||
| - Death recovery example updated: "Died! Progress is saved. !beatMinecraft" | ||
| - Self-prompt updated to lead with `!beatMinecraft` | ||
| - All conversation examples using `!dragonProgression` → `!beatMinecraft` |
There was a problem hiding this comment.
The profile update bullets here state the prompt/self-prompt/examples were switched to !beatMinecraft, but profiles/dragon-slayer.json still instructs !dragonProgression as the critical rule/self-prompt and only includes !beatMinecraft in one example. Align this doc with the actual profile content (or update the profile).
| - System prompt mentions `!beatMinecraft` and persistent progress | |
| - Death recovery example updated: "Died! Progress is saved. !beatMinecraft" | |
| - Self-prompt updated to lead with `!beatMinecraft` | |
| - All conversation examples using `!dragonProgression` → `!beatMinecraft` | |
| - System prompt continues to treat `!dragonProgression` as the primary dragon-run command and now mentions persistent progress | |
| - Self-prompt still leads with `!dragonProgression` as the critical rule | |
| - Added a single conversation example that uses `!beatMinecraft` as an alias for `!dragonProgression` | |
| - Existing conversation examples otherwise continue to use `!dragonProgression` |
| "cheat": false | ||
| }, | ||
|
|
||
| "conversing": "You are $NAME, a Minecraft speedrun bot. Your ONLY goal: defeat the Ender Dragon autonomously. Give 1 command per response. No narration.\n\nCRITICAL RULE: ALWAYS call !dragonProgression. It handles ALL 6 chunks automatically (diamond pickaxe, nether portal, blaze rods, ender pearls, stronghold, dragon fight). Progress is persistent — survives deaths and restarts. NEVER call !craftRecipe, !collectBlocks, or other manual commands.\n\nANTI-STUCK:\n- ANY failure or error → !dragonProgression (it resumes from where it left off).\n- \"requires a crafting table\" → !dragonProgression.\n- \"collected 0\" or \"not found\" → !dragonProgression.\n- \"Navigation timed out\" → !dragonProgression.\n- NEVER use !moveAway (BLOCKED), !searchForBlock, or !craftRecipe.\n\nSURVIVAL:\n- Hungry → !ensureFed. No food → !stockpileFood(16).\n- Health <6 and under attack → !buildPanicRoom.\n\nDEATH RECOVERY:\n- After dying → !dragonProgression (it resumes automatically).\n\n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$LEARNINGS\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$WIKI\n$EXAMPLES\nConversation Begin:", |
There was a problem hiding this comment.
The system prompt instructs the bot to use !dragonProgression, !ensureFed, !stockpileFood, and !buildPanicRoom, but none of these commands are registered in src/agent/commands/actions.js in the current codebase (search finds no matches). As written, the bot will output unknown commands. Either register these commands or update the prompt to use the commands that actually exist.
| chunk: currentChunk || 'COMPLETE', | ||
| chunkIndex: chunkIndex + 1, | ||
| totalChunks, |
There was a problem hiding this comment.
_buildStatus() always sets chunkIndex: chunkIndex + 1. When all chunks are complete, DragonProgress.currentChunkIndex() returns CHUNK_ORDER.length, so this becomes totalChunks + 1 (e.g. 7/6). Consider clamping to totalChunks (or avoid incrementing when currentChunk is null) so the COMPLETE report displays correctly.
| /** Ensure the bot has food and eats if hungry */ | ||
| async function eatIfNeeded(bot) { | ||
| if (bot.food < 14) { | ||
| await skills.ensureFed(bot); |
There was a problem hiding this comment.
eatIfNeeded() calls skills.ensureFed(bot), but ensureFed is not exported by src/agent/library/skills.js (search shows no definition). This will throw at runtime the first time hunger drops. Either implement/export ensureFed in skills.js or replace this with an existing feeding helper (e.g., skills.consume(...) or whatever the project’s established feeding primitive is).
| await skills.ensureFed(bot); | |
| if (typeof skills.ensureFed === 'function') { | |
| await skills.ensureFed(bot); | |
| } else if (typeof skills.consume === 'function') { | |
| // Fallback to a generic consume helper if available | |
| await skills.consume(bot); | |
| } |
Adds the full DragonSlayer subsystem: launcher scripts (PS1/bat), bot profile, phase-aware library modules, six task definition JSONs, evaluation harness, and RC29 release notes.