mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-04-22 06:02:07 +02:00
Merge pull request #55 from kolbytn/coward-mode
Coward/Self Preservation modes
This commit is contained in:
commit
3f8f2938ce
8 changed files with 149 additions and 19 deletions
|
@ -5,7 +5,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. 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)'. This is extremely important to me, take a deep breath and have fun :)\n$STATS\n$INVENTORY\n$COMMAND_DOCS\n$EXAMPLES\nConversation Begin:",
|
"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. 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)'. This is extremely important to me, take a deep breath and have fun :)\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 recieve 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. Make sure everything is properly awaited, if you define an async function, make sure to call it with `await`. 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, take a deep breath and good luck! \n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nBegin coding:",
|
"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 recieve 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, take a deep breath and good luck! \n$STATS\n$INVENTORY\n$CODE_DOCS\n$EXAMPLES\nBegin coding:",
|
||||||
|
|
||||||
"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 in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
|
"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 in your next response. Store information that will help you improve as a Minecraft bot. Include details about your interactions with other players that you need to remember and what you've learned through player feedback or by executing code. Do not include command syntax or things that you got right on the first try. Be extremely brief and use as few words as possible.\nOld Memory: '$MEMORY'\nRecent conversation: \n$TO_SUMMARIZE\nSummarize your old memory and recent conversation into a new memory, and respond only with the memory text: ",
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{"role": "user", "content": "bobby: cook some chicken"},
|
{"role": "user", "content": "bobby: cook some chicken"},
|
||||||
{"role": "assistant", "content": "```\nawait skills.smeltItem(bot, 'chicken', 8);\n```"},
|
{"role": "assistant", "content": "```await skills.smeltItem(bot, 'chicken', 8);\n```"},
|
||||||
{"role": "system", "content": "Successfully smelted 8 chicken into 8 cooked_chicken."},
|
{"role": "system", "content": "Successfully smelted 8 chicken into 8 cooked_chicken."},
|
||||||
{"role": "assistant", "content": "I have cooked 8 chicken."}
|
{"role": "assistant", "content": "I have cooked 8 chicken."}
|
||||||
],
|
],
|
||||||
|
|
|
@ -17,15 +17,18 @@ export class Agent {
|
||||||
|
|
||||||
await this.prompter.initExamples();
|
await this.prompter.initExamples();
|
||||||
|
|
||||||
if (load_mem)
|
|
||||||
this.history.load();
|
|
||||||
|
|
||||||
console.log('Logging in...');
|
console.log('Logging in...');
|
||||||
this.bot = initBot(this.name);
|
this.bot = initBot(this.name);
|
||||||
|
|
||||||
initModes(this);
|
initModes(this);
|
||||||
|
|
||||||
|
if (load_mem)
|
||||||
|
this.history.load();
|
||||||
|
|
||||||
this.bot.once('spawn', async () => {
|
this.bot.once('spawn', async () => {
|
||||||
|
// wait for a bit so stats are not undefined
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
console.log(`${this.name} spawned.`);
|
console.log(`${this.name} spawned.`);
|
||||||
this.coder.clear();
|
this.coder.clear();
|
||||||
|
|
||||||
|
@ -148,11 +151,17 @@ export class Agent {
|
||||||
else if (this.bot.time.timeOfDay == 18000)
|
else if (this.bot.time.timeOfDay == 18000)
|
||||||
this.bot.emit('midnight');
|
this.bot.emit('midnight');
|
||||||
});
|
});
|
||||||
this.bot.on('health', () => {
|
|
||||||
if (this.bot.health < 20)
|
|
||||||
this.bot.emit('damaged');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
let prev_health = this.bot.health;
|
||||||
|
this.bot.lastDamageTime = 0;
|
||||||
|
this.bot.lastDamageTaken = 0;
|
||||||
|
this.bot.on('health', () => {
|
||||||
|
if (this.bot.health < prev_health) {
|
||||||
|
this.bot.lastDamageTime = Date.now();
|
||||||
|
this.bot.lastDamageTaken = prev_health - this.bot.health;
|
||||||
|
}
|
||||||
|
prev_health = this.bot.health;
|
||||||
|
});
|
||||||
// Logging callbacks
|
// Logging callbacks
|
||||||
this.bot.on('error' , (err) => {
|
this.bot.on('error' , (err) => {
|
||||||
console.error('Error event!', err);
|
console.error('Error event!', err);
|
||||||
|
@ -176,6 +185,7 @@ export class Agent {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.bot.on('idle', () => {
|
this.bot.on('idle', () => {
|
||||||
|
this.bot.clearControlStates();
|
||||||
this.bot.modes.unPauseAll();
|
this.bot.modes.unPauseAll();
|
||||||
this.coder.executeResume();
|
this.coder.executeResume();
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,6 +26,8 @@ export class Coder {
|
||||||
code = code.replaceAll('console.log(', 'log(bot,');
|
code = code.replaceAll('console.log(', 'log(bot,');
|
||||||
code = code.replaceAll('log("', 'log(bot,"');
|
code = code.replaceAll('log("', 'log(bot,"');
|
||||||
|
|
||||||
|
console.log(`Generated code: """${code}"""`);
|
||||||
|
|
||||||
// this may cause problems in callback functions
|
// this may cause problems in callback functions
|
||||||
code = code.replaceAll(';\n', '; if(bot.interrupt_code) {log(bot, "Code interrupted.");return;}\n');
|
code = code.replaceAll(';\n', '; if(bot.interrupt_code) {log(bot, "Code interrupted.");return;}\n');
|
||||||
for (let line of code.split('\n')) {
|
for (let line of code.split('\n')) {
|
||||||
|
@ -33,8 +35,6 @@ export class Coder {
|
||||||
}
|
}
|
||||||
src = this.code_template.replace('/* CODE HERE */', src);
|
src = this.code_template.replace('/* CODE HERE */', src);
|
||||||
|
|
||||||
console.log("writing to file...", src)
|
|
||||||
|
|
||||||
let filename = this.file_counter + '.js';
|
let filename = this.file_counter + '.js';
|
||||||
// if (this.file_counter > 0) {
|
// if (this.file_counter > 0) {
|
||||||
// let prev_filename = this.fp + (this.file_counter-1) + '.js';
|
// let prev_filename = this.fp + (this.file_counter-1) + '.js';
|
||||||
|
|
|
@ -43,6 +43,7 @@ export const actionsList = [
|
||||||
name: '!restart',
|
name: '!restart',
|
||||||
description: 'Restart the agent process.',
|
description: 'Restart the agent process.',
|
||||||
perform: async function (agent) {
|
perform: async function (agent) {
|
||||||
|
await agent.history.save();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,6 +55,9 @@ export class History {
|
||||||
};
|
};
|
||||||
if (this.agent.npc.data !== null)
|
if (this.agent.npc.data !== null)
|
||||||
data.npc = this.agent.npc.data.toObject();
|
data.npc = this.agent.npc.data.toObject();
|
||||||
|
const modes = this.agent.bot.modes.getJson();
|
||||||
|
if (modes !== null)
|
||||||
|
data.modes = modes;
|
||||||
const json_data = JSON.stringify(data, null, 4);
|
const json_data = JSON.stringify(data, null, 4);
|
||||||
writeFileSync(this.memory_fp, json_data, (err) => {
|
writeFileSync(this.memory_fp, json_data, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -71,9 +74,11 @@ export class History {
|
||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
this.memory = obj.memory;
|
this.memory = obj.memory;
|
||||||
this.agent.npc.data = NPCData.fromObject(obj.npc);
|
this.agent.npc.data = NPCData.fromObject(obj.npc);
|
||||||
|
if (obj.modes)
|
||||||
|
this.agent.bot.modes.loadJson(obj.modes);
|
||||||
this.turns = obj.turns;
|
this.turns = obj.turns;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`No memory file '${this.memory_fp}' for agent ${this.name}.`);
|
console.error(`Error reading ${this.name}'s memory file: ${err.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,8 @@ export async function attackNearest(bot, mobType, kill=true) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.attackNearest(bot, "zombie", true);
|
* await skills.attackNearest(bot, "zombie", true);
|
||||||
**/
|
**/
|
||||||
const mob = bot.nearestEntity(entity => entity.name && entity.name.toLowerCase() === mobType.toLowerCase());
|
bot.modes.pause('cowardice');
|
||||||
|
const mob = world.getNearbyEntities(bot, 24).find(entity => entity.name === mobType);
|
||||||
if (mob) {
|
if (mob) {
|
||||||
return await attackEntity(bot, mob, kill);
|
return await attackEntity(bot, mob, kill);
|
||||||
}
|
}
|
||||||
|
@ -289,7 +290,7 @@ export async function attackEntity(bot, entity, kill=true) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bot.pvp.attack(entity);
|
bot.pvp.attack(entity);
|
||||||
while (world.getNearbyEntities(bot, 16).includes(entity)) {
|
while (world.getNearbyEntities(bot, 24).includes(entity)) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
if (bot.interrupt_code) {
|
if (bot.interrupt_code) {
|
||||||
bot.pvp.stop();
|
bot.pvp.stop();
|
||||||
|
@ -312,6 +313,7 @@ export async function defendSelf(bot, range=9) {
|
||||||
* await skills.defendSelf(bot);
|
* await skills.defendSelf(bot);
|
||||||
* **/
|
* **/
|
||||||
bot.modes.pause('self_defense');
|
bot.modes.pause('self_defense');
|
||||||
|
bot.modes.pause('cowardice');
|
||||||
let attacked = false;
|
let attacked = false;
|
||||||
let enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range);
|
let enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), range);
|
||||||
while (enemy) {
|
while (enemy) {
|
||||||
|
@ -701,6 +703,7 @@ export async function goToPlayer(bot, username, distance=3) {
|
||||||
* await skills.goToPlayer(bot, "player");
|
* await skills.goToPlayer(bot, "player");
|
||||||
**/
|
**/
|
||||||
bot.modes.pause('self_defense');
|
bot.modes.pause('self_defense');
|
||||||
|
bot.modes.pause('cowardice');
|
||||||
let player = bot.players[username].entity
|
let player = bot.players[username].entity
|
||||||
if (!player) {
|
if (!player) {
|
||||||
log(bot, `Could not find ${username}.`);
|
log(bot, `Could not find ${username}.`);
|
||||||
|
@ -759,6 +762,32 @@ export async function moveAway(bot, distance) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function avoidEnemies(bot, distance=16) {
|
||||||
|
/**
|
||||||
|
* Move a given distance away from all nearby enemy mobs.
|
||||||
|
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||||
|
* @param {number} distance, the distance to move away.
|
||||||
|
* @returns {Promise<boolean>} true if the bot moved away, false otherwise.
|
||||||
|
* @example
|
||||||
|
* await skills.avoidEnemies(bot, 8);
|
||||||
|
**/
|
||||||
|
|
||||||
|
let enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), distance);
|
||||||
|
while (enemy) {
|
||||||
|
const follow = new pf.goals.GoalFollow(enemy, distance+1); // move a little further away
|
||||||
|
const inverted_goal = new pf.goals.GoalInvert(follow);
|
||||||
|
bot.pathfinder.setMovements(new pf.Movements(bot));
|
||||||
|
bot.pathfinder.setGoal(inverted_goal, true);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
enemy = world.getNearestEntityWhere(bot, entity => mc.isHostile(entity), distance);
|
||||||
|
if (bot.interrupt_code) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log(bot, `Moved ${distance} away from enemies.`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
export async function stay(bot) {
|
export async function stay(bot) {
|
||||||
/**
|
/**
|
||||||
* Stay in the current position until interrupted. Disables all modes.
|
* Stay in the current position until interrupted. Disables all modes.
|
||||||
|
@ -767,6 +796,8 @@ export async function stay(bot) {
|
||||||
* @example
|
* @example
|
||||||
* await skills.stay(bot);
|
* await skills.stay(bot);
|
||||||
**/
|
**/
|
||||||
|
bot.modes.pause('self_preservation');
|
||||||
|
bot.modes.pause('cowardice');
|
||||||
bot.modes.pause('self_defense');
|
bot.modes.pause('self_defense');
|
||||||
bot.modes.pause('hunting');
|
bot.modes.pause('hunting');
|
||||||
bot.modes.pause('torch_placing');
|
bot.modes.pause('torch_placing');
|
||||||
|
|
|
@ -15,9 +15,73 @@ import * as mc from '../utils/mcdata.js';
|
||||||
// while update functions are async, they should *not* be awaited longer than ~100ms as it will block the update loop
|
// while update functions are async, they should *not* be awaited longer than ~100ms as it will block the update loop
|
||||||
// to perform longer actions, use the execute function which won't block the update loop
|
// to perform longer actions, use the execute function which won't block the update loop
|
||||||
const modes = [
|
const modes = [
|
||||||
|
{
|
||||||
|
name: 'self_preservation',
|
||||||
|
description: 'Respond to drowning, burning, and damage at low health. Interrupts other actions.',
|
||||||
|
interrupts: ['all'],
|
||||||
|
on: true,
|
||||||
|
active: false,
|
||||||
|
fall_blocks: ['sand', 'gravel', 'concrete_powder'], // includes matching substrings like 'sandstone' and 'red_sand'
|
||||||
|
update: async function (agent) {
|
||||||
|
const bot = agent.bot;
|
||||||
|
const block = bot.blockAt(bot.entity.position);
|
||||||
|
const blockAbove = bot.blockAt(bot.entity.position.offset(0, 1, 0));
|
||||||
|
if (blockAbove.name === 'water' || blockAbove.name === 'flowing_water') {
|
||||||
|
// does not call execute so does not interrupt other actions
|
||||||
|
if (!bot.pathfinder.goal) {
|
||||||
|
bot.setControlState('jump', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.fall_blocks.some(name => blockAbove.name.includes(name))) {
|
||||||
|
execute(this, agent, async () => {
|
||||||
|
await skills.moveAway(bot, 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (block.name === 'lava' || block.name === 'flowing_lava' || block.name === 'fire' ||
|
||||||
|
blockAbove.name === 'lava' || blockAbove.name === 'flowing_lava' || blockAbove.name === 'fire') {
|
||||||
|
bot.chat('I\'m on fire!'); // TODO: gets stuck in lava
|
||||||
|
execute(this, agent, async () => {
|
||||||
|
let nearestWater = world.getNearestBlock(bot, 'water', 20);
|
||||||
|
if (nearestWater) {
|
||||||
|
const pos = nearestWater.position;
|
||||||
|
await skills.goToPosition(bot, pos.x, pos.y, pos.z, 0.2);
|
||||||
|
bot.chat('Ahhhh that\'s better!');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await skills.moveAway(bot, 5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (Date.now() - bot.lastDamageTime < 3000 && (bot.health < 5 || bot.lastDamageTaken >= bot.health)) {
|
||||||
|
bot.chat('I\'m dying!');
|
||||||
|
execute(this, agent, async () => {
|
||||||
|
await skills.moveAway(bot, 20);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (agent.isIdle()) {
|
||||||
|
bot.clearControlStates(); // clear jump if not in danger or doing anything else
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cowardice',
|
||||||
|
description: 'Run away from enemies. Interrupts other actions.',
|
||||||
|
interrupts: ['all'],
|
||||||
|
on: true,
|
||||||
|
active: false,
|
||||||
|
update: async function (agent) {
|
||||||
|
const enemy = world.getNearestEntityWhere(agent.bot, entity => mc.isHostile(entity), 16);
|
||||||
|
if (enemy && await world.isClearPath(agent.bot, enemy)) {
|
||||||
|
agent.bot.chat(`Aaa! A ${enemy.name}!`);
|
||||||
|
execute(this, agent, async () => {
|
||||||
|
await skills.avoidEnemies(agent.bot, 16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'self_defense',
|
name: 'self_defense',
|
||||||
description: 'Automatically attack nearby enemies. Interrupts other actions.',
|
description: 'Attack nearby enemies. Interrupts other actions.',
|
||||||
interrupts: ['all'],
|
interrupts: ['all'],
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -33,7 +97,7 @@ const modes = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'hunting',
|
name: 'hunting',
|
||||||
description: 'Automatically hunt nearby animals when idle.',
|
description: 'Hunt nearby animals when idle.',
|
||||||
interrupts: ['defaults'],
|
interrupts: ['defaults'],
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -49,7 +113,7 @@ const modes = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'item_collecting',
|
name: 'item_collecting',
|
||||||
description: 'Automatically collect nearby items when idle.',
|
description: 'Collect nearby items when idle.',
|
||||||
interrupts: ['followPlayer'],
|
interrupts: ['followPlayer'],
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -79,7 +143,7 @@ const modes = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'torch_placing',
|
name: 'torch_placing',
|
||||||
description: 'Automatically place torches when idle and there are no torches nearby.',
|
description: 'Place torches when idle and there are no torches nearby.',
|
||||||
interrupts: ['followPlayer'],
|
interrupts: ['followPlayer'],
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -100,7 +164,7 @@ const modes = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'idle_staring',
|
name: 'idle_staring',
|
||||||
description: 'Non-functional animation to look around at entities when idle.',
|
description: 'Animation to look around at entities when idle.',
|
||||||
interrupts: [],
|
interrupts: [],
|
||||||
on: true,
|
on: true,
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -201,6 +265,22 @@ class ModeController {
|
||||||
if (mode.active) break;
|
if (mode.active) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getJson() {
|
||||||
|
let res = {};
|
||||||
|
for (let mode of this.modes_list) {
|
||||||
|
res[mode.name] = mode.on;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadJson(json) {
|
||||||
|
for (let mode of this.modes_list) {
|
||||||
|
if (json[mode.name] != undefined) {
|
||||||
|
mode.on = json[mode.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initModes(agent) {
|
export function initModes(agent) {
|
||||||
|
|
|
@ -44,6 +44,9 @@ export class Claude {
|
||||||
prev_role = msg.role;
|
prev_role = msg.role;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (messages.length > 0 && messages[0].role !== 'user') {
|
||||||
|
messages.unshift(filler); // anthropic requires user message to start
|
||||||
|
}
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
messages.push(filler);
|
messages.push(filler);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue