mindcraft 0.1.4-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FAQ.md +38 -0
- package/LICENSE +21 -0
- package/README.md +255 -0
- package/andy.json +6 -0
- package/bin/mindcraft.js +80 -0
- package/keys.example.json +19 -0
- package/main.js +80 -0
- package/package.json +78 -0
- package/patches/minecraft-data+3.97.0.patch +13 -0
- package/patches/mineflayer+4.33.0.patch +54 -0
- package/patches/mineflayer-pathfinder+2.4.5.patch +265 -0
- package/patches/mineflayer-pvp+1.3.2.patch +13 -0
- package/patches/prismarine-viewer+1.33.0.patch +13 -0
- package/patches/protodef+1.19.0.patch +15 -0
- package/profiles/andy-4-reasoning.json +14 -0
- package/profiles/andy-4.json +7 -0
- package/profiles/azure.json +19 -0
- package/profiles/claude.json +7 -0
- package/profiles/claude_thinker.json +15 -0
- package/profiles/deepseek.json +7 -0
- package/profiles/defaults/_default.json +256 -0
- package/profiles/defaults/assistant.json +14 -0
- package/profiles/defaults/creative.json +14 -0
- package/profiles/defaults/god_mode.json +14 -0
- package/profiles/defaults/survival.json +14 -0
- package/profiles/freeguy.json +7 -0
- package/profiles/gemini.json +9 -0
- package/profiles/gpt.json +12 -0
- package/profiles/grok.json +7 -0
- package/profiles/llama.json +10 -0
- package/profiles/mercury.json +9 -0
- package/profiles/mistral.json +5 -0
- package/profiles/qwen.json +17 -0
- package/profiles/tasks/construction_profile.json +42 -0
- package/profiles/tasks/cooking_profile.json +11 -0
- package/profiles/tasks/crafting_profile.json +71 -0
- package/profiles/vllm.json +10 -0
- package/settings.js +64 -0
- package/src/agent/action_manager.js +177 -0
- package/src/agent/agent.js +561 -0
- package/src/agent/coder.js +229 -0
- package/src/agent/commands/actions.js +504 -0
- package/src/agent/commands/index.js +259 -0
- package/src/agent/commands/queries.js +347 -0
- package/src/agent/connection_handler.js +96 -0
- package/src/agent/conversation.js +353 -0
- package/src/agent/history.js +122 -0
- package/src/agent/library/full_state.js +89 -0
- package/src/agent/library/index.js +23 -0
- package/src/agent/library/lockdown.js +32 -0
- package/src/agent/library/skill_library.js +93 -0
- package/src/agent/library/skills.js +2093 -0
- package/src/agent/library/world.js +431 -0
- package/src/agent/memory_bank.js +25 -0
- package/src/agent/mindserver_proxy.js +136 -0
- package/src/agent/modes.js +446 -0
- package/src/agent/npc/build_goal.js +80 -0
- package/src/agent/npc/construction/dirt_shelter.json +38 -0
- package/src/agent/npc/construction/large_house.json +230 -0
- package/src/agent/npc/construction/small_stone_house.json +42 -0
- package/src/agent/npc/construction/small_wood_house.json +42 -0
- package/src/agent/npc/controller.js +261 -0
- package/src/agent/npc/data.js +50 -0
- package/src/agent/npc/item_goal.js +355 -0
- package/src/agent/npc/utils.js +126 -0
- package/src/agent/self_prompter.js +146 -0
- package/src/agent/settings.js +7 -0
- package/src/agent/speak.js +150 -0
- package/src/agent/tasks/construction_tasks.js +1104 -0
- package/src/agent/tasks/cooking_tasks.js +358 -0
- package/src/agent/tasks/tasks.js +594 -0
- package/src/agent/templates/execTemplate.js +6 -0
- package/src/agent/templates/lintTemplate.js +10 -0
- package/src/agent/vision/browser_viewer.js +8 -0
- package/src/agent/vision/camera.js +78 -0
- package/src/agent/vision/vision_interpreter.js +82 -0
- package/src/mindcraft/index.js +28 -0
- package/src/mindcraft/mcserver.js +154 -0
- package/src/mindcraft/mindcraft.js +111 -0
- package/src/mindcraft/mindserver.js +328 -0
- package/src/mindcraft/public/index.html +1253 -0
- package/src/mindcraft/public/settings_spec.json +145 -0
- package/src/mindcraft/userconfig.js +72 -0
- package/src/mindcraft-py/example.py +27 -0
- package/src/mindcraft-py/init-mindcraft.js +24 -0
- package/src/mindcraft-py/mindcraft.py +99 -0
- package/src/models/_model_map.js +89 -0
- package/src/models/azure.js +32 -0
- package/src/models/cerebras.js +61 -0
- package/src/models/claude.js +87 -0
- package/src/models/deepseek.js +59 -0
- package/src/models/gemini.js +176 -0
- package/src/models/glhf.js +71 -0
- package/src/models/gpt.js +147 -0
- package/src/models/grok.js +82 -0
- package/src/models/groq.js +95 -0
- package/src/models/huggingface.js +86 -0
- package/src/models/hyperbolic.js +114 -0
- package/src/models/lmstudio.js +74 -0
- package/src/models/mercury.js +95 -0
- package/src/models/mistral.js +94 -0
- package/src/models/novita.js +71 -0
- package/src/models/ollama.js +115 -0
- package/src/models/openrouter.js +77 -0
- package/src/models/prompter.js +366 -0
- package/src/models/qwen.js +80 -0
- package/src/models/replicate.js +60 -0
- package/src/models/vllm.js +81 -0
- package/src/process/agent_process.js +84 -0
- package/src/process/init_agent.js +54 -0
- package/src/utils/examples.js +83 -0
- package/src/utils/keys.js +34 -0
- package/src/utils/math.js +13 -0
- package/src/utils/mcdata.js +572 -0
- package/src/utils/text.js +78 -0
- package/src/utils/translator.js +30 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"profile": {
|
|
3
|
+
"type": "object",
|
|
4
|
+
"required": true,
|
|
5
|
+
"description": "The profile object to use, including name, prompts, and examples"
|
|
6
|
+
},
|
|
7
|
+
"data_dir": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Directory where bot memories, histories, screenshots, and generated code are written",
|
|
10
|
+
"default": "./bots"
|
|
11
|
+
},
|
|
12
|
+
"minecraft_version": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "The version of Minecraft to use. Set to 'auto' to automatically detect the version.",
|
|
15
|
+
"default": "auto"
|
|
16
|
+
},
|
|
17
|
+
"host": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "The minecraft server host address to connect to",
|
|
20
|
+
"default": "127.0.0.1"
|
|
21
|
+
},
|
|
22
|
+
"port": {
|
|
23
|
+
"type": "number",
|
|
24
|
+
"description": "The minecraft server port to connect to. -1 for auto-detect.",
|
|
25
|
+
"default": 55916
|
|
26
|
+
},
|
|
27
|
+
"auth": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "The authentication method to use",
|
|
30
|
+
"default": "offline",
|
|
31
|
+
"options": ["offline", "microsoft"]
|
|
32
|
+
},
|
|
33
|
+
"base_profile": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Allowed values: survival, assistant, creative, god_mode. Each has fine tuned settings for different game modes.",
|
|
36
|
+
"default": "survival",
|
|
37
|
+
"options": ["survival", "assistant", "creative", "god_mode"]
|
|
38
|
+
},
|
|
39
|
+
"load_memory": {
|
|
40
|
+
"type": "boolean",
|
|
41
|
+
"description": "Whether to load bot's previous memory",
|
|
42
|
+
"default": false
|
|
43
|
+
},
|
|
44
|
+
"init_message": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "The initial message to send to the bot",
|
|
47
|
+
"default": "Respond with hello world and your name"
|
|
48
|
+
},
|
|
49
|
+
"only_chat_with": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"description": "List of agents to only chat with. If empty, the bot will chat publicly",
|
|
52
|
+
"default": []
|
|
53
|
+
},
|
|
54
|
+
"speak": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"description": "Whether to enable text-to-speech reading on the host machine",
|
|
57
|
+
"default": false
|
|
58
|
+
},
|
|
59
|
+
"language": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"description": "The language to automatically translate to and from using google translate",
|
|
62
|
+
"default": "en"
|
|
63
|
+
},
|
|
64
|
+
"allow_vision": {
|
|
65
|
+
"type": "boolean",
|
|
66
|
+
"description": "Whether to allow vision capabilities",
|
|
67
|
+
"default": false
|
|
68
|
+
},
|
|
69
|
+
"blocked_actions": {
|
|
70
|
+
"type": "array",
|
|
71
|
+
"description": "List of actions that are blocked",
|
|
72
|
+
"default": ["!checkBlueprint", "!checkBlueprintLevel", "!getBlueprint", "!getBlueprintLevel"]
|
|
73
|
+
},
|
|
74
|
+
"relevant_docs_count": {
|
|
75
|
+
"type": "number",
|
|
76
|
+
"description": "Number of relevant function documents to include in the prompt for LLM code writing",
|
|
77
|
+
"default": 5
|
|
78
|
+
},
|
|
79
|
+
"max_messages": {
|
|
80
|
+
"type": "number",
|
|
81
|
+
"description": "Maximum number of recent messages to keep in context for LLM",
|
|
82
|
+
"default": 15
|
|
83
|
+
},
|
|
84
|
+
"num_examples": {
|
|
85
|
+
"type": "number",
|
|
86
|
+
"description": "Number of examples to select to help prompt better LLM responses",
|
|
87
|
+
"default": 2
|
|
88
|
+
},
|
|
89
|
+
"max_commands": {
|
|
90
|
+
"type": "number",
|
|
91
|
+
"description": "Maximum number of commands allowed in consecutive responses. -1 for no limit",
|
|
92
|
+
"default": -1
|
|
93
|
+
},
|
|
94
|
+
"narrate_behavior": {
|
|
95
|
+
"type": "boolean",
|
|
96
|
+
"description": "Whether to openly chat automatic behavior like 'Picking up item!'",
|
|
97
|
+
"default": true
|
|
98
|
+
},
|
|
99
|
+
"log_all_prompts": {
|
|
100
|
+
"type": "boolean",
|
|
101
|
+
"description": "Whether to log all prompts to file. Can be very verbose.",
|
|
102
|
+
"default": false
|
|
103
|
+
},
|
|
104
|
+
"show_command_syntax": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"description": "Whether to show \"full\" command syntax, \"shortened\" command syntax, or \"none\"",
|
|
107
|
+
"default": "full",
|
|
108
|
+
"options": ["full", "shortened", "none"]
|
|
109
|
+
},
|
|
110
|
+
"chat_ingame": {
|
|
111
|
+
"type": "boolean",
|
|
112
|
+
"description": "Whether to show bot's chat messages in game chat",
|
|
113
|
+
"default": true
|
|
114
|
+
},
|
|
115
|
+
"chat_bot_messages": {
|
|
116
|
+
"type": "boolean",
|
|
117
|
+
"description": "Whether to publicly chat messages to and from other bots",
|
|
118
|
+
"default": true
|
|
119
|
+
},
|
|
120
|
+
"render_bot_view": {
|
|
121
|
+
"type": "boolean",
|
|
122
|
+
"description": "Whether to render bot view for user observation. Does not give bot vision.",
|
|
123
|
+
"default": false
|
|
124
|
+
},
|
|
125
|
+
"allow_insecure_coding": {
|
|
126
|
+
"type": "boolean",
|
|
127
|
+
"description": "Whether to allow newAction command that let's LLM write/run code on host computer. Despite sandboxxing, it is potentially insecure.",
|
|
128
|
+
"default": false
|
|
129
|
+
},
|
|
130
|
+
"code_timeout_mins": {
|
|
131
|
+
"type": "number",
|
|
132
|
+
"description": "Number of minutes to allow code execution. -1 for no timeout",
|
|
133
|
+
"default": -1
|
|
134
|
+
},
|
|
135
|
+
"task": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"description": "The task object to give the agent on start. If null, the agent will not have a task.",
|
|
138
|
+
"default": null
|
|
139
|
+
},
|
|
140
|
+
"spawn_timeout": {
|
|
141
|
+
"type": "number",
|
|
142
|
+
"description": "Number of seconds allowed for the bot to spawn before throwing an error. Increase when spawning takes a while.",
|
|
143
|
+
"default": 30
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, chmodSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
// Persistence layer used by the web UI's setup wizard.
|
|
6
|
+
// Keeps API keys, server config, and saved profiles across restarts.
|
|
7
|
+
// Follows the XDG base-dir convention: $XDG_CONFIG_HOME/mindcraft, falling
|
|
8
|
+
// back to ~/.config/mindcraft.
|
|
9
|
+
|
|
10
|
+
const CONFIG_HOME = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
|
|
11
|
+
const ROOT = join(CONFIG_HOME, 'mindcraft');
|
|
12
|
+
const CONFIG_PATH = join(ROOT, 'config.json');
|
|
13
|
+
const KEYS_PATH = join(ROOT, 'keys.json');
|
|
14
|
+
const PROFILES_DIR = join(ROOT, 'profiles');
|
|
15
|
+
const BOTS_DIR = join(ROOT, 'bots');
|
|
16
|
+
|
|
17
|
+
export const paths = { ROOT, CONFIG_PATH, KEYS_PATH, PROFILES_DIR, BOTS_DIR };
|
|
18
|
+
|
|
19
|
+
function readJson(path) {
|
|
20
|
+
if (!existsSync(path)) return null;
|
|
21
|
+
try { return JSON.parse(readFileSync(path, 'utf8')); }
|
|
22
|
+
catch { return null; }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function writeJson(path, data, mode) {
|
|
26
|
+
mkdirSync(ROOT, { recursive: true });
|
|
27
|
+
writeFileSync(path, JSON.stringify(data, null, 2));
|
|
28
|
+
if (mode) chmodSync(path, mode);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getConfig() {
|
|
32
|
+
return readJson(CONFIG_PATH);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function saveConfig(config) {
|
|
36
|
+
writeJson(CONFIG_PATH, config);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function hasKeys() {
|
|
40
|
+
const k = readJson(KEYS_PATH);
|
|
41
|
+
return !!k && Object.values(k).some(v => v);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function loadKeysIntoEnv() {
|
|
45
|
+
const k = readJson(KEYS_PATH);
|
|
46
|
+
if (!k) return;
|
|
47
|
+
for (const [name, value] of Object.entries(k)) {
|
|
48
|
+
if (value && !process.env[name]) process.env[name] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function saveKeys(keys) {
|
|
53
|
+
const existing = readJson(KEYS_PATH) || {};
|
|
54
|
+
writeJson(KEYS_PATH, { ...existing, ...keys }, 0o600);
|
|
55
|
+
for (const [name, value] of Object.entries(keys)) {
|
|
56
|
+
if (value) process.env[name] = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function listProfiles() {
|
|
61
|
+
if (!existsSync(PROFILES_DIR)) return [];
|
|
62
|
+
return readdirSync(PROFILES_DIR)
|
|
63
|
+
.filter(f => f.endsWith('.json'))
|
|
64
|
+
.map(f => readJson(join(PROFILES_DIR, f)))
|
|
65
|
+
.filter(p => p && p.name);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function saveProfile(profile) {
|
|
69
|
+
if (!profile?.name) throw new Error('profile.name is required');
|
|
70
|
+
mkdirSync(PROFILES_DIR, { recursive: true });
|
|
71
|
+
writeJson(join(PROFILES_DIR, `${profile.name}.json`), profile);
|
|
72
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import mindcraft
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# Initialize Mindcraft, starting the Node.js server
|
|
6
|
+
# This will also connect to the MindServer via websockets
|
|
7
|
+
mindcraft.init()
|
|
8
|
+
|
|
9
|
+
# Get the directory of the current script
|
|
10
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
11
|
+
profile_path = os.path.abspath(os.path.join(script_dir, '..', '..', 'andy.json'))
|
|
12
|
+
|
|
13
|
+
# Load agent settings from a JSON file
|
|
14
|
+
try:
|
|
15
|
+
with open(profile_path, 'r') as f:
|
|
16
|
+
profile_data = json.load(f)
|
|
17
|
+
|
|
18
|
+
settings = {"profile": profile_data}
|
|
19
|
+
mindcraft.create_agent(settings)
|
|
20
|
+
|
|
21
|
+
settings_copy = settings.copy()
|
|
22
|
+
settings_copy['profile']['name'] = 'andy2'
|
|
23
|
+
mindcraft.create_agent(settings_copy)
|
|
24
|
+
except FileNotFoundError:
|
|
25
|
+
print(f"Error: Could not find andy.json at {profile_path}")
|
|
26
|
+
|
|
27
|
+
mindcraft.wait()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as Mindcraft from '../mindcraft/mindcraft.js';
|
|
2
|
+
import settings from '../../settings.js';
|
|
3
|
+
import yargs from 'yargs';
|
|
4
|
+
import { hideBin } from 'yargs/helpers';
|
|
5
|
+
|
|
6
|
+
function parseArguments() {
|
|
7
|
+
return yargs(hideBin(process.argv))
|
|
8
|
+
.option('mindserver_port', {
|
|
9
|
+
type: 'number',
|
|
10
|
+
describe: 'Mindserver port',
|
|
11
|
+
default: settings.mindserver_port
|
|
12
|
+
})
|
|
13
|
+
.help()
|
|
14
|
+
.alias('help', 'h')
|
|
15
|
+
.parse();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const args = parseArguments();
|
|
19
|
+
|
|
20
|
+
settings.mindserver_port = args.mindserver_port;
|
|
21
|
+
|
|
22
|
+
Mindcraft.init(settings.mindserver_port);
|
|
23
|
+
|
|
24
|
+
console.log(`Mindcraft initialized with MindServer at localhost:${settings.mindserver_port}`);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import socketio
|
|
3
|
+
import time
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import atexit
|
|
7
|
+
import threading
|
|
8
|
+
import sys
|
|
9
|
+
import signal
|
|
10
|
+
|
|
11
|
+
class Mindcraft:
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self.sio = socketio.Client()
|
|
14
|
+
self.process = None
|
|
15
|
+
self.connected = False
|
|
16
|
+
self.log_thread = None
|
|
17
|
+
|
|
18
|
+
def _log_reader(self):
|
|
19
|
+
for line in iter(self.process.stdout.readline, ''):
|
|
20
|
+
sys.stdout.write(f'[Node.js] {line}')
|
|
21
|
+
sys.stdout.flush()
|
|
22
|
+
|
|
23
|
+
def init(self, port=8080):
|
|
24
|
+
if self.process:
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
self.port = port
|
|
28
|
+
|
|
29
|
+
node_script_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'init-mindcraft.js'))
|
|
30
|
+
|
|
31
|
+
self.process = subprocess.Popen([
|
|
32
|
+
'node',
|
|
33
|
+
node_script_path,
|
|
34
|
+
'--mindserver_port', str(self.port)
|
|
35
|
+
], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1)
|
|
36
|
+
|
|
37
|
+
self.log_thread = threading.Thread(target=self._log_reader)
|
|
38
|
+
self.log_thread.daemon = True
|
|
39
|
+
self.log_thread.start()
|
|
40
|
+
|
|
41
|
+
atexit.register(self.shutdown)
|
|
42
|
+
time.sleep(2) # Give server time to start before connecting
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
self.sio.connect(f'http://localhost:{self.port}')
|
|
46
|
+
self.connected = True
|
|
47
|
+
print("Connected to MindServer. Mindcraft is initialized.")
|
|
48
|
+
except socketio.exceptions.ConnectionError as e:
|
|
49
|
+
print(f"Failed to connect to MindServer: {e}")
|
|
50
|
+
self.shutdown()
|
|
51
|
+
raise
|
|
52
|
+
|
|
53
|
+
def create_agent(self, settings_json):
|
|
54
|
+
if not self.connected:
|
|
55
|
+
raise Exception("Not connected to MindServer. Call init() first.")
|
|
56
|
+
|
|
57
|
+
profile_data = settings_json.get('profile', {})
|
|
58
|
+
|
|
59
|
+
def callback(response):
|
|
60
|
+
if response.get('success'):
|
|
61
|
+
print(f"Agent '{profile_data.get('name')}' created successfully")
|
|
62
|
+
else:
|
|
63
|
+
print(f"Error creating agent: {response.get('error', 'Unknown error')}")
|
|
64
|
+
|
|
65
|
+
self.sio.emit('create-agent', settings_json, callback=callback)
|
|
66
|
+
|
|
67
|
+
def shutdown(self):
|
|
68
|
+
if self.sio.connected:
|
|
69
|
+
self.sio.disconnect()
|
|
70
|
+
self.connected = False
|
|
71
|
+
if self.process:
|
|
72
|
+
self.process.terminate()
|
|
73
|
+
self.process.wait()
|
|
74
|
+
self.process = None
|
|
75
|
+
print("Mindcraft shut down.")
|
|
76
|
+
|
|
77
|
+
def wait(self):
|
|
78
|
+
"""Block the main thread until Ctrl+C is pressed so the server stays up,"""
|
|
79
|
+
print("Server is running. Press Ctrl+C to exit.")
|
|
80
|
+
try:
|
|
81
|
+
while True:
|
|
82
|
+
time.sleep(1)
|
|
83
|
+
except KeyboardInterrupt:
|
|
84
|
+
print("\nCtrl+C detected. Exiting...")
|
|
85
|
+
self.shutdown()
|
|
86
|
+
|
|
87
|
+
mindcraft_instance = Mindcraft()
|
|
88
|
+
|
|
89
|
+
def init(port=8080):
|
|
90
|
+
mindcraft_instance.init(port)
|
|
91
|
+
|
|
92
|
+
def create_agent(settings_json):
|
|
93
|
+
mindcraft_instance.create_agent(settings_json)
|
|
94
|
+
|
|
95
|
+
def shutdown():
|
|
96
|
+
mindcraft_instance.shutdown()
|
|
97
|
+
|
|
98
|
+
def wait():
|
|
99
|
+
mindcraft_instance.wait()
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
// Dynamically discover model classes in this directory.
|
|
9
|
+
// Each model class must export a static `prefix` string.
|
|
10
|
+
const apiMap = await (async () => {
|
|
11
|
+
const map = {};
|
|
12
|
+
const files = (await fs.readdir(__dirname))
|
|
13
|
+
.filter(f => f.endsWith('.js') && f !== '_model_map.js' && f !== 'prompter.js');
|
|
14
|
+
for (const file of files) {
|
|
15
|
+
try {
|
|
16
|
+
const moduleUrl = pathToFileURL(path.join(__dirname, file)).href;
|
|
17
|
+
const mod = await import(moduleUrl);
|
|
18
|
+
for (const exported of Object.values(mod)) {
|
|
19
|
+
if (typeof exported === 'function' && Object.prototype.hasOwnProperty.call(exported, 'prefix')) {
|
|
20
|
+
const prefix = exported.prefix;
|
|
21
|
+
if (typeof prefix === 'string' && prefix.length > 0) {
|
|
22
|
+
map[prefix] = exported;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.warn('Failed to load model module:', file, e?.message || e);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return map;
|
|
31
|
+
})();
|
|
32
|
+
|
|
33
|
+
export function selectAPI(profile) {
|
|
34
|
+
if (typeof profile === 'string' || profile instanceof String) {
|
|
35
|
+
profile = {model: profile};
|
|
36
|
+
}
|
|
37
|
+
// backwards compatibility with local->ollama
|
|
38
|
+
if (profile.api?.includes('local') || profile.model?.includes('local')) {
|
|
39
|
+
profile.api = 'ollama';
|
|
40
|
+
if (profile.model) {
|
|
41
|
+
profile.model = profile.model.replace('local', 'ollama');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!profile.api) {
|
|
45
|
+
const api = Object.keys(apiMap).find(key => profile.model?.startsWith(key));
|
|
46
|
+
if (api) {
|
|
47
|
+
profile.api = api;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// check for some common models that do not require prefixes
|
|
51
|
+
if (profile.model.includes('gpt') || profile.model.includes('o1')|| profile.model.includes('o3'))
|
|
52
|
+
profile.api = 'openai';
|
|
53
|
+
else if (profile.model.includes('claude'))
|
|
54
|
+
profile.api = 'anthropic';
|
|
55
|
+
else if (profile.model.includes('gemini'))
|
|
56
|
+
profile.api = "google";
|
|
57
|
+
else if (profile.model.includes('grok'))
|
|
58
|
+
profile.api = 'xai';
|
|
59
|
+
else if (profile.model.includes('mistral'))
|
|
60
|
+
profile.api = 'mistral';
|
|
61
|
+
else if (profile.model.includes('deepseek'))
|
|
62
|
+
profile.api = 'deepseek';
|
|
63
|
+
else if (profile.model.includes('qwen'))
|
|
64
|
+
profile.api = 'qwen';
|
|
65
|
+
}
|
|
66
|
+
if (!profile.api) {
|
|
67
|
+
throw new Error('Unknown model:', profile.model);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!apiMap[profile.api]) {
|
|
71
|
+
throw new Error('Unknown api:', profile.api);
|
|
72
|
+
}
|
|
73
|
+
let model_name = profile.model.replace(profile.api + '/', ''); // remove prefix
|
|
74
|
+
profile.model = model_name === "" ? null : model_name; // if model is empty, set to null
|
|
75
|
+
return profile;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createModel(profile) {
|
|
79
|
+
if (!!apiMap[profile.model]) {
|
|
80
|
+
// if the model value is an api (instead of a specific model name)
|
|
81
|
+
// then set model to null so it uses the default model for that api
|
|
82
|
+
profile.model = null;
|
|
83
|
+
}
|
|
84
|
+
if (!apiMap[profile.api]) {
|
|
85
|
+
throw new Error('Unknown api:', profile.api);
|
|
86
|
+
}
|
|
87
|
+
const model = new apiMap[profile.api](profile.model, profile.url, profile.params);
|
|
88
|
+
return model;
|
|
89
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AzureOpenAI } from "openai";
|
|
2
|
+
import { getKey, hasKey } from '../utils/keys.js';
|
|
3
|
+
import { GPT } from './gpt.js'
|
|
4
|
+
|
|
5
|
+
export class AzureGPT extends GPT {
|
|
6
|
+
static prefix = 'azure';
|
|
7
|
+
constructor(model_name, url, params) {
|
|
8
|
+
super(model_name, url)
|
|
9
|
+
|
|
10
|
+
this.model_name = model_name;
|
|
11
|
+
this.params = params || {};
|
|
12
|
+
|
|
13
|
+
const config = {};
|
|
14
|
+
|
|
15
|
+
if (url)
|
|
16
|
+
config.endpoint = url;
|
|
17
|
+
|
|
18
|
+
config.apiKey = hasKey('AZURE_OPENAI_API_KEY') ? getKey('AZURE_OPENAI_API_KEY') : getKey('OPENAI_API_KEY');
|
|
19
|
+
|
|
20
|
+
config.deployment = model_name;
|
|
21
|
+
|
|
22
|
+
if (this.params.apiVersion) {
|
|
23
|
+
config.apiVersion = this.params.apiVersion;
|
|
24
|
+
delete this.params.apiVersion; // remove from params for later use in requests
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
throw new Error('apiVersion is required in params for azure!');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.openai = new AzureOpenAI(config)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import CerebrasSDK from '@cerebras/cerebras_cloud_sdk';
|
|
2
|
+
import { strictFormat } from '../utils/text.js';
|
|
3
|
+
import { getKey } from '../utils/keys.js';
|
|
4
|
+
|
|
5
|
+
export class Cerebras {
|
|
6
|
+
static prefix = 'cerebras';
|
|
7
|
+
constructor(model_name, url, params) {
|
|
8
|
+
this.model_name = model_name;
|
|
9
|
+
this.url = url;
|
|
10
|
+
this.params = params;
|
|
11
|
+
|
|
12
|
+
// Initialize client with API key
|
|
13
|
+
this.client = new CerebrasSDK({ apiKey: getKey('CEREBRAS_API_KEY') });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async sendRequest(turns, systemMessage, stop_seq = '***') {
|
|
17
|
+
// Format messages array
|
|
18
|
+
const messages = strictFormat(turns);
|
|
19
|
+
messages.unshift({ role: 'system', content: systemMessage });
|
|
20
|
+
|
|
21
|
+
const pack = {
|
|
22
|
+
model: this.model_name || 'gpt-oss-120b',
|
|
23
|
+
messages,
|
|
24
|
+
stream: false,
|
|
25
|
+
...(this.params || {}),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let res;
|
|
29
|
+
try {
|
|
30
|
+
const completion = await this.client.chat.completions.create(pack);
|
|
31
|
+
// OpenAI-compatible shape
|
|
32
|
+
res = completion.choices?.[0]?.message?.content || '';
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error('Cerebras API error:', err);
|
|
35
|
+
res = 'My brain disconnected, try again.';
|
|
36
|
+
}
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async sendVisionRequest(messages, systemMessage, imageBuffer) {
|
|
41
|
+
const imageMessages = [...messages];
|
|
42
|
+
imageMessages.push({
|
|
43
|
+
role: "user",
|
|
44
|
+
content: [
|
|
45
|
+
{ type: "text", text: systemMessage },
|
|
46
|
+
{
|
|
47
|
+
type: "image_url",
|
|
48
|
+
image_url: {
|
|
49
|
+
url: `data:image/jpeg;base64,${imageBuffer.toString('base64')}`
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return this.sendRequest(imageMessages, systemMessage);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async embed(text) {
|
|
59
|
+
throw new Error('Embeddings are not supported by Cerebras.');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import { strictFormat } from '../utils/text.js';
|
|
3
|
+
import { getKey } from '../utils/keys.js';
|
|
4
|
+
|
|
5
|
+
export class Claude {
|
|
6
|
+
static prefix = 'anthropic';
|
|
7
|
+
constructor(model_name, url, params) {
|
|
8
|
+
this.model_name = model_name;
|
|
9
|
+
this.params = params || {};
|
|
10
|
+
|
|
11
|
+
let config = {};
|
|
12
|
+
if (url)
|
|
13
|
+
config.baseURL = url;
|
|
14
|
+
|
|
15
|
+
config.apiKey = getKey('ANTHROPIC_API_KEY');
|
|
16
|
+
|
|
17
|
+
this.anthropic = new Anthropic(config);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async sendRequest(turns, systemMessage) {
|
|
21
|
+
const messages = strictFormat(turns);
|
|
22
|
+
let res = null;
|
|
23
|
+
try {
|
|
24
|
+
console.log(`Awaiting anthropic response from ${this.model_name}...`)
|
|
25
|
+
if (!this.params.max_tokens) {
|
|
26
|
+
if (this.params.thinking?.budget_tokens) {
|
|
27
|
+
this.params.max_tokens = this.params.thinking.budget_tokens + 1000;
|
|
28
|
+
// max_tokens must be greater than thinking.budget_tokens
|
|
29
|
+
} else {
|
|
30
|
+
this.params.max_tokens = 4096;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const resp = await this.anthropic.messages.create({
|
|
34
|
+
model: this.model_name || "claude-sonnet-4-20250514",
|
|
35
|
+
system: systemMessage,
|
|
36
|
+
messages: messages,
|
|
37
|
+
...(this.params || {})
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
console.log('Received.')
|
|
41
|
+
// get first content of type text
|
|
42
|
+
const textContent = resp.content.find(content => content.type === 'text');
|
|
43
|
+
if (textContent) {
|
|
44
|
+
res = textContent.text;
|
|
45
|
+
} else {
|
|
46
|
+
console.warn('No text content found in the response.');
|
|
47
|
+
res = 'No response from Claude.';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err.message.includes("does not support image input")) {
|
|
52
|
+
res = "Vision is only supported by certain models.";
|
|
53
|
+
} else {
|
|
54
|
+
res = "My brain disconnected, try again.";
|
|
55
|
+
}
|
|
56
|
+
console.log(err);
|
|
57
|
+
}
|
|
58
|
+
return res;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async sendVisionRequest(turns, systemMessage, imageBuffer) {
|
|
62
|
+
const imageMessages = [...turns];
|
|
63
|
+
imageMessages.push({
|
|
64
|
+
role: "user",
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: systemMessage
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: "image",
|
|
72
|
+
source: {
|
|
73
|
+
type: "base64",
|
|
74
|
+
media_type: "image/jpeg",
|
|
75
|
+
data: imageBuffer.toString('base64')
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return this.sendRequest(imageMessages, systemMessage);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async embed(text) {
|
|
85
|
+
throw new Error('Embeddings are not supported by Claude.');
|
|
86
|
+
}
|
|
87
|
+
}
|