From 1417f0b485ab5940aa4e30064e08e2ea9537bdd5 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sat, 2 Nov 2024 19:37:05 +1100 Subject: [PATCH 1/8] mods --- core/src/clients/discord/index.ts | 9 +++++++-- core/src/clients/twitter/generate.ts | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/src/clients/discord/index.ts b/core/src/clients/discord/index.ts index a0a9f70d09a..bb2d5eabdca 100644 --- a/core/src/clients/discord/index.ts +++ b/core/src/clients/discord/index.ts @@ -37,7 +37,9 @@ export class DiscordClient extends EventEmitter { constructor(runtime: IAgentRuntime) { super(); - this.apiToken = runtime.getSetting("DISCORD_API_TOKEN") as string; + this.apiToken = runtime.getSetting( + "DISCORD_API_TOKEN_" + runtime.character.name.toUpperCase() + ) as string; this.client = new Client({ intents: [ GatewayIntentBits.Guilds, @@ -120,7 +122,10 @@ export class DiscordClient extends EventEmitter { try { await rest.put( Routes.applicationCommands( - this.runtime.getSetting("DISCORD_APPLICATION_ID") + this.runtime.getSetting( + "DISCORD_APPLICATION_ID_" + + this.runtime.character.name.toUpperCase() + ) ), { body: commands } ); diff --git a/core/src/clients/twitter/generate.ts b/core/src/clients/twitter/generate.ts index af8148821fa..f2de43b9aa9 100644 --- a/core/src/clients/twitter/generate.ts +++ b/core/src/clients/twitter/generate.ts @@ -109,7 +109,7 @@ export class TwitterGenerationClient extends ClientBase { const newTweetContent = await generateText({ runtime: this.runtime, context, - modelClass: ModelClass.LARGE, + modelClass: ModelClass.SMALL, }); console.log("New Tweet:", newTweetContent); log_to_file( From 46139a16568e58f85efd49e2acd21990647a6146 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sat, 2 Nov 2024 20:31:34 +1100 Subject: [PATCH 2/8] fix anthropic --- core/src/core/generation.ts | 128 ++++++++++++++++++------------------ core/src/core/models.ts | 12 ++-- 2 files changed, 69 insertions(+), 71 deletions(-) diff --git a/core/src/core/generation.ts b/core/src/core/generation.ts index 0191676978a..79bf2729778 100644 --- a/core/src/core/generation.ts +++ b/core/src/core/generation.ts @@ -13,7 +13,8 @@ import models from "./models.ts"; import { generateText as aiGenerateText } from "ai"; import { createAnthropicVertex } from "anthropic-vertex-ai"; - +import Anthropic from "@anthropic-ai/sdk"; +import { createAnthropic } from "@ai-sdk/anthropic"; /** * Send a message to the model for a text generateText - receive a string back and parse how you'd like * @param opts - The options for the generateText request. @@ -68,64 +69,62 @@ export async function generateText({ switch (provider) { case ModelProvider.OPENAI: - case ModelProvider.LLAMACLOUD: - { - console.log("Initializing OpenAI model."); - const openai = createOpenAI({ apiKey }); - - const { text: openaiResponse } = await aiGenerateText({ - model: openai.languageModel(model), - prompt: context, - temperature: temperature, - maxTokens: max_response_length, - frequencyPenalty: frequency_penalty, - presencePenalty: presence_penalty, - }); - - response = openaiResponse; - console.log("Received response from OpenAI model."); - break; - } - - case ModelProvider.ANTHROPIC: - { - console.log("Initializing Anthropic model."); - const anthropicVertex = createAnthropicVertex(); - - const { text: anthropicResponse } = await aiGenerateText({ - model: anthropicVertex(model), - prompt: context, - temperature: temperature, - maxTokens: max_response_length, - frequencyPenalty: frequency_penalty, - presencePenalty: presence_penalty, - }); - - response = anthropicResponse; - console.log("Received response from Anthropic model."); - break; - } - - case ModelProvider.GROK: - { - console.log("Initializing Grok model."); - const grok = createGroq({ apiKey }); - - const { text: grokResponse } = await aiGenerateText({ - model: grok.languageModel(model, { - parallelToolCalls: false, - }), - prompt: context, - temperature: temperature, - maxTokens: max_response_length, - frequencyPenalty: frequency_penalty, - presencePenalty: presence_penalty, - }); - - response = grokResponse; - console.log("Received response from Grok model."); - break; - } + case ModelProvider.LLAMACLOUD: { + console.log("Initializing OpenAI model."); + const openai = createOpenAI({ apiKey }); + + const { text: openaiResponse } = await aiGenerateText({ + model: openai.languageModel(model), + prompt: context, + temperature: temperature, + maxTokens: max_response_length, + frequencyPenalty: frequency_penalty, + presencePenalty: presence_penalty, + }); + + response = openaiResponse; + console.log("Received response from OpenAI model."); + break; + } + + case ModelProvider.ANTHROPIC: { + console.log("Initializing Anthropic model."); + + const anthropic = createAnthropic({ apiKey }); + + const { text: anthropicResponse } = await aiGenerateText({ + model: anthropic.languageModel(model), + prompt: context, + temperature: temperature, + maxTokens: max_response_length, + frequencyPenalty: frequency_penalty, + presencePenalty: presence_penalty, + }); + + response = anthropicResponse; + console.log("Received response from Anthropic model."); + break; + } + + case ModelProvider.GROK: { + console.log("Initializing Grok model."); + const grok = createGroq({ apiKey }); + + const { text: grokResponse } = await aiGenerateText({ + model: grok.languageModel(model, { + parallelToolCalls: false, + }), + prompt: context, + temperature: temperature, + maxTokens: max_response_length, + frequencyPenalty: frequency_penalty, + presencePenalty: presence_penalty, + }); + + response = grokResponse; + console.log("Received response from Grok model."); + break; + } case ModelProvider.LLAMALOCAL: console.log("Using local Llama model for text completion."); @@ -140,12 +139,11 @@ export async function generateText({ console.log("Received response from local Llama model."); break; - default: - { - const errorMessage = `Unsupported provider: ${provider}`; - console.error(errorMessage); - throw new Error(errorMessage); - } + default: { + const errorMessage = `Unsupported provider: ${provider}`; + console.error(errorMessage); + throw new Error(errorMessage); + } } return response; diff --git a/core/src/core/models.ts b/core/src/core/models.ts index 1c973bca07a..b04b8893b21 100644 --- a/core/src/core/models.ts +++ b/core/src/core/models.ts @@ -40,9 +40,9 @@ const models: Models = { }, endpoint: "https://api.anthropic.com/v1", model: { - [ModelClass.SMALL]: "claude-3-haiku", - [ModelClass.MEDIUM]: "claude-3-5-sonnet", - [ModelClass.LARGE]: "claude-3-opus", + [ModelClass.SMALL]: "claude-3-5-sonnet-20241022", + [ModelClass.MEDIUM]: "claude-3-5-sonnet-20241022", + [ModelClass.LARGE]: "claude-3-opus-20240229", }, }, [ModelProvider.CLAUDE_VERTEX]: { @@ -56,9 +56,9 @@ const models: Models = { }, endpoint: "https://api.anthropic.com/v1", // TODO: check model: { - [ModelClass.SMALL]: "claude-3-haiku", - [ModelClass.MEDIUM]: "claude-3-5-sonnet", - [ModelClass.LARGE]: "claude-3-opus", + [ModelClass.SMALL]: "claude-3-5-sonnet-20241022", + [ModelClass.MEDIUM]: "claude-3-5-sonnet-20241022", + [ModelClass.LARGE]: "claude-3-opus-20240229", }, }, [ModelProvider.GROK]: { From 880e5ac981b9298fd3fc385f0694f2b45b95c5e5 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sun, 3 Nov 2024 16:36:01 +1100 Subject: [PATCH 3/8] prettier logs, some minor cleanups --- core/src/actions/imageGeneration.ts | 21 ++ core/src/adapters/sqlite/sqlite_vec.ts | 5 +- core/src/cli/colors.ts | 268 ++++++++++++++++++ core/src/cli/config.ts | 5 +- core/src/cli/index.ts | 33 ++- core/src/clients/telegram/src/index.ts | 38 +-- .../clients/telegram/src/messageManager.ts | 8 +- core/src/clients/twitter/base.ts | 7 +- core/src/clients/twitter/utils.ts | 9 +- core/src/core/generation.ts | 67 ++--- core/src/core/runtime.ts | 8 +- core/src/index.ts | 12 +- 12 files changed, 404 insertions(+), 77 deletions(-) create mode 100644 core/src/cli/colors.ts diff --git a/core/src/actions/imageGeneration.ts b/core/src/actions/imageGeneration.ts index 0ee3c879b65..208e8265dbc 100644 --- a/core/src/actions/imageGeneration.ts +++ b/core/src/actions/imageGeneration.ts @@ -5,6 +5,7 @@ import { State, Action, } from "../core/types.ts"; +import { prettyConsole } from "../index.ts"; import { generateCaption, generateImage } from "./imageGenerationUtils.ts"; export const imageGeneration: Action = { @@ -23,11 +24,16 @@ export const imageGeneration: Action = { options: any, callback: HandlerCallback ) => { + prettyConsole.log("Composing state for message:", message); state = (await runtime.composeState(message)) as State; const userId = runtime.agentId; + prettyConsole.log("User ID:", userId); const imagePrompt = message.content.text; + prettyConsole.log("Image prompt received:", imagePrompt); const res: { image: string; caption: string }[] = []; + + prettyConsole.log("Generating image with prompt:", imagePrompt); const images = await generateImage( { prompt: imagePrompt, @@ -37,16 +43,29 @@ export const imageGeneration: Action = { }, runtime ); + if (images.success && images.data && images.data.length > 0) { + prettyConsole.log( + "Image generation successful, number of images:", + images.data.length + ); for (let i = 0; i < images.data.length; i++) { const image = images.data[i]; + prettyConsole.log(`Processing image ${i + 1}:`, image); + const caption = await generateCaption( { imageUrl: image, }, runtime ); + + prettyConsole.log( + `Generated caption for image ${i + 1}:`, + caption.title + ); res.push({ image: image, caption: caption.title }); + callback( { text: caption.description, @@ -64,6 +83,8 @@ export const imageGeneration: Action = { [] ); } + } else { + prettyConsole.error("Image generation failed or returned no data."); } }, examples: [ diff --git a/core/src/adapters/sqlite/sqlite_vec.ts b/core/src/adapters/sqlite/sqlite_vec.ts index 57429ae188d..2f159d22f99 100644 --- a/core/src/adapters/sqlite/sqlite_vec.ts +++ b/core/src/adapters/sqlite/sqlite_vec.ts @@ -1,14 +1,15 @@ import * as sqliteVec from "sqlite-vec"; import { Database } from "better-sqlite3"; +import { prettyConsole } from "../../index.ts"; // Loads the sqlite-vec extensions into the provided SQLite database export function loadVecExtensions(db: Database): void { try { // Load sqlite-vec extensions sqliteVec.load(db); - console.log("sqlite-vec extensions loaded successfully."); + prettyConsole.log("sqlite-vec extensions loaded successfully."); } catch (error) { - console.error("Failed to load sqlite-vec extensions:", error); + prettyConsole.error("Failed to load sqlite-vec extensions:", error); throw error; } } diff --git a/core/src/cli/colors.ts b/core/src/cli/colors.ts new file mode 100644 index 00000000000..86209c1ebbd --- /dev/null +++ b/core/src/cli/colors.ts @@ -0,0 +1,268 @@ +export class PrettyConsole { + closeByNewLine = true; + useIcons = true; + logsTitle = "LOGS"; + warningsTitle = "WARNINGS"; + errorsTitle = "ERRORS"; + informationsTitle = "INFORMATIONS"; + successesTitle = "SUCCESS"; + debugsTitle = "DEBUG"; + assertsTitle = "ASSERT"; + #getColor(foregroundColor = "", backgroundColor = "") { + let fgc = "\x1b[37m"; + switch (foregroundColor.trim().toLowerCase()) { + case "black": + fgc = "\x1b[30m"; + break; + case "red": + fgc = "\x1b[31m"; + break; + case "green": + fgc = "\x1b[32m"; + break; + case "yellow": + fgc = "\x1b[33m"; + break; + case "blue": + fgc = "\x1b[34m"; + break; + case "magenta": + fgc = "\x1b[35m"; + break; + case "cyan": + fgc = "\x1b[36m"; + break; + case "white": + fgc = "\x1b[37m"; + break; + } + + let bgc = ""; + switch (backgroundColor.trim().toLowerCase()) { + case "black": + bgc = "\x1b[40m"; + break; + case "red": + bgc = "\x1b[44m"; + break; + case "green": + bgc = "\x1b[44m"; + break; + case "yellow": + bgc = "\x1b[43m"; + break; + case "blue": + bgc = "\x1b[44m"; + break; + case "magenta": + bgc = "\x1b[45m"; + break; + case "cyan": + bgc = "\x1b[46m"; + break; + case "white": + bgc = "\x1b[47m"; + break; + } + + return `${fgc}${bgc}`; + } + #getColorReset() { + return "\x1b[0m"; + } + clear() { + console.clear(); + } + print(foregroundColor = "white", backgroundColor = "black", ...strings) { + const c = this.#getColor(foregroundColor, backgroundColor); + // turns objects into printable strings + strings = strings.map((item) => { + if (typeof item === "object") item = JSON.stringify(item); + return item; + }); + console.log(c, strings.join(""), this.#getColorReset()); + if (this.closeByNewLine) console.log(""); + } + log(...strings) { + const fg = "white"; + const bg = ""; + const icon = "\u25ce"; + const groupTile = ` ${this.logsTitle}`; + if (strings.length > 1) { + const c = this.#getColor(fg, bg); + console.group(c, (this.useIcons ? icon : "") + groupTile); + const nl = this.closeByNewLine; + this.closeByNewLine = false; + strings.forEach((item) => { + this.print(fg, bg, item, this.#getColorReset()); + }); + this.closeByNewLine = nl; + console.groupEnd(); + if (nl) console.log(); + } else { + this.print( + fg, + bg, + strings.map((item) => { + return `${this.useIcons ? `${icon} ` : ""}${item}`; + }) + ); + } + } + warn(...strings) { + const fg = "yellow"; + const bg = ""; + const icon = "\u26a0"; + const groupTile = ` ${this.warningsTitle}`; + if (strings.length > 1) { + const c = this.#getColor(fg, bg); + console.group(c, (this.useIcons ? icon : "") + groupTile); + const nl = this.closeByNewLine; + this.closeByNewLine = false; + strings.forEach((item) => { + this.print(fg, bg, item, this.#getColorReset()); + }); + this.closeByNewLine = nl; + console.groupEnd(); + if (nl) console.log(); + } else { + this.print( + fg, + bg, + strings.map((item) => { + return `${this.useIcons ? `${icon} ` : ""}${item}`; + }) + ); + } + } + error(...strings) { + const fg = "red"; + const bg = ""; + const icon = "\u26D4"; + const groupTile = ` ${this.errorsTitle}`; + if (strings.length > 1) { + const c = this.#getColor(fg, bg); + console.group(c, (this.useIcons ? icon : "") + groupTile); + const nl = this.closeByNewLine; + this.closeByNewLine = false; + strings.forEach((item) => { + this.print(fg, bg, item); + }); + this.closeByNewLine = nl; + console.groupEnd(); + if (nl) console.log(); + } else { + this.print( + fg, + bg, + strings.map((item) => { + return `${this.useIcons ? `${icon} ` : ""}${item}`; + }) + ); + } + } + info(...strings) { + const fg = "blue"; + const bg = ""; + const icon = "\u2139"; + const groupTile = ` ${this.informationsTitle}`; + if (strings.length > 1) { + const c = this.#getColor(fg, bg); + console.group(c, (this.useIcons ? icon : "") + groupTile); + const nl = this.closeByNewLine; + this.closeByNewLine = false; + strings.forEach((item) => { + this.print(fg, bg, item); + }); + this.closeByNewLine = nl; + console.groupEnd(); + if (nl) console.log(); + } else { + this.print( + fg, + bg, + strings.map((item) => { + return `${this.useIcons ? `${icon} ` : ""}${item}`; + }) + ); + } + } + success(...strings) { + const fg = "green"; + const bg = ""; + const icon = "\u2713"; + const groupTile = ` ${this.successesTitle}`; + if (strings.length > 1) { + const c = this.#getColor(fg, bg); + console.group(c, (this.useIcons ? icon : "") + groupTile); + const nl = this.closeByNewLine; + this.closeByNewLine = false; + strings.forEach((item) => { + this.print(fg, bg, item); + }); + this.closeByNewLine = nl; + console.groupEnd(); + if (nl) console.log(); + } else { + this.print( + fg, + bg, + strings.map((item) => { + return `${this.useIcons ? `${icon} ` : ""}${item}`; + }) + ); + } + } + debug(...strings) { + const fg = "magenta"; + const bg = ""; + const icon = "\u1367"; + const groupTile = ` ${this.debugsTitle}`; + if (strings.length > 1) { + const c = this.#getColor(fg, bg); + console.group(c, (this.useIcons ? icon : "") + groupTile); + const nl = this.closeByNewLine; + this.closeByNewLine = false; + strings.forEach((item) => { + this.print(fg, bg, item); + }); + this.closeByNewLine = nl; + console.groupEnd(); + if (nl) console.log(); + } else { + this.print( + fg, + bg, + strings.map((item) => { + return `${this.useIcons ? `${icon} ` : ""}${item}`; + }) + ); + } + } + assert(...strings) { + const fg = "cyan"; + const bg = ""; + const icon = "\u0021"; + const groupTile = ` ${this.assertsTitle}`; + if (strings.length > 1) { + const c = this.#getColor(fg, bg); + console.group(c, (this.useIcons ? icon : "") + groupTile); + const nl = this.closeByNewLine; + this.closeByNewLine = false; + strings.forEach((item) => { + this.print(fg, bg, item); + }); + this.closeByNewLine = nl; + console.groupEnd(); + if (nl) console.log(); + } else { + this.print( + fg, + bg, + strings.map((item) => { + return `${this.useIcons ? `${icon} ` : ""}${item}`; + }) + ); + } + } +} diff --git a/core/src/cli/config.ts b/core/src/cli/config.ts index 05b7bda964e..7162f8e1e15 100644 --- a/core/src/cli/config.ts +++ b/core/src/cli/config.ts @@ -3,6 +3,7 @@ import yaml from "js-yaml"; import path from "path"; import { fileURLToPath } from "url"; import { Action } from "../core/types"; +import { prettyConsole } from "../index.ts"; const ROOT_DIR = path.resolve(fileURLToPath(import.meta.url), "../../../src"); @@ -29,13 +30,13 @@ export async function loadCustomActions( for (const config of actionConfigs) { const resolvedPath = path.resolve(ROOT_DIR, config.path); - console.log(`Importing action from: ${resolvedPath}`); // Debugging log + prettyConsole.log(`Importing action from: ${resolvedPath}`); // Debugging log try { const actionModule = await import(resolvedPath); actions.push(actionModule[config.name]); } catch (error) { - console.error( + prettyConsole.error( `Failed to import action from ${resolvedPath}:`, error ); diff --git a/core/src/cli/index.ts b/core/src/cli/index.ts index 90c5ef46d41..953bd04adb4 100644 --- a/core/src/cli/index.ts +++ b/core/src/cli/index.ts @@ -14,6 +14,7 @@ import { AgentRuntime } from "../core/runtime.ts"; import { defaultActions } from "../core/actions.ts"; import { Arguments } from "../types/index.ts"; import { loadActionConfigs, loadCustomActions } from "./config.ts"; +import { prettyConsole } from "../index.ts"; export async function initializeClients( character: Character, @@ -149,11 +150,16 @@ export async function createAgentRuntime( }); } -export function createDirectRuntime( +export async function createDirectRuntime( character: Character, db: any, - token: string + token: string, + configPath: string = "./elizaConfig.yaml" ) { + const actionConfigs = loadActionConfigs(configPath); + const customActions = await loadCustomActions(actionConfigs); + + console.log("Creating runtime for character", character.name); return new AgentRuntime({ databaseAdapter: db, token, @@ -161,7 +167,18 @@ export function createDirectRuntime( evaluators: [], character, providers: [Provider.timeProvider, Provider.boredomProvider], - actions: [...defaultActions], + actions: [ + ...defaultActions, + // Custom actions + Action.followRoom, + Action.unfollowRoom, + Action.unmuteRoom, + Action.muteRoom, + Action.imageGeneration, + + // imported from elizaConfig.yaml + ...customActions, + ], }); } @@ -173,11 +190,11 @@ export async function startTelegram( runtime: IAgentRuntime, character: Character ) { - console.log("🔍 Attempting to start Telegram bot..."); + prettyConsole.log("🔍 Attempting to start Telegram bot..."); const botToken = runtime.getSetting("TELEGRAM_BOT_TOKEN"); if (!botToken) { - console.error( + prettyConsole.error( `❌ Telegram bot token is not set for character ${character.name}.` ); return null; @@ -186,12 +203,12 @@ export async function startTelegram( try { const telegramClient = new Client.TelegramClient(runtime, botToken); await telegramClient.start(); - console.log( + prettyConsole.success( `✅ Telegram client successfully started for character ${character.name}` ); return telegramClient; } catch (error) { - console.error( + prettyConsole.error( `❌ Error creating/starting Telegram client for ${character.name}:`, error ); @@ -200,7 +217,7 @@ export async function startTelegram( } export async function startTwitter(runtime: IAgentRuntime) { - console.log("Starting Twitter clients..."); + prettyConsole.log("Starting Twitter clients..."); const twitterSearchClient = new Client.TwitterSearchClient(runtime); await wait(); const twitterInteractionClient = new Client.TwitterInteractionClient( diff --git a/core/src/clients/telegram/src/index.ts b/core/src/clients/telegram/src/index.ts index 21505cab590..c378db8cfb3 100644 --- a/core/src/clients/telegram/src/index.ts +++ b/core/src/clients/telegram/src/index.ts @@ -2,6 +2,7 @@ import { Context, Telegraf } from "telegraf"; import { IAgentRuntime } from "../../../core/types.ts"; import { MessageManager } from "./messageManager.ts"; +import { prettyConsole } from "../../../index.ts"; export class TelegramClient { private bot: Telegraf; @@ -9,18 +10,18 @@ export class TelegramClient { private messageManager: MessageManager; constructor(runtime: IAgentRuntime, botToken: string) { - console.log("📱 Constructing new TelegramClient..."); + prettyConsole.log("📱 Constructing new TelegramClient..."); this.runtime = runtime; this.bot = new Telegraf(botToken); this.messageManager = new MessageManager(this.bot, this.runtime); - console.log("Setting up message handler..."); + prettyConsole.log("Setting up message handler..."); this.bot.on("message", async (ctx) => { try { - console.log("📥 Received message:", ctx.message); + prettyConsole.log("📥 Received message:", ctx.message); await this.messageManager.handleMessage(ctx); } catch (error) { - console.error("❌ Error handling message:", error); + prettyConsole.error("❌ Error handling message:", error); await ctx.reply( "An error occurred while processing your message." ); @@ -29,48 +30,51 @@ export class TelegramClient { // Handle specific message types for better logging this.bot.on("photo", (ctx) => { - console.log( + prettyConsole.log( "📸 Received photo message with caption:", ctx.message.caption ); }); this.bot.on("document", (ctx) => { - console.log( + prettyConsole.log( "📎 Received document message:", ctx.message.document.file_name ); }); this.bot.catch((err, ctx) => { - console.error(`❌ Telegram Error for ${ctx.updateType}:`, err); + prettyConsole.error( + `❌ Telegram Error for ${ctx.updateType}:`, + err + ); ctx.reply("An unexpected error occurred. Please try again later."); }); - console.log("✅ TelegramClient constructor completed"); + prettyConsole.log("✅ TelegramClient constructor completed"); } public async start(): Promise { - console.log("🚀 Starting Telegram bot..."); + prettyConsole.log("🚀 Starting Telegram bot..."); try { this.bot.launch({ dropPendingUpdates: true, }); - console.log( + prettyConsole.log( "✨ Telegram bot successfully launched and is running!" ); - console.log(`Bot username: @${this.bot.botInfo?.username}`); + prettyConsole.log(`Bot username: @${this.bot.botInfo?.username}`); // Graceful shutdown handlers const shutdownHandler = async (signal: string) => { - console.log( + prettyConsole.log( `⚠️ Received ${signal}. Shutting down Telegram bot gracefully...` ); try { await this.stop(); - console.log("🛑 Telegram bot stopped gracefully"); + prettyConsole.log("🛑 Telegram bot stopped gracefully"); } catch (error) { - console.error( + prettyConsole.error( "❌ Error during Telegram bot shutdown:", error ); @@ -82,14 +86,14 @@ export class TelegramClient { process.once("SIGTERM", () => shutdownHandler("SIGTERM")); process.once("SIGHUP", () => shutdownHandler("SIGHUP")); } catch (error) { - console.error("❌ Failed to launch Telegram bot:", error); + prettyConsole.error("❌ Failed to launch Telegram bot:", error); throw error; } } public async stop(): Promise { - console.log("Stopping Telegram bot..."); + prettyConsole.log("Stopping Telegram bot..."); await this.bot.stop(); - console.log("Telegram bot stopped"); + prettyConsole.log("Telegram bot stopped"); } } diff --git a/core/src/clients/telegram/src/messageManager.ts b/core/src/clients/telegram/src/messageManager.ts index ed2566d0814..e662f5f98d6 100644 --- a/core/src/clients/telegram/src/messageManager.ts +++ b/core/src/clients/telegram/src/messageManager.ts @@ -42,10 +42,10 @@ export class MessageManager { private async processImage( message: Message ): Promise<{ description: string } | null> { - console.log( - "🖼️ Processing image message:", - JSON.stringify(message, null, 2) - ); + // console.log( + // "🖼️ Processing image message:", + // JSON.stringify(message, null, 2) + // ); try { let imageUrl: string | null = null; diff --git a/core/src/clients/twitter/base.ts b/core/src/clients/twitter/base.ts index 2bc06e43d78..e0fbdb57c7a 100644 --- a/core/src/clients/twitter/base.ts +++ b/core/src/clients/twitter/base.ts @@ -21,6 +21,7 @@ import ImageDescriptionService from "../../services/image.ts"; import { glob } from "glob"; import { stringToUuid } from "../../core/uuid.ts"; +import { prettyConsole } from "../../index.ts"; export function extractAnswer(text: string): string { const startIndex = text.indexOf("Answer: ") + 8; @@ -429,7 +430,7 @@ export class ClientBase extends EventEmitter { : undefined, } as Content; - console.log("Creating memory for tweet", tweet.id); + prettyConsole.log("Creating memory for tweet", tweet.id); // check if it already exists const memory = @@ -437,7 +438,7 @@ export class ClientBase extends EventEmitter { stringToUuid(tweet.id) ); if (memory) { - console.log( + prettyConsole.log( "Memory already exists, skipping timeline population" ); break; @@ -453,7 +454,7 @@ export class ClientBase extends EventEmitter { }); } - console.log( + prettyConsole.log( `Populated ${tweetsToSave.length} missing tweets from the cache.` ); return; diff --git a/core/src/clients/twitter/utils.ts b/core/src/clients/twitter/utils.ts index aec300cab33..9fff81e3f2f 100644 --- a/core/src/clients/twitter/utils.ts +++ b/core/src/clients/twitter/utils.ts @@ -3,6 +3,7 @@ import { embeddingZeroVector } from "../../core/memory.ts"; import { Content, Memory, UUID } from "../../core/types.ts"; import { stringToUuid } from "../../core/uuid.ts"; import { ClientBase } from "./base.ts"; +import { prettyConsole } from "../../index.ts"; const MAX_TWEET_LENGTH = 280; @@ -36,7 +37,7 @@ export async function buildConversationThread( async function processThread(currentTweet: Tweet) { if (!currentTweet) { - console.log("No current tweet found"); + prettyConsole.log("No current tweet found"); return; } // check if the current tweet has already been saved @@ -44,7 +45,7 @@ export async function buildConversationThread( stringToUuid(currentTweet.id) ); if (!memory) { - console.log("Creating memory for tweet", currentTweet.id); + prettyConsole.log("Creating memory for tweet", currentTweet.id); const roomId = stringToUuid(currentTweet.conversationId); const userId = stringToUuid(currentTweet.userId); @@ -108,9 +109,9 @@ export async function sendTweetChunks( inReplyTo ) ); - console.log("send tweet result:\n", result); + // console.log("send tweet result:\n", result); const body = await result.json(); - console.log("send tweet body:\n", body); + console.log("send tweet body:\n", body.data.create_tweet.tweet_results); const tweetResult = body.data.create_tweet.tweet_results.result; const finalTweet = { diff --git a/core/src/core/generation.ts b/core/src/core/generation.ts index 79bf2729778..588fd1efd4c 100644 --- a/core/src/core/generation.ts +++ b/core/src/core/generation.ts @@ -12,9 +12,10 @@ import { default as tiktoken, TiktokenModel } from "tiktoken"; import models from "./models.ts"; import { generateText as aiGenerateText } from "ai"; -import { createAnthropicVertex } from "anthropic-vertex-ai"; -import Anthropic from "@anthropic-ai/sdk"; + import { createAnthropic } from "@ai-sdk/anthropic"; +import { prettyConsole } from "../index.ts"; + /** * Send a message to the model for a text generateText - receive a string back and parse how you'd like * @param opts - The options for the generateText request. @@ -55,7 +56,7 @@ export async function generateText({ const apiKey = runtime.token; try { - console.log( + prettyConsole.log( `Trimming context to max length of ${max_context_length} tokens.` ); context = await trimTokens(context, max_context_length, "gpt-4o"); @@ -63,14 +64,14 @@ export async function generateText({ let response: string; const _stop = stop || models[provider].settings.stop; - console.log( + prettyConsole.log( `Using provider: ${provider}, model: ${model}, temperature: ${temperature}, max response length: ${max_response_length}` ); switch (provider) { case ModelProvider.OPENAI: case ModelProvider.LLAMACLOUD: { - console.log("Initializing OpenAI model."); + prettyConsole.log("Initializing OpenAI model."); const openai = createOpenAI({ apiKey }); const { text: openaiResponse } = await aiGenerateText({ @@ -83,12 +84,12 @@ export async function generateText({ }); response = openaiResponse; - console.log("Received response from OpenAI model."); + prettyConsole.log("Received response from OpenAI model."); break; } case ModelProvider.ANTHROPIC: { - console.log("Initializing Anthropic model."); + prettyConsole.log("Initializing Anthropic model."); const anthropic = createAnthropic({ apiKey }); @@ -102,12 +103,12 @@ export async function generateText({ }); response = anthropicResponse; - console.log("Received response from Anthropic model."); + prettyConsole.log("Received response from Anthropic model."); break; } case ModelProvider.GROK: { - console.log("Initializing Grok model."); + prettyConsole.log("Initializing Grok model."); const grok = createGroq({ apiKey }); const { text: grokResponse } = await aiGenerateText({ @@ -122,12 +123,14 @@ export async function generateText({ }); response = grokResponse; - console.log("Received response from Grok model."); + prettyConsole.log("Received response from Grok model."); break; } case ModelProvider.LLAMALOCAL: - console.log("Using local Llama model for text completion."); + prettyConsole.log( + "Using local Llama model for text completion." + ); response = await runtime.llamaService.queueTextCompletion( context, temperature, @@ -136,19 +139,19 @@ export async function generateText({ presence_penalty, max_response_length ); - console.log("Received response from local Llama model."); + prettyConsole.log("Received response from local Llama model."); break; default: { const errorMessage = `Unsupported provider: ${provider}`; - console.error(errorMessage); + prettyConsole.error(errorMessage); throw new Error(errorMessage); } } return response; } catch (error) { - console.error("Error in generateText:", error); + prettyConsole.error("Error in generateText:", error); throw error; } } @@ -198,34 +201,37 @@ export async function generateShouldRespond({ let retryDelay = 1000; while (true) { try { - console.log("Attempting to generate text with context:", context); + prettyConsole.log( + "Attempting to generate text with context:", + context + ); const response = await generateText({ runtime, context, modelClass, }); - console.log("Received response from generateText:", response); + prettyConsole.log("Received response from generateText:", response); const parsedResponse = parseShouldRespondFromText(response.trim()); if (parsedResponse) { - console.log("Parsed response:", parsedResponse); + prettyConsole.log("Parsed response:", parsedResponse); return parsedResponse; } else { - console.log("generateShouldRespond no response"); + prettyConsole.log("generateShouldRespond no response"); } } catch (error) { - console.error("Error in generateShouldRespond:", error); + prettyConsole.error("Error in generateShouldRespond:", error); if ( error instanceof TypeError && error.message.includes("queueTextCompletion") ) { - console.error( + prettyConsole.error( "TypeError: Cannot read properties of null (reading 'queueTextCompletion')" ); } } - console.log(`Retrying in ${retryDelay}ms...`); + prettyConsole.log(`Retrying in ${retryDelay}ms...`); await new Promise((resolve) => setTimeout(resolve, retryDelay)); retryDelay *= 2; } @@ -316,7 +322,7 @@ export async function generateTrueOrFalse({ return parsedResponse; } } catch (error) { - console.error("Error in generateTrueOrFalse:", error); + prettyConsole.error("Error in generateTrueOrFalse:", error); } await new Promise((resolve) => setTimeout(resolve, retryDelay)); @@ -349,7 +355,7 @@ export async function generateTextArray({ modelClass: string; }): Promise { if (!context) { - console.error("generateTextArray context is empty"); + prettyConsole.error("generateTextArray context is empty"); return []; } let retryDelay = 1000; @@ -367,7 +373,7 @@ export async function generateTextArray({ return parsedResponse; } } catch (error) { - console.error("Error in generateTextArray:", error); + prettyConsole.error("Error in generateTextArray:", error); } await new Promise((resolve) => setTimeout(resolve, retryDelay)); @@ -385,7 +391,7 @@ export async function generateObjectArray({ modelClass: string; }): Promise { if (!context) { - console.error("generateObjectArray context is empty"); + prettyConsole.error("generateObjectArray context is empty"); return []; } let retryDelay = 1000; @@ -403,7 +409,7 @@ export async function generateObjectArray({ return parsedResponse; } } catch (error) { - console.error("Error in generateTextArray:", error); + prettyConsole.error("Error in generateTextArray:", error); } await new Promise((resolve) => setTimeout(resolve, retryDelay)); @@ -446,20 +452,17 @@ export async function generateMessageResponse({ // try parsing the response as JSON, if null then try again const parsedContent = parseJSONObjectFromText(response) as Content; if (!parsedContent) { - console.log("parsedContent is null, retrying"); + prettyConsole.log("parsedContent is null, retrying"); continue; } return parsedContent; } catch (error) { - console.error("ERROR:", error); + prettyConsole.error("ERROR:", error); // wait for 2 seconds retryLength *= 2; await new Promise((resolve) => setTimeout(resolve, retryLength)); - console.log("Retrying..."); + prettyConsole.log("Retrying..."); } } - throw new Error( - "Failed to complete message after 5 tries, probably a network connectivity, model or API key issue" - ); } diff --git a/core/src/core/runtime.ts b/core/src/core/runtime.ts index dce60d50c95..95cb59f8bcf 100644 --- a/core/src/core/runtime.ts +++ b/core/src/core/runtime.ts @@ -55,6 +55,7 @@ import settings from "./settings.ts"; import { UUID, type Actor } from "./types.ts"; import { stringToUuid } from "./uuid.ts"; import { ImageGenModel } from "./imageGenModels.ts"; +import { prettyConsole } from "../index.ts"; /** * Represents the runtime environment for an agent, handling message processing, @@ -403,6 +404,7 @@ export class AgentRuntime implements IAgentRuntime { * @param action The action to register. */ registerAction(action: Action) { + prettyConsole.success(`Registering action: ${action.name}`); this.actions.push(action); } @@ -586,7 +588,7 @@ export class AgentRuntime implements IAgentRuntime { email: email || (userName || "Bot") + "@" + source || "Unknown", // Temporary details: { summary: "" }, }); - console.log(`User ${userName} created successfully.`); + prettyConsole.success(`User ${userName} created successfully.`); } } @@ -595,7 +597,7 @@ export class AgentRuntime implements IAgentRuntime { await this.databaseAdapter.getParticipantsForRoom(roomId); if (!participants.includes(userId)) { await this.databaseAdapter.addParticipant(userId, roomId); - console.log( + prettyConsole.log( `User ${userId} linked to room ${roomId} successfully.` ); } @@ -641,7 +643,7 @@ export class AgentRuntime implements IAgentRuntime { const room = await this.databaseAdapter.getRoom(roomId); if (!room) { await this.databaseAdapter.createRoom(roomId); - console.log(`Room ${roomId} created successfully.`); + prettyConsole.log(`Room ${roomId} created successfully.`); } } diff --git a/core/src/index.ts b/core/src/index.ts index b017d0be27e..0eec821d9ce 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -19,6 +19,7 @@ import { loadCharacters, parseArguments, } from "./cli/index.ts"; +import { PrettyConsole } from "./cli/colors.ts"; let argv: Arguments = parseArguments(); @@ -26,10 +27,17 @@ const characters = loadCharacters(argv.characters); const directClient = new Client.DirectClient(); +// Initialize the pretty console +export const prettyConsole = new PrettyConsole(); +prettyConsole.clear(); +prettyConsole.closeByNewLine = true; +prettyConsole.useIcons = true; + +// Start the direct client directClient.start(3000); async function startAgent(character: Character) { - console.log(`Starting agent for character ${character.name}`); + prettyConsole.success(`Starting agent for character ${character.name}`); const token = getTokenForProvider(character.modelProvider, character); const db = initializeDatabase(); @@ -37,7 +45,7 @@ async function startAgent(character: Character) { const directRuntime = createDirectRuntime(character, db, token); const clients = await initializeClients(character, runtime); - directClient.registerAgent(directRuntime); + directClient.registerAgent(await directRuntime); return clients; } From 3b05a1a43b5d009692679549d6b7a38f8b8325ba Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sun, 3 Nov 2024 16:37:48 +1100 Subject: [PATCH 4/8] prettier --- core/src/core/models.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/core/models.ts b/core/src/core/models.ts index 5e397effb02..cf9fd861217 100644 --- a/core/src/core/models.ts +++ b/core/src/core/models.ts @@ -104,13 +104,15 @@ const models: Models = { temperature: 0.3, }, model: { - [ModelClass.SMALL]: "NousResearch/Hermes-3-Llama-3.1-8B-GGUF/resolve/main/Hermes-3-Llama-3.1-8B.Q8_0.gguf?download=true", + [ModelClass.SMALL]: + "NousResearch/Hermes-3-Llama-3.1-8B-GGUF/resolve/main/Hermes-3-Llama-3.1-8B.Q8_0.gguf?download=true", [ModelClass.MEDIUM]: "NousResearch/Hermes-3-Llama-3.1-8B-GGUF/resolve/main/Hermes-3-Llama-3.1-8B.Q8_0.gguf?download=true", // TODO: ?download=true [ModelClass.LARGE]: - "NousResearch/Hermes-3-Llama-3.1-8B-GGUF/resolve/main/Hermes-3-Llama-3.1-8B.Q8_0.gguf?download=true", - // "RichardErkhov/NousResearch_-_Meta-Llama-3.1-70B-gguf", // TODO: - [ModelClass.EMBEDDING]: "togethercomputer/m2-bert-80M-32k-retrieval" + "NousResearch/Hermes-3-Llama-3.1-8B-GGUF/resolve/main/Hermes-3-Llama-3.1-8B.Q8_0.gguf?download=true", + // "RichardErkhov/NousResearch_-_Meta-Llama-3.1-70B-gguf", // TODO: + [ModelClass.EMBEDDING]: + "togethercomputer/m2-bert-80M-32k-retrieval", }, }, [ModelProvider.GOOGLE]: { From c0915e79a731234e4ffd929e2d35ffc9e2db5c90 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sun, 3 Nov 2024 17:50:21 +1100 Subject: [PATCH 5/8] discord env --- core/src/clients/discord/index.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/src/clients/discord/index.ts b/core/src/clients/discord/index.ts index 8409217d78e..22e0d1885fb 100644 --- a/core/src/clients/discord/index.ts +++ b/core/src/clients/discord/index.ts @@ -24,6 +24,7 @@ import { MessageManager } from "./messages.ts"; import channelStateProvider from "./providers/channelState.ts"; import voiceStateProvider from "./providers/voiceState.ts"; import { VoiceManager } from "./voice.ts"; +import { prettyConsole } from "../../index.ts"; export class DiscordClient extends EventEmitter { apiToken: string; @@ -35,9 +36,7 @@ export class DiscordClient extends EventEmitter { constructor(runtime: IAgentRuntime) { super(); - this.apiToken = runtime.getSetting( - "DISCORD_API_TOKEN_" + runtime.character.name.toUpperCase() - ) as string; + this.apiToken = runtime.getSetting("DISCORD_API_TOKEN") as string; this.client = new Client({ intents: [ GatewayIntentBits.Guilds, @@ -120,10 +119,7 @@ export class DiscordClient extends EventEmitter { try { await rest.put( Routes.applicationCommands( - this.runtime.getSetting( - "DISCORD_APPLICATION_ID_" + - this.runtime.character.name.toUpperCase() - ) + this.runtime.getSetting("DISCORD_APPLICATION_ID") ), { body: commands } ); @@ -134,16 +130,16 @@ export class DiscordClient extends EventEmitter { } private async onClientReady(readyClient: { user: { tag: any; id: any } }) { - console.log(`Logged in as ${readyClient.user?.tag}`); - console.log("Use this URL to add the bot to your server:"); - console.log( + prettyConsole.success(`Logged in as ${readyClient.user?.tag}`); + prettyConsole.success("Use this URL to add the bot to your server:"); + prettyConsole.success( `https://discord.com/api/oauth2/authorize?client_id=${readyClient.user?.id}&permissions=0&scope=bot%20applications.commands` ); await this.onReady(); } async handleReactionAdd(reaction: MessageReaction, user: User) { - console.log("Reaction added"); + prettyConsole.log("Reaction added"); // if (user.bot) return; let emoji = reaction.emoji.name; From a18c192aba597d40e239c7840935d51e0af312f4 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sun, 3 Nov 2024 17:55:24 +1100 Subject: [PATCH 6/8] add type script ref path for cleaner imports --- core/src/clients/telegram/src/messageManager.ts | 16 ++++++++-------- core/tsconfig.json | 6 +++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/core/src/clients/telegram/src/messageManager.ts b/core/src/clients/telegram/src/messageManager.ts index e662f5f98d6..5da74bcc3f6 100644 --- a/core/src/clients/telegram/src/messageManager.ts +++ b/core/src/clients/telegram/src/messageManager.ts @@ -2,9 +2,9 @@ import { Message } from "@telegraf/types"; import { Context } from "telegraf"; import { Telegraf } from "telegraf"; -import { composeContext } from "../../../core/context.ts"; -import { log_to_file } from "../../../core/logger.ts"; -import { embeddingZeroVector } from "../../../core/memory.ts"; +import { composeContext } from "@/core/context.ts"; +import { log_to_file } from "@/core/logger.ts"; +import { embeddingZeroVector } from "@/core/memory.ts"; import { Content, IAgentRuntime, @@ -13,17 +13,17 @@ import { UUID, HandlerCallback, ModelClass, -} from "../../../core/types.ts"; -import { stringToUuid } from "../../../core/uuid.ts"; +} from "@/core/types.ts"; +import { stringToUuid } from "@/core/uuid.ts"; import { messageHandlerTemplate, shouldRespondTemplate, -} from "../../discord/templates.ts"; -import ImageDescriptionService from "../../../services/image.ts"; +} from "@/clients/discord/templates.ts"; +import ImageDescriptionService from "@/services/image.ts"; import { generateMessageResponse, generateShouldRespond, -} from "../../../core/generation.ts"; +} from "@/core/generation.ts"; const MAX_MESSAGE_LENGTH = 4096; // Telegram's max message length diff --git a/core/tsconfig.json b/core/tsconfig.json index 3527f3ee01e..b8e6dc3265d 100644 --- a/core/tsconfig.json +++ b/core/tsconfig.json @@ -20,7 +20,11 @@ "noEmitOnError": false, "moduleDetection": "force", "allowArbitraryExtensions": true, - "typeRoots": ["./node_modules/@types", "./types"] + "typeRoots": ["./node_modules/@types", "./types"], + "baseUrl": "./src", + "paths": { + "@/*": ["*"] + } }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "src/**/*.d.ts", "types/**/*.test.ts"] From 01bef5d967c5ddc66ce1513efe4695e437d2be18 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sun, 3 Nov 2024 18:00:01 +1100 Subject: [PATCH 7/8] revert --- core/src/clients/telegram/src/messageManager.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/clients/telegram/src/messageManager.ts b/core/src/clients/telegram/src/messageManager.ts index 5da74bcc3f6..e662f5f98d6 100644 --- a/core/src/clients/telegram/src/messageManager.ts +++ b/core/src/clients/telegram/src/messageManager.ts @@ -2,9 +2,9 @@ import { Message } from "@telegraf/types"; import { Context } from "telegraf"; import { Telegraf } from "telegraf"; -import { composeContext } from "@/core/context.ts"; -import { log_to_file } from "@/core/logger.ts"; -import { embeddingZeroVector } from "@/core/memory.ts"; +import { composeContext } from "../../../core/context.ts"; +import { log_to_file } from "../../../core/logger.ts"; +import { embeddingZeroVector } from "../../../core/memory.ts"; import { Content, IAgentRuntime, @@ -13,17 +13,17 @@ import { UUID, HandlerCallback, ModelClass, -} from "@/core/types.ts"; -import { stringToUuid } from "@/core/uuid.ts"; +} from "../../../core/types.ts"; +import { stringToUuid } from "../../../core/uuid.ts"; import { messageHandlerTemplate, shouldRespondTemplate, -} from "@/clients/discord/templates.ts"; -import ImageDescriptionService from "@/services/image.ts"; +} from "../../discord/templates.ts"; +import ImageDescriptionService from "../../../services/image.ts"; import { generateMessageResponse, generateShouldRespond, -} from "@/core/generation.ts"; +} from "../../../core/generation.ts"; const MAX_MESSAGE_LENGTH = 4096; // Telegram's max message length From 8bf480916b3ee4b64fd53bd7aefbde28f990b22d Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Sun, 3 Nov 2024 18:13:47 +1100 Subject: [PATCH 8/8] remove path --- core/tsconfig.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/tsconfig.json b/core/tsconfig.json index b8e6dc3265d..3527f3ee01e 100644 --- a/core/tsconfig.json +++ b/core/tsconfig.json @@ -20,11 +20,7 @@ "noEmitOnError": false, "moduleDetection": "force", "allowArbitraryExtensions": true, - "typeRoots": ["./node_modules/@types", "./types"], - "baseUrl": "./src", - "paths": { - "@/*": ["*"] - } + "typeRoots": ["./node_modules/@types", "./types"] }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "src/**/*.d.ts", "types/**/*.test.ts"]