Skip to content

Commit a44dba3

Browse files
committed
Merge branch 'develop' into pr/756
2 parents 4f07e90 + 8acbd90 commit a44dba3

15 files changed

Lines changed: 249 additions & 39 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,14 @@ Bot profiles are json files (such as `andy.json`) that define:
168168

169169
## Model Specifications
170170

171-
LLM models can be specified simply as `"model": "gpt-4o"`, or more specifically with `"{api}/{model}"`, like `"openrouter/google/gemini-2.5-pro"`. See all supported APIs [here](#model-customization).
171+
LLM models can be specified simply as `"model": "gpt-5.4"`, or more specifically with `"{api}/{model}"`, like `"openrouter/google/gemini-2.5-pro"`. See all supported APIs [here](#model-customization).
172172

173173
The `model` field can be a string or an object. A model object must specify an `api`, and optionally a `model`, `url`, and additional `params`. You can also use different models/providers for chatting, coding, vision, embedding, and voice synthesis. See the example below.
174174

175175
```json
176176
"model": {
177177
"api": "openai",
178-
"model": "gpt-4o",
178+
"model": "gpt-5.4",
179179
"url": "https://api.openai.com/v1/",
180180
"params": {
181181
"max_tokens": 1000,
@@ -184,18 +184,18 @@ The `model` field can be a string or an object. A model object must specify an `
184184
},
185185
"code_model": {
186186
"api": "openai",
187-
"model": "gpt-4",
187+
"model": "gpt-5.4-mini",
188188
"url": "https://api.openai.com/v1/"
189189
},
190190
"vision_model": {
191191
"api": "openai",
192-
"model": "gpt-4o",
192+
"model": "gpt-5.4",
193193
"url": "https://api.openai.com/v1/"
194194
},
195195
"embedding": {
196196
"api": "openai",
197197
"url": "https://api.openai.com/v1/",
198-
"model": "text-embedding-ada-002"
198+
"model": "text-embedding-3-small"
199199
},
200200
"speak_model": "openai/tts-1/echo"
201201
```

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
"dependencies": {
55
"@anthropic-ai/sdk": "^0.17.1",
66
"@cerebras/cerebras_cloud_sdk": "^1.46.0",
7+
"@eslint/js": "^9.13.0",
78
"@google/genai": "^1.15.0",
89
"@huggingface/inference": "^2.8.1",
910
"@mistralai/mistralai": "^1.1.0",
1011
"canvas": "^3.1.0",
1112
"cheerio": "^1.0.0",
13+
"eslint": "^9.13.0",
14+
"eslint-plugin-no-floating-promise": "^2.0.0",
1215
"express": "^4.18.2",
16+
"globals": "^15.11.0",
1317
"google-translate-api-x": "^10.7.1",
1418
"groq-sdk": "^0.15.0",
1519
"minecraft-data": "^3.97.0",
20+
"minecraft-assets": "^1.16.0",
1621
"mineflayer": "^4.33.0",
1722
"mineflayer-armor-manager": "^2.0.1",
1823
"mineflayer-auto-eat": "^3.3.6",
@@ -43,10 +48,6 @@
4348
"clean:modules": "node -e \"const fs=require('fs');const p=require('path');['node_modules','package-lock.json'].forEach(f=>{if(fs.existsSync(f)){if(fs.lstatSync(f).isDirectory()){fs.rmSync(f,{recursive:true,force:true});}else{fs.unlinkSync(f);}}});\""
4449
},
4550
"devDependencies": {
46-
"@eslint/js": "^9.13.0",
47-
"eslint": "^9.13.0",
48-
"eslint-plugin-no-floating-promise": "^2.0.0",
49-
"globals": "^15.11.0",
5051
"patch-package": "^8.0.0"
5152
}
5253
}

profiles/claude_thinker.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "claude_thinker",
33

44
"model": {
5-
"model": "claude-sonnet-4-20250514",
5+
"model": "claude-sonnet-4-6",
66
"params": {
77
"thinking": {
88
"type": "enabled",

profiles/gemini.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "gemini",
33

4-
"model": "gemini-3-flash-preview",
4+
"model": "gemini-flash-latest",
55

66
"speak_model": "google/gemini-2.5-flash-preview-tts/Kore",
77

settings.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ const settings = {
5757
"block_place_delay": 0, // delay between placing blocks (ms) if using newAction. helps avoid bot being kicked by anti-cheat mechanisms on servers.
5858

5959
"log_all_prompts": false, // log ALL prompts to file
60-
61-
}
60+
};
6261

6362
export default settings;

src/agent/coder.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { writeFile, readFile, mkdirSync } from 'fs';
2+
import path from 'path';
3+
import { fileURLToPath } from 'url';
24
import { makeCompartment, lockdown } from './library/lockdown.js';
35
import * as skills from './library/skills.js';
46
import * as world from './library/world.js';
57
import { Vec3 } from 'vec3';
68
import {ESLint} from "eslint";
79

10+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
11+
812
export class Coder {
913
constructor(agent) {
1014
this.agent = agent;
@@ -13,11 +17,11 @@ export class Coder {
1317
this.code_template = '';
1418
this.code_lint_template = '';
1519

16-
readFile('./bots/execTemplate.js', 'utf8', (err, data) => {
20+
readFile(path.join(__dirname, '../../bots/execTemplate.js'), 'utf8', (err, data) => {
1721
if (err) throw err;
1822
this.code_template = data;
1923
});
20-
readFile('./bots/lintTemplate.js', 'utf8', (err, data) => {
24+
readFile(path.join(__dirname, '../../bots/lintTemplate.js'), 'utf8', (err, data) => {
2125
if (err) throw err;
2226
this.code_lint_template = data;
2327
});

src/agent/library/skills.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ async function equipHighestAttack(bot) {
2727
weapons = bot.inventory.items().filter(item => item.name.includes('pickaxe') || item.name.includes('shovel'));
2828
if (weapons.length === 0)
2929
return;
30-
weapons.sort((a, b) => a.attackDamage < b.attackDamage);
30+
weapons.sort((a, b) => b.attackDamage - a.attackDamage);
3131
let weapon = weapons[0];
3232
if (weapon)
3333
await bot.equip(weapon, 'hand');

src/mindcraft/mindserver.js

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,65 @@ export function createMindServer(host_public = false, port = 8080) {
5454
const __dirname = path.dirname(fileURLToPath(import.meta.url));
5555
app.use(express.static(path.join(__dirname, 'public')));
5656

57+
// Texture proxy: resolve item/block textures using minecraft-assets with version fallback
58+
app.get('/assets/item/:agent/:name.png', async (req, res) => {
59+
try {
60+
const agentName = req.params.agent;
61+
const rawName = req.params.name;
62+
const itemName = String(rawName).toLowerCase();
63+
const conn = agent_connections[agentName];
64+
const preferred = conn?.settings?.minecraft_version;
65+
const candidates = [];
66+
if (preferred && preferred !== 'auto') candidates.push(preferred);
67+
candidates.push('1.21.8');
68+
69+
// Lazy import to avoid ESM/CJS conflicts
70+
const mod = await import('minecraft-assets');
71+
const mcAssetsFactory = mod.default || mod;
72+
73+
for (const ver of candidates) {
74+
try {
75+
const assets = mcAssetsFactory(ver);
76+
// Prefer items path first, then blocks
77+
const item = assets.items[itemName];
78+
const block = assets.blocks[itemName];
79+
const tex = assets.textureContent?.[itemName]?.texture
80+
|| (item ? assets.textureContent?.[itemName]?.texture : null)
81+
|| (block ? assets.textureContent?.[itemName]?.texture : null);
82+
if (tex) {
83+
// textureContent already provides a data URL in many versions
84+
if (tex.startsWith('data:image')) {
85+
const base64 = tex.split(',')[1];
86+
const img = globalThis.Buffer.from(base64, 'base64');
87+
res.setHeader('Content-Type', 'image/png');
88+
return res.end(img);
89+
}
90+
}
91+
// If textureContent missing, try static path resolution inside package
92+
// Helps with some strange blocks like Leaf Litter
93+
const guessPaths = [];
94+
const base = assets.directory;
95+
guessPaths.push(path.join(base, 'items', `${itemName}.png`));
96+
guessPaths.push(path.join(base, 'blocks', `${itemName}.png`));
97+
for (const p of guessPaths) {
98+
try {
99+
const fsMod = await import('fs');
100+
const buf = fsMod.readFileSync(p);
101+
res.setHeader('Content-Type', 'image/png');
102+
return res.end(buf);
103+
} catch { /* ignore */ }
104+
}
105+
} catch { /* ignore */ }
106+
}
107+
// Not found, fallback svg
108+
res.setHeader('Content-Type', 'image/svg+xml');
109+
res.status(404).send('<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><rect width="100%" height="100%" fill="#444"/><text x="50%" y="55%" font-size="12" fill="#bbb" text-anchor="middle">?</text></svg>');
110+
} catch (e) {
111+
res.setHeader('Content-Type', 'image/svg+xml');
112+
res.status(500).send('<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><rect width="100%" height="100%" fill="#444"/><text x="50%" y="55%" font-size="12" fill="#bbb" text-anchor="middle">!</text></svg>');
113+
}
114+
});
115+
57116
// Socket.io connection handling
58117
io.on('connection', (socket) => {
59118
let curAgentName = null;
@@ -191,18 +250,18 @@ export function createMindServer(host_public = false, port = 8080) {
191250
// wait 2 seconds
192251
setTimeout(() => {
193252
console.log('Exiting MindServer');
194-
process.exit(0);
253+
globalThis.process.exit(0);
195254
}, 2000);
196255

197256
});
198257

199258
socket.on('send-message', (agentName, data) => {
200259
if (!agent_connections[agentName]) {
201260
console.warn(`Agent ${agentName} not in game, cannot send message via MindServer.`);
202-
return
261+
return;
203262
}
204263
try {
205-
agent_connections[agentName].socket.emit('send-message', data)
264+
agent_connections[agentName].socket.emit('send-message', data);
206265
} catch (error) {
207266
console.error('Error: ', error);
208267
}

0 commit comments

Comments
 (0)