fix: Allow supression of MCP healtcheck for non-rich text output

This commit is contained in:
CoreRasurae
2026-04-24 10:40:20 +01:00
committed by Forgejo
parent cb60593134
commit d97f2bbe26
+58 -7
View File
@@ -16,6 +16,8 @@ from __future__ import annotations
import json
import logging
import sys
import threading
from collections import OrderedDict
from pathlib import Path
from typing import Annotated, Any, cast
@@ -47,6 +49,14 @@ _log = logging.getLogger(__name__)
# Reusable --format option description
_FORMAT_HELP = "Output format: json, yaml, plain, table, or rich (default: rich)"
# MCP logger name constant — used in create() and list_sessions() to suppress
# MCP health-check output during structured (non-Rich) CLI output.
_MCP_LOGGER_NAME = "cleveragents.mcp"
# Thread lock for MCP logger level mutations to prevent race conditions when
# multiple CLI commands execute concurrently (e.g., in parallel test runners).
_mcp_logger_lock = threading.Lock()
# ---------------------------------------------------------------------------
# Module-level service accessor (patchable in tests)
# ---------------------------------------------------------------------------
@@ -186,6 +196,14 @@ def create(
agents session create --actor openai/gpt-4
agents session create --format json
"""
# Suppress MCP daemon logger during JSON/YAML output to prevent health check
# messages from interfering with structured output.
mcp_logger = logging.getLogger(_MCP_LOGGER_NAME)
orig_level = mcp_logger.level
if fmt not in (OutputFormat.RICH.value, OutputFormat.COLOR.value):
with _mcp_logger_lock:
mcp_logger.setLevel(logging.CRITICAL)
try:
# Create session through the service, then notify the A2A
# facade for protocol compliance and telemetry.
@@ -258,6 +276,10 @@ def create(
"Hint: run 'agents init' to initialise the database."
)
raise typer.Exit(1) from exc
finally:
# Restore original MCP logger level
with _mcp_logger_lock:
mcp_logger.setLevel(orig_level)
@app.command("list")
@@ -276,6 +298,14 @@ def list_sessions(
agents session list --format json
agents session list --format table
"""
# Suppress MCP daemon logger during JSON/YAML output to prevent health check
# messages from interfering with structured output.
mcp_logger = logging.getLogger(_MCP_LOGGER_NAME)
orig_level = mcp_logger.level
if fmt not in (OutputFormat.RICH.value, OutputFormat.COLOR.value):
with _mcp_logger_lock:
mcp_logger.setLevel(logging.CRITICAL)
try:
service = _get_session_service()
sessions = service.list()
@@ -286,6 +316,10 @@ def list_sessions(
"Hint: run 'agents init' to initialise the database."
)
raise typer.Exit(1) from exc
finally:
# Restore original MCP logger level
with _mcp_logger_lock:
mcp_logger.setLevel(orig_level)
if not sessions:
# For machine-readable formats, always emit a structured empty list
@@ -806,6 +840,14 @@ def tell(
bool,
typer.Option("--stream", help="Stream response in real-time"),
] = False,
fmt: Annotated[
OutputFormat,
typer.Option(
"--format",
"-f",
help=_FORMAT_HELP,
),
] = OutputFormat.RICH,
) -> None:
"""Send a message to a session.
@@ -816,6 +858,7 @@ def tell(
agents session tell --session 01HXYZ... "Hello, world"
agents session tell --session 01HXYZ... --actor openai/gpt-4 "Plan a feature"
agents session tell --session 01HXYZ... --stream "Build tests"
agents session tell --session 01HXYZ... --format json "Hello"
"""
try:
service = _get_session_service()
@@ -839,14 +882,22 @@ def tell(
content=assistant_content,
)
if stream:
# Route streaming output through the Rich console so that the
# redaction layer is applied before any content reaches stdout.
# Previously this used sys.stdout.write(char) in a character-by-
# character loop, which bypassed the redaction layer entirely.
from rich.markup import escape as _escape
data = {
"session_id": session_id,
"user_message": prompt,
"assistant_message": assistant_content,
}
console.print(_escape(assistant_content))
if fmt not in (OutputFormat.RICH.value, OutputFormat.COLOR.value):
typer.echo(format_output(data, fmt))
return
if stream:
# Simulate streaming by printing character by character
for char in assistant_content:
sys.stdout.write(char)
sys.stdout.flush()
sys.stdout.write("\n")
else:
from rich.markup import escape