Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve cmdline colors in Console #5875

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Dandelionym
Copy link

Why are these changes needed?

This PR enhances the readability of multi-agent conversations in the command line interface by improving the color display system. By adding colorama support with proper type definitions, agent messages are now more distinguishable with customizable colors, making it easier to follow conversations between different agents in the terminal.

image

Related issue number

Enhances UI readability. No specific issue number.

Checks

@Dandelionym
Copy link
Author

@Dandelionym please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

@microsoft-github-policy-service agree [company="{your company}"]

@microsoft-github-policy-service agree [company="{Westlake University}"]

@Dandelionym
Copy link
Author

@microsoft-github-policy-service agree company="your company"

@microsoft-github-policy-service agree company="Westlake University"

@Dandelionym Dandelionym changed the title Improve cmdline colors in Concole Improve cmdline colors in Console Mar 8, 2025
@@ -16,6 +16,7 @@ classifiers = [
]
dependencies = [
"autogen-core==0.4.8",
"colorama>=0.4.6",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use native coloring code e.g.

# Define ANSI escape sequences for text colors
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
MAGENTA = '\033[35m'
CYAN = '\033[36m'
RESET = '\033[0m'  # Resets the text to default color

# Example usage
print(f"{RED}This text is red.{RESET}")
print(f"{GREEN}This text is green.{RESET}")
print(f"{YELLOW}This text is yellow.{RESET}")

We don't need to introduce a new dependency just for coloring. For more advanced features like markdown formatting that requires dependencies, we should use autogen-ext package instead of autogen-agentchat.

@@ -85,22 +128,24 @@ async def Console(
no_inline_images: bool = False,
output_stats: bool = False,
user_input_manager: UserInputManager | None = None,
colormap: Optional[Dict[str, str]] = None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make it easier to use, we can automatically assign colors based on the source field observed in the message stream. Each new source gets assigned a new color based on a predefined or an automatically generated sequence of colors.

for example:

def color_generator(step=30):
    """Yields an infinite sequence of distinct RGB colors."""
    hue = 0  # Start from 0
    while True:
        hue = (hue + step) % 360  # Keep hue within 0-360
        r, g, b = hue_to_rgb(hue)
        yield (r, g, b)

def hue_to_rgb(hue):
    """Convert a hue (0-360) to an RGB color (0-255) manually."""
    x = (255 * (1 - abs((hue / 60) % 2 - 1)))  # Intermediate color mixing
    if 0 <= hue < 60:
        return (255, int(x), 0)
    elif 60 <= hue < 120:
        return (int(x), 255, 0)
    elif 120 <= hue < 180:
        return (0, 255, int(x))
    elif 180 <= hue < 240:
        return (0, int(x), 255)
    elif 240 <= hue < 300:
        return (int(x), 0, 255)
    else:
        return (255, 0, int(x))

# Example usage:
color_seq = color_generator()
for _ in range(10):  # Generate 10 distinct colors
    print(next(color_seq))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To convert RGB to ANSI color code using approximation. For example:

def rgb_to_ansi_256(r, g, b):
    """Convert RGB (0-255) to the closest ANSI 256 color."""
    if r == g == b:
        if r < 8:
            return 16
        if r > 248:
            return 231
        return round(((r - 8) / 247) * 24) + 232  # Grayscale range

    return 16 + (36 * round(r / 255 * 5) + 6 * round(g / 255 * 5) + round(b / 255 * 5))

def ansi_256_color_text(text, r, g, b):
    """Wrap text with ANSI escape codes for 256-color mode."""
    color_code = rgb_to_ansi_256(r, g, b)
    return f"\033[38;5;{color_code}m{text}\033[0m"

# Example usage:
print(ansi_256_color_text("Hello in 256-color!", 255, 100, 50))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can enable automatic coloring by default. The colormap can be a simple boolean type for turning on or off the color printing feature. If in the future a custom colormap is needed, we can come back and add a dictionary option to this parameter.

Copy link
Collaborator

@ekzhu ekzhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need unit test for this feature to ensure it is working. Please add unit tests to verify colors are added when printing to console. For example,

import pytest

def my_function():
    print("Hello, pytest!")

def test_my_function(capsys: pytest.CaptureFixture[str]) -> None:
    my_function()
    captured = capsys.readouterr()
    assert captured.out.strip() == "Hello, pytest!"

@Dandelionym
Copy link
Author

Dandelionym commented Mar 19, 2025

Hi, @ekzhu, thank you for your good suggestions. By considering the simplest enhancement, I have finished the modification by local color_map with random color settings. I also tested them with pytest like you described here. Please check. ☕️ :-)

But I don't know how to solve this conflict as I cannot determine these versions. Hope to discuss or help for that.

Thank you again!

@@ -74,9 +80,57 @@ def notify_event_received(self, request_id: str) -> None:
event = asyncio.Event()
self.input_events[request_id] = event

def get_random_ansi_color() -> str:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the simplicty. Though I think we should have some deterministic behavior here.

How about let's hash the agent name (source) of the message into bytes, and then, use the lowest 24 bits to determine the r, g, b numbers?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also avoid colors that are overly dark or overly white, so lower and upper bound numbers should apply.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent idea! I think I may further enhance this feature enhancement soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants