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/discord/index.ts b/core/src/clients/discord/index.ts index 0a1751af5dd..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; @@ -129,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; 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/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( 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 db6eb85c206..588fd1efd4c 100644 --- a/core/src/core/generation.ts +++ b/core/src/core/generation.ts @@ -12,7 +12,9 @@ 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 { 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 @@ -54,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"); @@ -62,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({ @@ -82,16 +84,17 @@ 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."); - const anthropicVertex = createAnthropicVertex(); + prettyConsole.log("Initializing Anthropic model."); + + const anthropic = createAnthropic({ apiKey }); const { text: anthropicResponse } = await aiGenerateText({ - model: anthropicVertex(model), + model: anthropic.languageModel(model), prompt: context, temperature: temperature, maxTokens: max_response_length, @@ -100,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({ @@ -120,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, @@ -134,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; } } @@ -196,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; } @@ -314,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)); @@ -347,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; @@ -365,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)); @@ -383,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; @@ -401,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)); @@ -444,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/models.ts b/core/src/core/models.ts index a6903b9c8fb..cf9fd861217 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]: { @@ -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]: { 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 a65a8f07727..f74ca175040 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,11 +27,18 @@ 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 const serverPort = parseInt(process.env.SERVER_PORT || "3000"); directClient.start(serverPort); 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(); @@ -38,7 +46,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; }