diff --git a/.changeset/rude-ducks-invent.md b/.changeset/rude-ducks-invent.md
new file mode 100644
index 0000000000000000000000000000000000000000..5dc1712990814f1677e8268b9043998fa5703bc6
--- /dev/null
+++ b/.changeset/rude-ducks-invent.md
@@ -0,0 +1,5 @@
+---
+"llamaindex": patch
+---
+
+feat: add verbose mode to Agent
diff --git a/examples/.env.example b/examples/.env.example
new file mode 100644
index 0000000000000000000000000000000000000000..a86a908b7a24ca70e892348095fb4dad1d4b5147
--- /dev/null
+++ b/examples/.env.example
@@ -0,0 +1 @@
+DEBUG=llamaindex
diff --git a/examples/agent/openai.ts b/examples/agent/openai.ts
index 857008054ebb31b60fa0426d6e5abd7c00a5c33d..67d0d4b556f5a5b95b6c0b8d10d2a35c1075c846 100644
--- a/examples/agent/openai.ts
+++ b/examples/agent/openai.ts
@@ -53,7 +53,7 @@ async function main() {
     message: "How much is 5 + 5? then divide by 2",
   });
 
-  console.log(String(response));
+  console.log(response.response.message);
 }
 
 void main().then(() => {
diff --git a/packages/core/src/Settings.ts b/packages/core/src/Settings.ts
index 7e9f8eb90659dee2e3544bbf7d173371c78f3e6c..6852fffcc0d4bc4af7fc63e2de43056b6851fa5a 100644
--- a/packages/core/src/Settings.ts
+++ b/packages/core/src/Settings.ts
@@ -55,9 +55,9 @@ class GlobalSettings implements Config {
   get debug() {
     const debug = getEnv("DEBUG");
     return (
-      getEnv("NODE_ENV") === "development" &&
-      Boolean(debug) &&
-      debug?.includes("llamaindex")
+      (Boolean(debug) && debug?.includes("llamaindex")) ||
+      debug === "*" ||
+      debug === "true"
     );
   }
 
diff --git a/packages/core/src/agent/anthropic.ts b/packages/core/src/agent/anthropic.ts
index accc87fcaf55279d1d2c8398d8f973ed13b6f90a..3ab55521ec511190abaa7b24362db5fc0a96bee0 100644
--- a/packages/core/src/agent/anthropic.ts
+++ b/packages/core/src/agent/anthropic.ts
@@ -49,6 +49,7 @@ export class AnthropicAgent extends AgentRunner<Anthropic> {
         "tools" in params
           ? params.tools
           : params.toolRetriever.retrieve.bind(params.toolRetriever),
+      verbose: params.verbose ?? false,
     });
   }
 
@@ -94,7 +95,11 @@ export class AnthropicAgent extends AgentRunner<Anthropic> {
       const targetTool = tools.find(
         (tool) => tool.metadata.name === toolCall.name,
       );
-      const toolOutput = await callTool(targetTool, toolCall);
+      const toolOutput = await callTool(
+        targetTool,
+        toolCall,
+        step.context.logger,
+      );
       step.context.store.toolOutputs.push(toolOutput);
       step.context.store.messages = [
         ...step.context.store.messages,
diff --git a/packages/core/src/agent/base.ts b/packages/core/src/agent/base.ts
index e0e14f4f5ee8de60918c1b30ff3b1ca3de2309a5..aa0a192cb35f94d0416c5725b10701ecda1cacad 100644
--- a/packages/core/src/agent/base.ts
+++ b/packages/core/src/agent/base.ts
@@ -4,12 +4,14 @@ import {
   pipeline,
   randomUUID,
 } from "@llamaindex/env";
+import { Settings } from "../Settings.js";
 import {
   type ChatEngine,
   type ChatEngineParamsNonStreaming,
   type ChatEngineParamsStreaming,
 } from "../engines/chat/index.js";
 import { wrapEventCaller } from "../internal/context/EventCaller.js";
+import { consoleLogger, emptyLogger } from "../internal/logger.js";
 import { getCallbackManager } from "../internal/settings/CallbackManager.js";
 import { isAsyncIterable } from "../internal/utils.js";
 import type {
@@ -66,6 +68,7 @@ export function createTaskOutputStream<
       const enqueueOutput = (
         output: TaskStepOutput<Model, Store, AdditionalMessageOptions>,
       ) => {
+        context.logger.log("Enqueueing output for step(id, %s).", step.id);
         taskOutputs.push(output);
         controller.enqueue(output);
       };
@@ -75,7 +78,9 @@ export function createTaskOutputStream<
         },
       });
 
+      context.logger.log("Starting step(id, %s).", step.id);
       await handler(step, enqueueOutput);
+      context.logger.log("Finished step(id, %s).", step.id);
       // fixme: support multi-thread when there are multiple outputs
       // todo: for now we pretend there is only one task output
       const { isLast, taskStep } = taskOutputs[0];
@@ -87,6 +92,10 @@ export function createTaskOutputStream<
         toolCallCount: 1,
       };
       if (isLast) {
+        context.logger.log(
+          "Final step(id, %s) reached, closing task.",
+          step.id,
+        );
         getCallbackManager().dispatchEvent("agent-end", {
           payload: {
             endStep: step,
@@ -125,6 +134,7 @@ export type AgentRunnerParams<
   tools:
     | BaseToolWithCall[]
     | ((query: MessageContent) => Promise<BaseToolWithCall[]>);
+  verbose: boolean;
 };
 
 export type AgentParamsBase<
@@ -139,6 +149,7 @@ export type AgentParamsBase<
   llm?: AI;
   chatHistory?: ChatMessage<AdditionalMessageOptions>[];
   systemPrompt?: MessageContent;
+  verbose?: boolean;
 };
 
 /**
@@ -218,6 +229,7 @@ export abstract class AgentRunner<
   readonly #systemPrompt: MessageContent | null = null;
   #chatHistory: ChatMessage<AdditionalMessageOptions>[];
   readonly #runner: AgentWorker<AI, Store, AdditionalMessageOptions>;
+  readonly #verbose: boolean;
 
   // create extra store
   abstract createStore(): Store;
@@ -229,14 +241,15 @@ export abstract class AgentRunner<
   protected constructor(
     params: AgentRunnerParams<AI, Store, AdditionalMessageOptions>,
   ) {
-    const { llm, chatHistory, runner, tools } = params;
+    const { llm, chatHistory, systemPrompt, runner, tools, verbose } = params;
     this.#llm = llm;
     this.#chatHistory = chatHistory;
     this.#runner = runner;
-    if (params.systemPrompt) {
-      this.#systemPrompt = params.systemPrompt;
+    if (systemPrompt) {
+      this.#systemPrompt = systemPrompt;
     }
     this.#tools = tools;
+    this.#verbose = verbose;
   }
 
   get llm() {
@@ -247,6 +260,10 @@ export abstract class AgentRunner<
     return this.#chatHistory;
   }
 
+  get verbose(): boolean {
+    return Settings.debug || this.#verbose;
+  }
+
   public reset(): void {
     this.#chatHistory = [];
   }
@@ -270,8 +287,11 @@ export abstract class AgentRunner<
     return task.context.toolCallCount < MAX_TOOL_CALLS;
   }
 
-  // fixme: this shouldn't be async
-  async createTask(message: MessageContent, stream: boolean = false) {
+  createTask(
+    message: MessageContent,
+    stream: boolean = false,
+    verbose: boolean | undefined = undefined,
+  ) {
     const initialMessages = [...this.#chatHistory];
     if (this.#systemPrompt !== null) {
       const systemPrompt = this.#systemPrompt;
@@ -296,6 +316,13 @@ export abstract class AgentRunner<
         toolOutputs: [] as ToolOutput[],
       },
       shouldContinue: AgentRunner.shouldContinue,
+      logger:
+        // disable verbose if explicitly set to false
+        verbose === false
+          ? emptyLogger
+          : verbose || this.verbose
+            ? consoleLogger
+            : emptyLogger,
     });
   }
 
@@ -312,7 +339,7 @@ export abstract class AgentRunner<
     | AgentChatResponse<AdditionalMessageOptions>
     | ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>
   > {
-    const task = await this.createTask(params.message, !!params.stream);
+    const task = this.createTask(params.message, !!params.stream);
     const stepOutput = await pipeline(
       task,
       async (
diff --git a/packages/core/src/agent/openai.ts b/packages/core/src/agent/openai.ts
index f7146665d11e0e5110473467ea919e5dc642267b..fec65b7dd4b23eaa3f00a12466294a46a36c3302 100644
--- a/packages/core/src/agent/openai.ts
+++ b/packages/core/src/agent/openai.ts
@@ -46,6 +46,7 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
         "tools" in params
           ? params.tools
           : params.toolRetriever.retrieve.bind(params.toolRetriever),
+      verbose: params.verbose ?? false,
     });
   }
 
@@ -77,7 +78,11 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
         const targetTool = tools.find(
           (tool) => tool.metadata.name === toolCall.name,
         );
-        const toolOutput = await callTool(targetTool, toolCall);
+        const toolOutput = await callTool(
+          targetTool,
+          toolCall,
+          step.context.logger,
+        );
         step.context.store.toolOutputs.push(toolOutput);
         step.context.store.messages = [
           ...step.context.store.messages,
@@ -154,7 +159,11 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
               },
             },
           ];
-          const toolOutput = await callTool(targetTool, toolCall);
+          const toolOutput = await callTool(
+            targetTool,
+            toolCall,
+            step.context.logger,
+          );
           step.context.store.messages = [
             ...step.context.store.messages,
             {
diff --git a/packages/core/src/agent/react.ts b/packages/core/src/agent/react.ts
index ebed34fb1e604cd72ab4b36c7273f6f3356b07d4..f1e895d9403c6ec629f520cbd7748cb7a59fcd28 100644
--- a/packages/core/src/agent/react.ts
+++ b/packages/core/src/agent/react.ts
@@ -354,6 +354,7 @@ export class ReActAgent extends AgentRunner<LLM, ReACTAgentStore> {
         "tools" in params
           ? params.tools
           : params.toolRetriever.retrieve.bind(params.toolRetriever),
+      verbose: params.verbose ?? false,
     });
   }
 
@@ -387,14 +388,19 @@ export class ReActAgent extends AgentRunner<LLM, ReACTAgentStore> {
         isLast: type !== "action",
       });
     });
+    step.context.logger.log("current reason: %O", reason);
     step.context.store.reasons = [...step.context.store.reasons, reason];
     if (reason.type === "action") {
       const tool = tools.find((tool) => tool.metadata.name === reason.action);
-      const toolOutput = await callTool(tool, {
-        id: randomUUID(),
-        input: reason.input,
-        name: reason.action,
-      });
+      const toolOutput = await callTool(
+        tool,
+        {
+          id: randomUUID(),
+          input: reason.input,
+          name: reason.action,
+        },
+        step.context.logger,
+      );
       step.context.store.reasons = [
         ...step.context.store.reasons,
         {
diff --git a/packages/core/src/agent/types.ts b/packages/core/src/agent/types.ts
index b3d48374ccd6f3fb78844d92e4c774c394986500..22d562c1a88a599cb0d05f44b67b7509cf6f7903 100644
--- a/packages/core/src/agent/types.ts
+++ b/packages/core/src/agent/types.ts
@@ -1,4 +1,5 @@
 import { ReadableStream } from "@llamaindex/env";
+import type { Logger } from "../internal/logger.js";
 import type { BaseEvent } from "../internal/type.js";
 import type {
   ChatMessage,
@@ -32,6 +33,7 @@ export type AgentTaskContext<
     toolOutputs: ToolOutput[];
     messages: ChatMessage<AdditionalMessageOptions>[];
   } & Store;
+  logger: Readonly<Logger>;
 };
 
 export type TaskStep<
diff --git a/packages/core/src/agent/utils.ts b/packages/core/src/agent/utils.ts
index df8f6b8cd71f215b870db4f51bd8d00e145cf105..d385016d80aa0be46c311fa7a5b87955fbf5604d 100644
--- a/packages/core/src/agent/utils.ts
+++ b/packages/core/src/agent/utils.ts
@@ -1,4 +1,5 @@
 import { ReadableStream } from "@llamaindex/env";
+import type { Logger } from "../internal/logger.js";
 import { getCallbackManager } from "../internal/settings/CallbackManager.js";
 import { isAsyncIterable, prettifyError } from "../internal/utils.js";
 import type {
@@ -13,12 +14,14 @@ import type { BaseTool, JSONObject, JSONValue, ToolOutput } from "../types.js";
 export async function callTool(
   tool: BaseTool | undefined,
   toolCall: ToolCall | PartialToolCall,
+  logger: Logger,
 ): Promise<ToolOutput> {
   const input: JSONObject =
     typeof toolCall.input === "string"
       ? JSON.parse(toolCall.input)
       : toolCall.input;
   if (!tool) {
+    logger.error(`Tool ${toolCall.name} does not exist.`);
     const output = `Tool ${toolCall.name} does not exist.`;
     return {
       tool,
@@ -30,6 +33,9 @@ export async function callTool(
   const call = tool.call;
   let output: JSONValue;
   if (!call) {
+    logger.error(
+      `Tool ${tool.metadata.name} (remote:${toolCall.name}) does not have a implementation.`,
+    );
     output = `Tool ${tool.metadata.name} (remote:${toolCall.name}) does not have a implementation.`;
     return {
       tool,
@@ -45,6 +51,10 @@ export async function callTool(
       },
     });
     output = await call.call(tool, input);
+    logger.log(
+      `Tool ${tool.metadata.name} (remote:${toolCall.name}) succeeded.`,
+    );
+    logger.log(`Output: ${JSON.stringify(output)}`);
     const toolOutput: ToolOutput = {
       tool,
       input,
@@ -60,6 +70,9 @@ export async function callTool(
     return toolOutput;
   } catch (e) {
     output = prettifyError(e);
+    logger.error(
+      `Tool ${tool.metadata.name} (remote:${toolCall.name}) failed: ${output}`,
+    );
   }
   return {
     tool,
diff --git a/packages/core/src/engines/chat/types.ts b/packages/core/src/engines/chat/types.ts
index d81e0035ab552464ee95f778b9fc86da0ce65831..0b00f1d1dbfa47e33f7c15d26448df8ff26a8535 100644
--- a/packages/core/src/engines/chat/types.ts
+++ b/packages/core/src/engines/chat/types.ts
@@ -13,6 +13,11 @@ export interface ChatEngineParamsBase {
    * Optional chat history if you want to customize the chat history.
    */
   chatHistory?: ChatMessage[] | ChatHistory;
+  /**
+   * Optional flag to enable verbose mode.
+   * @default false
+   */
+  verbose?: boolean;
 }
 
 export interface ChatEngineParamsStreaming extends ChatEngineParamsBase {
diff --git a/packages/core/src/internal/logger.ts b/packages/core/src/internal/logger.ts
new file mode 100644
index 0000000000000000000000000000000000000000..686d7e170f2751c5ef0a022a41e6bd719d3e8de1
--- /dev/null
+++ b/packages/core/src/internal/logger.ts
@@ -0,0 +1,17 @@
+export type Logger = {
+  log: (...args: unknown[]) => void;
+  error: (...args: unknown[]) => void;
+  warn: (...args: unknown[]) => void;
+};
+
+export const emptyLogger: Logger = Object.freeze({
+  log: () => {},
+  error: () => {},
+  warn: () => {},
+});
+
+export const consoleLogger: Logger = Object.freeze({
+  log: console.log.bind(console),
+  error: console.error.bind(console),
+  warn: console.warn.bind(console),
+});