mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-07-19 14:35:17 +02:00
Merge branch 'main' into main
This commit is contained in:
commit
7c3660e0f2
10 changed files with 221 additions and 173 deletions
|
@ -43,9 +43,9 @@ You can configure the agent's name, model, and prompts in their profile like `an
|
|||
| Anthropic | `ANTHROPIC_API_KEY` | `claude-3-5-haiku-20241022` | [docs](https://docs.anthropic.com/claude/docs/models-overview) |
|
||||
| Replicate | `REPLICATE_API_KEY` | `replicate/meta/meta-llama-3-70b-instruct` | [docs](https://replicate.com/collections/language-models) |
|
||||
| Ollama (local) | n/a | `ollama/qwen2.5` | [docs](https://ollama.com/library) |
|
||||
| Groq | `GROQCLOUD_API_KEY` | `groq/mixtral-8x7b-32768` | [docs](https://console.groq.com/docs/models) |
|
||||
| Groq (Not Grok) | `GROQCLOUD_API_KEY` | `groq/mixtral-8x7b-32768` | [docs](https://console.groq.com/docs/models) |
|
||||
| Hugging Face | `HUGGINGFACE_API_KEY` | `huggingface/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B` | [docs](https://huggingface.co/models) |
|
||||
| Novita AI | `NOVITA_API_KEY` | `gryphe/mythomax-l2-13b` | [docs](https://novita.ai/model-api/product/llm-api?utm_source=github_mindcraft&utm_medium=github_readme&utm_campaign=link) |
|
||||
| Novita | `NOVITA_API_KEY` | `novita/deepseek/deepseek-r1` | [docs](https://novita.ai/model-api/product/llm-api?utm_source=github_mindcraft&utm_medium=github_readme&utm_campaign=link) |
|
||||
| Qwen | `QWEN_API_KEY` | `qwen-max` | [Intl.](https://www.alibabacloud.com/help/en/model-studio/developer-reference/use-qwen-by-calling-api)/[cn](https://help.aliyun.com/zh/model-studio/getting-started/models) |
|
||||
| Mistral | `MISTRAL_API_KEY` | `mistral-large-latest` | [docs](https://docs.mistral.ai/getting-started/models/models_overview/) |
|
||||
| xAI | `XAI_API_KEY` | `grok-2` | [docs](https://docs.x.ai/docs) |
|
||||
|
@ -54,6 +54,7 @@ You can configure the agent's name, model, and prompts in their profile like `an
|
|||
| glhf.chat | `GHLF_API_KEY` | `GLHF/hf:meta-llama/Llama-3.1-405B-Instruct` | [docs](https://glhf.chat/user-settings/api) |
|
||||
| Hyperbolic | `HYPERBOLIC_API_KEY` | `hyperbolic/deepseek-ai/DeepSeek-V3` | [docs](https://docs.hyperbolic.xyz/docs/getting-started) |
|
||||
|
||||
|
||||
If you use Ollama, to install the models used by default (generation and embedding), execute the following terminal command:
|
||||
`ollama pull qwen2.5 && ollama pull nomic-embed-text`
|
||||
Note that you can you any local model, such as `qwen2.5` `llama3` or fine tuned models like `sweaterdog/andy-3.6` But not matter what model, it is recommended you put `ollama/` before the model so Mindcraft can handle it properly.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"canvas": "^3.1.0",
|
||||
"express": "^4.18.2",
|
||||
"google-translate-api-x": "^10.7.1",
|
||||
"groq-sdk": "^0.5.0",
|
||||
"groq-sdk": "^0.15.0",
|
||||
"minecraft-data": "^3.78.0",
|
||||
"mineflayer": "^4.23.0",
|
||||
"mineflayer-armor-manager": "^2.0.1",
|
||||
|
|
15
profiles/claude_thinker.json
Normal file
15
profiles/claude_thinker.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "claude_thinker",
|
||||
|
||||
"model": {
|
||||
"model": "claude-3-7-sonnet-latest",
|
||||
"params": {
|
||||
"thinking": {
|
||||
"type": "enabled",
|
||||
"budget_tokens": 16000
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"embedding": "openai"
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
"conversing": "You are a playful Minecraft bot named $NAME that can converse with players, see, move, mine, build, and interact with the world by using commands.\n$SELF_PROMPT Act human-like as if you were a typical Minecraft player, rather than an AI. Be very brief in your responses, don't apologize constantly, don't give instructions or make lists unless asked, and don't refuse requests. Don't pretend to act, use commands immediately when requested. Do NOT say this: 'Sure, I've stopped.', instead say this: 'Sure, I'll stop. !stop'. Do NOT say this: 'On my way! Give me a moment.', instead say this: 'On my way! !goToPlayer(\"playername\", 3)'. Respond only as $NAME, never output '(FROM OTHER BOT)' or pretend to be someone else. If you have nothing to say or do, respond with an just a tab '\t'. This is extremely important to me, take a deep breath and have fun :)\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
|
||||
|
||||
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation between you and the user, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will receive it's output. If you are satisfied with the response, respond without a codeblock in a conversational way. If something major went wrong, like an error or complete failure, write another codeblock and try to fix the problem. Minor mistakes are acceptable. Be maximally efficient, creative, and clear. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST CALL AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` Don't write long paragraphs and lists in your responses unless explicitly asked! Only summarize the code you write with a sentence or two when done. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
|
||||
"coding": "You are an intelligent mineflayer bot $NAME that plays minecraft by writing javascript codeblocks. Given the conversation, use the provided skills and world functions to write a js codeblock that controls the mineflayer bot ``` // using this syntax ```. The code will be executed and you will receive it's output. If an error occurs, write another codeblock and try to fix the problem. Be maximally efficient, creative, and correct. Be mindful of previous actions. Do not use commands !likeThis, only use codeblocks. The code is asynchronous and MUST USE AWAIT for all async function calls. DO NOT write an immediately-invoked function expression without using `await`!! DO NOT WRITE LIKE THIS: ```(async () => {console.log('not properly awaited')})();``` You have `Vec3`, `skills`, and `world` imported, and the mineflayer `bot` is given. Do not use setTimeout or setInterval, instead use `await skills.wait(bot, ms)`. Do not speak conversationally, only use codeblocks. Do any planning in comments. This is extremely important to me, think step-by-step, take a deep breath and good luck! \n$SELF_PROMPT\nSummarized memory:'$MEMORY'\n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nConversation:",
|
||||
|
||||
"saving_memory": "You are a minecraft bot named $NAME that has been talking and playing minecraft by using commands. Update your memory by summarizing the following conversation and your old memory in your next response. Prioritize preserving important facts, things you've learned, useful tips, and long term reminders. Do Not record stats, inventory, or docs! Only save transient information from your chat history. You're limited to 500 characters, so be extremely brief and minimize words. Compress useful information. \nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the unwrapped memory text: ",
|
||||
|
||||
|
@ -238,8 +238,9 @@
|
|||
],
|
||||
[
|
||||
{"role": "user", "content": "brug: build a dirt house"},
|
||||
{"role": "assistant", "content": "```const position = world.getPosition(bot);\nconst startX = position.x;\nconst startY = position.y;\nconst startZ = position.z;\nconst width = 7;\nconst depth = 7;\nconst height = 4;\n\n// Build the walls\nfor (let x = startX; x < startX + width; x++) {\n for (let y = startY; y < startY + height; y++) {\n for (let z = startZ; z < startZ + depth; z++) {\n if (x === startX || x === startX + width - 1 || y === startY || y === startY + height - 1 || z === startZ || z === startZ + depth - 1) {\n await skills.placeBlock(bot, 'oak_planks', x, y, z); \n }\n }\n }\n}\n```"}
|
||||
{"role": "assistant", "content": "```js\nconst position = world.getPosition(bot);\nconst startX = position.x;\nconst startY = position.y;\nconst startZ = position.z;\nconst width = 7;\nconst depth = 7;\nconst height = 4;\n\n// Build front wall (z = startZ)\nfor (let x = startX; x < startX + width; x++) {\n for (let y = startY; y < startY + height; y++) {\n await skills.placeBlock(bot, 'oak_planks', x, y, startZ);\n }\n}\n\n// Build back wall (z = startZ + depth - 1)\nfor (let x = startX; x < startX + width; x++) {\n for (let y = startY; y < startY + height; y++) {\n await skills.placeBlock(bot, 'oak_planks', x, y, startZ + depth - 1);\n }\n}\n\n// Build left wall (x = startX)\nfor (let z = startZ; z < startZ + depth; z++) {\n for (let y = startY; y < startY + height; y++) {\n await skills.placeBlock(bot, 'oak_planks', startX, y, z);\n }\n}\n\n// Build right wall (x = startX + width - 1)\nfor (let z = startZ; z < startZ + depth; z++) {\n for (let y = startY; y < startY + height; y++) {\n await skills.placeBlock(bot, 'oak_planks', startX + width - 1, y, z);\n }\n}\n\n// Build floor (y = startY)\nfor (let x = startX; x < startX + width; x++) {\n for (let z = startZ; z < startZ + depth; z++) {\n await skills.placeBlock(bot, 'oak_planks', x, startY, z);\n }\n}\n\n// Build ceiling (y = startY + height - 1)\nfor (let x = startX; x < startX + width; x++) {\n for (let z = startZ; z < startZ + depth; z++) {\n await skills.placeBlock(bot, 'oak_planks', x, startY + height - 1, z);\n }\n}\n```"}
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
}
|
||||
|
|
|
@ -19,96 +19,85 @@ export class Agent {
|
|||
async start(profile_fp, load_mem=false, init_message=null, count_id=0, task_path=null, task_id=null) {
|
||||
this.last_sender = null;
|
||||
this.count_id = count_id;
|
||||
try {
|
||||
if (!profile_fp) {
|
||||
throw new Error('No profile filepath provided');
|
||||
}
|
||||
|
||||
console.log('Starting agent initialization with profile:', profile_fp);
|
||||
|
||||
// Initialize components with more detailed error handling
|
||||
console.log('Initializing action manager...');
|
||||
this.actions = new ActionManager(this);
|
||||
console.log('Initializing prompter...');
|
||||
this.prompter = new Prompter(this, profile_fp);
|
||||
this.name = this.prompter.getName();
|
||||
console.log('Initializing history...');
|
||||
this.history = new History(this);
|
||||
console.log('Initializing coder...');
|
||||
this.coder = new Coder(this);
|
||||
console.log('Initializing npc controller...');
|
||||
this.npc = new NPCContoller(this);
|
||||
console.log('Initializing memory bank...');
|
||||
this.memory_bank = new MemoryBank();
|
||||
console.log('Initializing self prompter...');
|
||||
this.self_prompter = new SelfPrompter(this);
|
||||
convoManager.initAgent(this);
|
||||
console.log('Initializing examples...');
|
||||
await this.prompter.initExamples();
|
||||
console.log('Initializing task...');
|
||||
this.task = new Task(this, task_path, task_id);
|
||||
const blocked_actions = this.task.blocked_actions || [];
|
||||
blacklistCommands(blocked_actions);
|
||||
|
||||
serverProxy.connect(this);
|
||||
|
||||
console.log(this.name, 'logging into minecraft...');
|
||||
this.bot = initBot(this.name);
|
||||
|
||||
initModes(this);
|
||||
|
||||
let save_data = null;
|
||||
if (load_mem) {
|
||||
save_data = this.history.load();
|
||||
}
|
||||
|
||||
this.bot.on('login', () => {
|
||||
console.log(this.name, 'logged in!');
|
||||
|
||||
serverProxy.login();
|
||||
|
||||
// Set skin for profile, requires Fabric Tailor. (https://modrinth.com/mod/fabrictailor)
|
||||
if (this.prompter.profile.skin)
|
||||
this.bot.chat(`/skin set URL ${this.prompter.profile.skin.model} ${this.prompter.profile.skin.path}`);
|
||||
else
|
||||
this.bot.chat(`/skin clear`);
|
||||
});
|
||||
|
||||
const spawnTimeout = setTimeout(() => {
|
||||
process.exit(0);
|
||||
}, 30000);
|
||||
this.bot.once('spawn', async () => {
|
||||
try {
|
||||
clearTimeout(spawnTimeout);
|
||||
addViewer(this.bot, count_id);
|
||||
|
||||
// wait for a bit so stats are not undefined
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
console.log(`${this.name} spawned.`);
|
||||
this.clearBotLogs();
|
||||
|
||||
this._setupEventHandlers(save_data, init_message);
|
||||
this.startEvents();
|
||||
|
||||
// this.task.initBotTask();
|
||||
if (!load_mem) {
|
||||
this.task.initBotTask();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in spawn event:', error);
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
// Ensure we're not losing error details
|
||||
console.error('Agent start failed with error')
|
||||
console.error(error.message);
|
||||
console.error(error.stack);
|
||||
|
||||
throw error; // Re-throw with preserved details
|
||||
if (!profile_fp) {
|
||||
throw new Error('No profile filepath provided');
|
||||
}
|
||||
|
||||
console.log('Starting agent initialization with profile:', profile_fp);
|
||||
|
||||
// Initialize components with more detailed error handling
|
||||
console.log('Initializing action manager...');
|
||||
this.actions = new ActionManager(this);
|
||||
console.log('Initializing prompter...');
|
||||
this.prompter = new Prompter(this, profile_fp);
|
||||
this.name = this.prompter.getName();
|
||||
console.log('Initializing history...');
|
||||
this.history = new History(this);
|
||||
console.log('Initializing coder...');
|
||||
this.coder = new Coder(this);
|
||||
console.log('Initializing npc controller...');
|
||||
this.npc = new NPCContoller(this);
|
||||
console.log('Initializing memory bank...');
|
||||
this.memory_bank = new MemoryBank();
|
||||
console.log('Initializing self prompter...');
|
||||
this.self_prompter = new SelfPrompter(this);
|
||||
convoManager.initAgent(this);
|
||||
console.log('Initializing examples...');
|
||||
await this.prompter.initExamples();
|
||||
console.log('Initializing task...');
|
||||
this.task = new Task(this, task_path, task_id);
|
||||
const blocked_actions = this.task.blocked_actions || [];
|
||||
blacklistCommands(blocked_actions);
|
||||
|
||||
serverProxy.connect(this);
|
||||
|
||||
console.log(this.name, 'logging into minecraft...');
|
||||
this.bot = initBot(this.name);
|
||||
|
||||
initModes(this);
|
||||
|
||||
let save_data = null;
|
||||
if (load_mem) {
|
||||
save_data = this.history.load();
|
||||
}
|
||||
|
||||
this.bot.on('login', () => {
|
||||
console.log(this.name, 'logged in!');
|
||||
|
||||
serverProxy.login();
|
||||
|
||||
// Set skin for profile, requires Fabric Tailor. (https://modrinth.com/mod/fabrictailor)
|
||||
if (this.prompter.profile.skin)
|
||||
this.bot.chat(`/skin set URL ${this.prompter.profile.skin.model} ${this.prompter.profile.skin.path}`);
|
||||
else
|
||||
this.bot.chat(`/skin clear`);
|
||||
});
|
||||
|
||||
const spawnTimeout = setTimeout(() => {
|
||||
process.exit(0);
|
||||
}, 30000);
|
||||
this.bot.once('spawn', async () => {
|
||||
try {
|
||||
clearTimeout(spawnTimeout);
|
||||
addViewer(this.bot, count_id);
|
||||
|
||||
// wait for a bit so stats are not undefined
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
console.log(`${this.name} spawned.`);
|
||||
this.clearBotLogs();
|
||||
this._setupEventHandlers(save_data, init_message);
|
||||
this.startEvents();
|
||||
|
||||
if (!load_mem) {
|
||||
this.task.initBotTask();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in spawn event:', error);
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async _setupEventHandlers(save_data, init_message) {
|
||||
|
|
|
@ -39,7 +39,7 @@ export class Coder {
|
|||
// check function exists
|
||||
const missingSkills = skills.filter(skill => !!allDocs[skill]);
|
||||
if (missingSkills.length > 0) {
|
||||
result += 'These functions do not exist. Please modify the correct function name and try again.\n';
|
||||
result += 'These functions do not exist.\n';
|
||||
result += '### FUNCTIONS NOT FOUND ###\n';
|
||||
result += missingSkills.join('\n');
|
||||
console.log(result)
|
||||
|
@ -177,12 +177,14 @@ export class Coder {
|
|||
}
|
||||
|
||||
if (failures >= 3) {
|
||||
console.warn("Action failed, agent would not write code.");
|
||||
return { success: false, message: 'Action failed, agent would not write code.', interrupted: false, timedout: false };
|
||||
}
|
||||
messages.push({
|
||||
role: 'system',
|
||||
content: 'Error: no code provided. Write code in codeblock in your response. ``` // example ```'}
|
||||
);
|
||||
console.warn("No code block generated.");
|
||||
failures++;
|
||||
continue;
|
||||
}
|
||||
|
@ -192,12 +194,14 @@ export class Coder {
|
|||
let src_lint_copy = result.src_lint_copy;
|
||||
const analysisResult = await this.lintCode(src_lint_copy);
|
||||
if (analysisResult) {
|
||||
const message = 'Error: Code syntax error. Please try again:'+'\n'+analysisResult+'\n';
|
||||
const message = 'Error: Code lint error:'+'\n'+analysisResult+'\nPlease try again.';
|
||||
console.warn("Linting error:"+'\n'+analysisResult+'\n');
|
||||
messages.push({ role: 'system', content: message });
|
||||
continue;
|
||||
}
|
||||
if (!executionModuleExports) {
|
||||
agent_history.add('system', 'Failed to stage code, something is wrong.');
|
||||
console.warn("Failed to stage code, something is wrong.");
|
||||
return {success: false, message: null, interrupted: false, timedout: false};
|
||||
}
|
||||
|
||||
|
|
|
@ -111,16 +111,28 @@ export async function craftRecipe(bot, itemName, num=1) {
|
|||
return true;
|
||||
}
|
||||
|
||||
export async function wait(seconds) {
|
||||
export async function wait(bot, milliseconds) {
|
||||
/**
|
||||
* Waits for the given number of seconds.
|
||||
* @param {number} seconds, the number of seconds to wait.
|
||||
* Waits for the given number of milliseconds.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {number} milliseconds, the number of milliseconds to wait.
|
||||
* @returns {Promise<boolean>} true if the wait was successful, false otherwise.
|
||||
* @example
|
||||
* await skills.wait(10);
|
||||
* await skills.wait(bot, 1000);
|
||||
**/
|
||||
// setTimeout is disabled to prevent unawaited code, so this is a safe alternative
|
||||
await new Promise(resolve => setTimeout(resolve, seconds * 1000));
|
||||
// setTimeout is disabled to prevent unawaited code, so this is a safe alternative that enables interrupts
|
||||
let timeLeft = milliseconds;
|
||||
let startTime = Date.now();
|
||||
|
||||
while (timeLeft > 0) {
|
||||
if (bot.interrupt_code) return false;
|
||||
|
||||
let waitTime = Math.min(2000, timeLeft);
|
||||
await new Promise(resolve => setTimeout(resolve, waitTime));
|
||||
|
||||
let elapsed = Date.now() - startTime;
|
||||
timeLeft = milliseconds - elapsed;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,12 @@ export class Claude {
|
|||
try {
|
||||
console.log('Awaiting anthropic api response...')
|
||||
if (!this.params.max_tokens) {
|
||||
this.params.max_tokens = 4096;
|
||||
if (this.params.thinking?.budget_tokens) {
|
||||
this.params.max_tokens = this.params.thinking.budget_tokens + 1000;
|
||||
// max_tokens must be greater than thinking.budget_tokens
|
||||
} else {
|
||||
this.params.max_tokens = 16000;
|
||||
}
|
||||
}
|
||||
const resp = await this.anthropic.messages.create({
|
||||
model: this.model_name || "claude-3-sonnet-20240229",
|
||||
|
@ -32,7 +37,14 @@ export class Claude {
|
|||
});
|
||||
|
||||
console.log('Received.')
|
||||
res = resp.content[0].text;
|
||||
// get first content of type text
|
||||
const textContent = resp.content.find(content => content.type === 'text');
|
||||
if (textContent) {
|
||||
res = textContent.text;
|
||||
} else {
|
||||
console.warn('No text content found in the response.');
|
||||
res = 'No response from Claude.';
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
|
|
|
@ -1,87 +1,105 @@
|
|||
import Groq from 'groq-sdk'
|
||||
import { getKey } from '../utils/keys.js';
|
||||
|
||||
// Umbrella class for Mixtral, LLama, Gemma...
|
||||
// THIS API IS NOT TO BE CONFUSED WITH GROK!
|
||||
// Go to grok.js for that. :)
|
||||
|
||||
// Umbrella class for everything under the sun... That GroqCloud provides, that is.
|
||||
export class GroqCloudAPI {
|
||||
|
||||
constructor(model_name, url, params) {
|
||||
this.model_name = model_name;
|
||||
this.url = url;
|
||||
this.params = params || {};
|
||||
// Groq Cloud does not support custom URLs; warn if provided
|
||||
if (this.url) {
|
||||
console.warn("Groq Cloud has no implementation for custom URLs. Ignoring provided URL.");
|
||||
constructor(model_name, url, params) {
|
||||
|
||||
this.model_name = model_name;
|
||||
this.url = url;
|
||||
this.params = params || {};
|
||||
|
||||
// Remove any mention of "tools" from params:
|
||||
if (this.params.tools)
|
||||
delete this.params.tools;
|
||||
// This is just a bit of future-proofing in case we drag Mindcraft in that direction.
|
||||
|
||||
// I'm going to do a sneaky ReplicateAPI theft for a lot of this, aren't I?
|
||||
if (this.url)
|
||||
console.warn("Groq Cloud has no implementation for custom URLs. Ignoring provided URL.");
|
||||
|
||||
this.groq = new Groq({ apiKey: getKey('GROQCLOUD_API_KEY') });
|
||||
|
||||
|
||||
}
|
||||
this.groq = new Groq({ apiKey: getKey('GROQCLOUD_API_KEY') });
|
||||
}
|
||||
|
||||
async sendRequest(turns, systemMessage, stop_seq = null) {
|
||||
const maxAttempts = 5;
|
||||
let attempt = 0;
|
||||
let finalRes = null;
|
||||
const messages = [{ role: "system", content: systemMessage }].concat(turns);
|
||||
async sendRequest(turns, systemMessage, stop_seq = null) {
|
||||
// Variables for DeepSeek-R1 models
|
||||
const maxAttempts = 5;
|
||||
let attempt = 0;
|
||||
let finalRes = null;
|
||||
let res = null;
|
||||
|
||||
while (attempt < maxAttempts) {
|
||||
attempt++;
|
||||
let res = null;
|
||||
try {
|
||||
console.log(`Awaiting Groq response... (model: ${this.model_name || "mixtral-8x7b-32768"}, attempt: ${attempt})`);
|
||||
if (!this.params.max_tokens) {
|
||||
this.params.max_tokens = 16384;
|
||||
}
|
||||
// Create the streaming chat completion request
|
||||
const completion = await this.groq.chat.completions.create({
|
||||
messages: messages,
|
||||
model: this.model_name || "mixtral-8x7b-32768",
|
||||
stream: true,
|
||||
stop: stop_seq,
|
||||
...(this.params || {})
|
||||
});
|
||||
// Construct messages array
|
||||
let messages = [{"role": "system", "content": systemMessage}].concat(turns);
|
||||
|
||||
while (attempt < maxAttempts) {
|
||||
attempt++;
|
||||
|
||||
let temp_res = "";
|
||||
// Aggregate streamed chunks into a full response
|
||||
for await (const chunk of completion) {
|
||||
temp_res += chunk.choices[0]?.delta?.content || '';
|
||||
}
|
||||
res = temp_res;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
res = "My brain just kinda stopped working. Try again.";
|
||||
// These variables look odd, but they're for the future.
|
||||
let raw_res = null;
|
||||
let tool_calls = null;
|
||||
|
||||
try {
|
||||
console.log("Awaiting Groq response...");
|
||||
|
||||
// Handle deprecated max_tokens parameter
|
||||
if (this.params.max_tokens) {
|
||||
console.warn("GROQCLOUD WARNING: A profile is using `max_tokens`. This is deprecated. Please move to `max_completion_tokens`.");
|
||||
this.params.max_completion_tokens = this.params.max_tokens;
|
||||
delete this.params.max_tokens;
|
||||
}
|
||||
|
||||
// If the model name includes "deepseek-r1", handle the <think> tags
|
||||
const hasOpenTag = res.includes("<think>");
|
||||
const hasCloseTag = res.includes("</think>");
|
||||
if (!this.params.max_completion_tokens) {
|
||||
this.params.max_completion_tokens = 8000; // Set it lower.
|
||||
}
|
||||
|
||||
// If a partial <think> block is detected, log a warning and retry
|
||||
if (hasOpenTag && !hasCloseTag) {
|
||||
console.warn("Partial <think> block detected. Re-generating Groq request...");
|
||||
continue;
|
||||
}
|
||||
let completion = await this.groq.chat.completions.create({
|
||||
"messages": messages,
|
||||
"model": this.model_name || "llama-3.3-70b-versatile",
|
||||
"stream": false,
|
||||
"stop": stop_seq,
|
||||
...(this.params || {})
|
||||
});
|
||||
|
||||
// If only the closing tag is present, prepend an opening tag
|
||||
if (hasCloseTag && !hasOpenTag) {
|
||||
res = '<think>' + res;
|
||||
}
|
||||
// Remove the complete <think> block (and any content inside) from the response
|
||||
res = res.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
||||
|
||||
finalRes = res;
|
||||
break; // Exit the loop once a valid response is obtained
|
||||
raw_res = completion.choices[0].message;
|
||||
res = raw_res.content;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
res = "My brain just kinda stopped working. Try again.";
|
||||
}
|
||||
|
||||
if (finalRes == null) {
|
||||
console.warn("Could not obtain a valid <think> block or normal response after max attempts.");
|
||||
finalRes = "I thought too hard, sorry, try again.";
|
||||
// Check for <think> tag issues
|
||||
const hasOpenTag = res.includes("<think>");
|
||||
const hasCloseTag = res.includes("</think>");
|
||||
|
||||
// If a partial <think> block is detected, log a warning and retry
|
||||
if (hasOpenTag && !hasCloseTag) {
|
||||
console.warn("Partial <think> block detected. Re-generating Groq request...");
|
||||
continue; // This will skip the rest of the loop and try again
|
||||
}
|
||||
finalRes = finalRes.replace(/<\|separator\|>/g, '*no response*');
|
||||
|
||||
return finalRes;
|
||||
// If only the closing tag is present, prepend an opening tag
|
||||
if (hasCloseTag && !hasOpenTag) {
|
||||
res = '<think>' + res;
|
||||
}
|
||||
|
||||
// Remove the complete <think> block (and any content inside) from the response
|
||||
res = res.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
||||
|
||||
finalRes = res;
|
||||
break; // Exit the loop once a valid response is obtained
|
||||
}
|
||||
|
||||
async embed(text) {
|
||||
console.log("There is no support for embeddings in Groq support. However, the following text was provided: " + text);
|
||||
if (finalRes == null) {
|
||||
console.warn("Could not obtain a valid <think> block or normal response after max attempts.");
|
||||
finalRes = "I thought too hard, sorry, try again.";
|
||||
}
|
||||
}
|
||||
|
||||
finalRes = finalRes.replace(/<\|separator\|>/g, '*no response*');
|
||||
return finalRes;
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import { readFileSync, mkdirSync, writeFileSync} from 'fs';
|
||||
import { Examples } from '../utils/examples.js';
|
||||
import { getCommandDocs } from '../agent/commands/index.js';
|
||||
import { getSkillDocs } from '../agent/library/index.js';
|
||||
import { SkillLibrary } from "../agent/library/skill_library.js";
|
||||
import { stringifyTurns } from '../utils/text.js';
|
||||
import { getCommand } from '../agent/commands/index.js';
|
||||
|
@ -245,9 +244,6 @@ export class Prompter {
|
|||
await this.skill_libary.getRelevantSkillDocs(code_task_content, settings.relevant_docs_count)
|
||||
);
|
||||
}
|
||||
prompt = prompt.replaceAll('$COMMAND_DOCS', getCommandDocs());
|
||||
if (prompt.includes('$CODE_DOCS'))
|
||||
prompt = prompt.replaceAll('$CODE_DOCS', getSkillDocs());
|
||||
if (prompt.includes('$EXAMPLES') && examples !== null)
|
||||
prompt = prompt.replaceAll('$EXAMPLES', await examples.createExampleMessage(messages));
|
||||
if (prompt.includes('$MEMORY'))
|
||||
|
|
Loading…
Add table
Reference in a new issue