From 077fa41edbfe264386039b1cb1743f26383ecd65 Mon Sep 17 00:00:00 2001 From: MaxRobinsonTheGreat Date: Wed, 18 Dec 2024 11:21:05 -0600 Subject: [PATCH 1/2] starting new convo ends current one --- profiles/_default.json | 7 +++--- src/agent/commands/actions.js | 19 ++++++++--------- src/agent/conversation.js | 40 +++++++++++++++++++++++------------ src/agent/prompter.js | 3 +++ src/server/public/index.html | 6 +++--- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/profiles/_default.json b/profiles/_default.json index c6a776b..2a67725 100644 --- a/profiles/_default.json +++ b/profiles/_default.json @@ -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\")"} ], [ diff --git a/src/agent/commands/actions.js b/src/agent/commands/actions.js index 2a303d3..2e9bd25 100644 --- a/src/agent/commands/actions.js +++ b/src/agent/commands/actions.js @@ -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); } }, diff --git a/src/agent/conversation.js b/src/agent/conversation.js index 1cd57a3..3d0f759 100644 --- a/src/agent/conversation.js +++ b/src/agent/conversation.js @@ -172,19 +172,21 @@ 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; } - + if (recieved.start) { convo.reset(); this.startConversationFromOtherBot(sender); } - if (convo.ignore_until_start) - return; - + this._clearMonitorTimeouts(); convo.queue(recieved); @@ -230,10 +232,12 @@ class ConversationManager { endConversation(sender) { if (this.convos[sender]) { this.convos[sender].end(); - this._stopMonitor(); - this.activeConversation = null; - if (self_prompter_paused && !this.inConversation()) { - _resumeSelfPrompter(); + if (this.activeConversation.name === sender) { + this._stopMonitor(); + this.activeConversation = null; + if (self_prompter_paused && !this.inConversation()) { + _resumeSelfPrompter(); + } } } } @@ -246,7 +250,15 @@ class ConversationManager { _resumeSelfPrompter(); } } - + + 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)); - self_prompter_paused = false; - agent.self_prompter.start(); + if (self_prompter_paused && !convoManager.inConversation()) { + self_prompter_paused = false; + agent.self_prompter.start(); + } } diff --git a/src/agent/prompter.js b/src/agent/prompter.js index 5c620f0..5f07eb4 100644 --- a/src/agent/prompter.js +++ b/src/agent/prompter.js @@ -230,6 +230,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); diff --git a/src/server/public/index.html b/src/server/public/index.html index 43ada99..1f7951f 100644 --- a/src/server/public/index.html +++ b/src/server/public/index.html @@ -85,9 +85,9 @@ `} - - - `).join('') : + `).join('') + + ` + ` : '
No agents connected
'; }); From a2a3d4a3055f217161fb1766182f8b9ed641b0ea Mon Sep 17 00:00:00 2001 From: Maximus Date: Thu, 26 Dec 2024 16:45:48 -0700 Subject: [PATCH 2/2] added deepseek --- keys.example.json | 3 ++- profiles/deepseek.json | 7 ++++++ settings.js | 1 + src/agent/prompter.js | 5 ++++ src/models/deepseek.js | 56 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 profiles/deepseek.json create mode 100644 src/models/deepseek.js diff --git a/keys.example.json b/keys.example.json index f6939f0..0e3d7dd 100644 --- a/keys.example.json +++ b/keys.example.json @@ -7,5 +7,6 @@ "GROQCLOUD_API_KEY": "", "HUGGINGFACE_API_KEY": "", "QWEN_API_KEY": "", - "XAI_API_KEY": "" + "XAI_API_KEY": "", + "DEEPSEEK_API_KEY": "" } diff --git a/profiles/deepseek.json b/profiles/deepseek.json new file mode 100644 index 0000000..ddae9bb --- /dev/null +++ b/profiles/deepseek.json @@ -0,0 +1,7 @@ +{ + "name": "deepseek", + + "model": "deepseek-chat", + + "embedding": "openai" +} \ No newline at end of file diff --git a/settings.js b/settings.js index 4895833..e21eb3e 100644 --- a/settings.js +++ b/settings.js @@ -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 ], diff --git a/src/agent/prompter.js b/src/agent/prompter.js index 5f07eb4..3679fcf 100644 --- a/src/agent/prompter.js +++ b/src/agent/prompter.js @@ -15,6 +15,7 @@ import { GroqCloudAPI } from '../models/groq.js'; import { HuggingFace } from '../models/huggingface.js'; import { Qwen } from "../models/qwen.js"; import { Grok } from "../models/grok.js"; +import { DeepSeek } from '../models/deepseek.js'; export class Prompter { constructor(agent, fp) { @@ -60,6 +61,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'; } @@ -87,6 +90,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); diff --git a/src/models/deepseek.js b/src/models/deepseek.js new file mode 100644 index 0000000..395aa8c --- /dev/null +++ b/src/models/deepseek.js @@ -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.'); + } +} + + +