Merge remote-tracking branch 'refs/remotes/upstream/main' into Tasks-more-relevant-docs-and-code-exception-fixes

# Conflicts:
#	src/agent/prompter.js
This commit is contained in:
“Qu 2025-01-04 12:30:28 +08:00
commit 2127e5b9fb
9 changed files with 118 additions and 33 deletions

View file

@ -7,5 +7,6 @@
"GROQCLOUD_API_KEY": "",
"HUGGINGFACE_API_KEY": "",
"QWEN_API_KEY": "",
"XAI_API_KEY": ""
"XAI_API_KEY": "",
"DEEPSEEK_API_KEY": ""
}

View file

@ -38,10 +38,9 @@
],
[
{"role": "system", "content": "work together with the other bot"},
{"role": "assistant", "content": "!startConversation(\"terrance\", \"Hey gpt! Let's work together on this.\"))"},
{"role": "user", "content": "terrance: (FROM OTHER BOT)Sounds good, what should we do first?"},
{"role": "assistant", "content": "I'll start by collecting some resources. !collectBlocks('stone', 10)"}
{"role": "system", "content": "work together with the other bot to build a house"},
{"role": "assistant", "content": "!startConversation(\"terrance\", \"Hey gpt! Let's work together to build a house. Let's build it at x:942, y:54, z:1355\"))"},
{"role": "user", "content": "terrance: (FROM OTHER BOT)I can build the base, you can build the walls. !newAction(\"Build a 10x10 wall of a house at x:942, y:54, z:1355\")"}
],
[

7
profiles/deepseek.json Normal file
View file

@ -0,0 +1,7 @@
{
"name": "deepseek",
"model": "deepseek-chat",
"embedding": "openai"
}

View file

@ -18,6 +18,7 @@ export default
// "./profiles/llama.json",
// "./profiles/qwen.json",
// "./profiles/grok.json",
// "./profiles/deepseek.json",
// using more than 1 profile requires you to /msg each bot indivually
],

View file

@ -266,13 +266,12 @@ export const actionsList = [
'num': { type: 'int', description: 'The number of times to smelt the item.', domain: [1, Number.MAX_SAFE_INTEGER] }
},
perform: runAsAction(async (agent, item_name, num) => {
let response = await skills.smeltItem(agent.bot, item_name, num);
if (response.indexOf('Successfully') !== -1) {
// there is a bug where the bot's inventory is not updated after smelting
// only updates after a restart
agent.cleanKill(response + ' Safely restarting to update inventory.');
let success = await skills.smeltItem(agent.bot, item_name, num);
if (success) {
setTimeout(() => {
agent.cleanKill('Safely restarting to update inventory.');
}, 500);
}
return response;
})
},
{
@ -386,12 +385,12 @@ export const actionsList = [
'message': { type: 'string', description: 'The message to send.' },
},
perform: async function (agent, player_name, message) {
if (convoManager.inConversation() && !convoManager.inConversation(player_name))
return 'You are already in conversation with other bot.';
if (!convoManager.isOtherAgent(player_name))
return player_name + ' is not a bot, cannot start conversation.';
if (convoManager.inConversation(player_name))
agent.history.add('system', 'You are already in conversation with ' + player_name + ' Don\'t use this command to talk to them.');
if (convoManager.inConversation() && !convoManager.inConversation(player_name))
convoManager.forceEndCurrentConversation();
else if (convoManager.inConversation(player_name))
agent.history.add('system', 'You are already in conversation with ' + player_name + '. Don\'t use this command to talk to them.');
convoManager.startConversation(player_name, message);
}
},

View file

@ -172,9 +172,13 @@ class ConversationManager {
async recieveFromBot(sender, recieved) {
const convo = this._getConvo(sender);
if (convo.ignore_until_start && !recieved.start)
return;
// check if any convo is active besides the sender
if (Object.values(this.convos).some(c => c.active && c.name !== sender)) {
if (this.inConversation() && !this.inConversation(sender)) {
this.sendToBot(sender, `I'm talking to someone else, try again later. !endConversation("${sender}")`, false, false);
this.endConversation(sender);
return;
}
@ -182,8 +186,6 @@ class ConversationManager {
convo.reset();
this.startConversationFromOtherBot(sender);
}
if (convo.ignore_until_start)
return;
this._clearMonitorTimeouts();
convo.queue(recieved);
@ -230,6 +232,7 @@ class ConversationManager {
endConversation(sender) {
if (this.convos[sender]) {
this.convos[sender].end();
if (this.activeConversation.name === sender) {
this._stopMonitor();
this.activeConversation = null;
if (self_prompter_paused && !this.inConversation()) {
@ -237,6 +240,7 @@ class ConversationManager {
}
}
}
}
endAllConversations() {
for (const sender in this.convos) {
@ -247,6 +251,14 @@ class ConversationManager {
}
}
forceEndCurrentConversation() {
if (this.activeConversation) {
let sender = this.activeConversation.name;
this.sendToBot(sender, '!endConversation("' + sender + '")', false, false);
this.endConversation(sender);
}
}
scheduleSelfPrompter() {
self_prompter_paused = true;
}
@ -332,8 +344,8 @@ function _handleFullInMessage(sender, recieved) {
let message = _tagMessage(recieved.message);
if (recieved.end) {
convoManager.endConversation(sender);
sender = 'system'; // bot will respond to system instead of the other bot
message = `Conversation with ${sender} ended with message: "${message}"`;
sender = 'system'; // bot will respond to system instead of the other bot
}
else if (recieved.start)
agent.shut_up = false;
@ -348,6 +360,8 @@ function _tagMessage(message) {
async function _resumeSelfPrompter() {
await new Promise(resolve => setTimeout(resolve, 5000));
if (self_prompter_paused && !convoManager.inConversation()) {
self_prompter_paused = false;
agent.self_prompter.start();
}
}

View file

@ -17,6 +17,7 @@ import { Qwen } from "../models/qwen.js";
import { Grok } from "../models/grok.js";
// import {cosineSimilarity} from "../utils/math.js";
import {SkillLibrary} from "./library/skill_library.js";
import { DeepSeek } from '../models/deepseek.js';
export class Prompter {
constructor(agent, fp) {
@ -32,7 +33,6 @@ export class Prompter {
this.convo_examples = null;
this.coding_examples = null;
let name = this.profile.name;
let chat = this.profile.model;
this.cooldown = this.profile.cooldown ? this.profile.cooldown : 0;
@ -63,6 +63,8 @@ export class Prompter {
chat.api = 'qwen';
else if (chat.model.includes('grok'))
chat.api = 'xai';
else if (chat.model.includes('deepseek'))
chat.api = 'deepseek';
else
chat.api = 'ollama';
}
@ -90,6 +92,8 @@ export class Prompter {
this.chat_model = new Qwen(chat.model, chat.url);
else if (chat.api === 'xai')
this.chat_model = new Grok(chat.model, chat.url);
else if (chat.api === 'deepseek')
this.chat_model = new DeepSeek(chat.model, chat.url);
else
throw new Error('Unknown API:', api);
@ -162,6 +166,7 @@ export class Prompter {
throw error;
}
}
async replaceStrings(prompt, messages, examples=null, to_summarize=[], last_goals=null) {
prompt = prompt.replaceAll('$NAME', this.agent.name);
@ -241,6 +246,9 @@ export class Prompter {
let current_msg_time = this.most_recent_msg_time;
for (let i = 0; i < 3; i++) { // try 3 times to avoid hallucinations
await this.checkCooldown();
if (current_msg_time !== this.most_recent_msg_time) {
return '';
}
let prompt = this.profile.conversing;
prompt = await this.replaceStrings(prompt, messages, this.convo_examples);
let generation = await this.chat_model.sendRequest(messages, prompt);

56
src/models/deepseek.js Normal file
View file

@ -0,0 +1,56 @@
import OpenAIApi from 'openai';
import { getKey, hasKey } from '../utils/keys.js';
import { strictFormat } from '../utils/text.js';
export class DeepSeek {
constructor(model_name, url) {
this.model_name = model_name;
let config = {};
config.baseURL = url || 'https://api.deepseek.com';
config.apiKey = getKey('DEEPSEEK_API_KEY');
this.openai = new OpenAIApi(config);
}
async sendRequest(turns, systemMessage, stop_seq='***') {
let messages = [{'role': 'system', 'content': systemMessage}].concat(turns);
messages = strictFormat(messages);
const pack = {
model: this.model_name || "deepseek-chat",
messages,
stop: stop_seq,
};
let res = null;
try {
console.log('Awaiting deepseek api response...')
// console.log('Messages:', messages);
let completion = await this.openai.chat.completions.create(pack);
if (completion.choices[0].finish_reason == 'length')
throw new Error('Context length exceeded');
console.log('Received.')
res = completion.choices[0].message.content;
}
catch (err) {
if ((err.message == 'Context length exceeded' || err.code == 'context_length_exceeded') && turns.length > 1) {
console.log('Context length exceeded, trying again with shorter context.');
return await this.sendRequest(turns.slice(1), systemMessage, stop_seq);
} else {
console.log(err);
res = 'My brain disconnected, try again.';
}
}
return res;
}
async embed(text) {
throw new Error('Embeddings are not supported by Deepseek.');
}
}

View file

@ -85,9 +85,9 @@
`}
</div>
</div>
<button class="stop-btn" onclick="killAllAgents()">Stop All</button>
<button class="stop-btn" onclick="shutdown()">Shutdown</button>
`).join('') :
`).join('') +
`<button class="stop-btn" onclick="killAllAgents()">Stop All</button>
<button class="stop-btn" onclick="shutdown()">Shutdown</button>` :
'<div class="agent">No agents connected</div>';
});