Skip to content

Avoid ANSI and progress output when running in LLM environment#7649

Merged
Youssef1313 merged 2 commits intomainfrom
dev/ygerges/no-ansi-no-progress-llm
Apr 1, 2026
Merged

Avoid ANSI and progress output when running in LLM environment#7649
Youssef1313 merged 2 commits intomainfrom
dev/ygerges/no-ansi-no-progress-llm

Conversation

@Youssef1313
Copy link
Copy Markdown
Member

Fixes #7647

Copilot AI review requested due to automatic review settings April 1, 2026 11:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to reduce noisy/token-inefficient terminal output in agent/LLM-driven runs by automatically disabling ANSI output and progress rendering when an LLM environment is detected.

Changes:

  • Added an LLMEnvironmentDetector helper that infers “LLM environment” based on known environment variables from various agent tools.
  • Updated TerminalOutputDevice to force AnsiMode.NoAnsi and disable progress output when an LLM environment is detected.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs Forces no-ANSI and no-progress behavior when LLMEnvironmentDetector indicates an LLM environment.
src/Platform/Microsoft.Testing.Platform/Helpers/LLMEnvironmentDetector.cs Introduces environment-variable-based detection of common LLM/agent CLI environments.
Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs:134

  • The comments inside this if block are now misleading: the condition is noAnsi || LLMEnvironmentDetector.IsLLMEnvironment(), but the block comment says the user explicitly specified --no-ansi and that we should respect it. Please update the comment to reflect that this path also applies to auto-detection of an LLM environment (and clarify the precedence between auto-detection and CLI options if relevant).
        if (noAnsi || LLMEnvironmentDetector.IsLLMEnvironment())
        {
            // User explicitly specified --no-ansi.
            // We should respect that.
            ansiMode = AnsiMode.NoAnsi;

@Youssef1313 Youssef1313 enabled auto-merge (squash) April 1, 2026 11:32
@Youssef1313 Youssef1313 merged commit 221ea23 into main Apr 1, 2026
10 checks passed
@Youssef1313 Youssef1313 deleted the dev/ygerges/no-ansi-no-progress-llm branch April 1, 2026 12:15
Copy link
Copy Markdown
Member

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

Thanks for the PR @Youssef1313 — the concept is solid and the detection rule catalog is comprehensive. A few concerns:

Architecture / Testability:

  • LLMEnvironmentDetector uses System.Environment directly, bypassing the IEnvironment abstraction that the project enforces via BannedSymbols.txt. TerminalOutputDevice and CIEnvironmentDetector both follow the DI pattern — this class should too.
  • The static design prevents unit testing. Following the CIEnvironmentDetector pattern (non-static class with injected IEnvironment) would enable proper test coverage.

Scope:

  • The linked issue (#7647) requests explicit TESTINGPLATFORM_NOPROGRESS / TESTINGPLATFORM_NOANSI env vars. This PR takes the complementary auto-detection approach instead. Both are valuable — is the env var support planned as a follow-up?

Minor:

  • Comment inside the if block is now misleading after the condition change.
  • ArgumentNullException usage vs project's ArgumentGuard convention.
  • The string composition in GetLLMEnvironment() is unused — only the null check matters.

CI is green on completed checks. The integration point in TerminalOutputDevice is clean and minimal.


// Copy from https://github.com/dotnet/sdk/tree/1e5d8e39d3026edb222cdf4f8d8240f1eb99f24b/src/Cli/Microsoft.DotNet.Cli.Definitions/Telemetry
internal static class LLMEnvironmentDetector
{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This class calls Environment.GetEnvironmentVariable() directly (suppressing RS0030 each time), but the project's BannedSymbols.txt bans the entire System.Environment type with the directive "Use 'IEnvironment' instead".

TerminalOutputDevice (the caller of this class) already properly uses the IEnvironment abstraction via constructor injection. CIEnvironmentDetector in TestFramework follows the same DI pattern.

Additionally, the static design (static class with a static auto-property initialized at class load) makes this completely untestable — you can't mock environment variables without actually setting them in the process, and the result is frozen for the process lifetime.

Suggestion: Follow the CIEnvironmentDetector pattern — make this a non-static class with constructor-injected IEnvironment. Provide a singleton default via a static Instance property if convenient static access is still desired. This aligns with the architectural conventions and enables unit testing.


private static string? GetLLMEnvironment()
{
string?[] results = DetectionRules.Select(r => r.GetResult()).Where(r => r != null).ToArray();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

GetLLMEnvironment() builds a comma-separated string of all matched LLM environment names, but IsLLMEnvironment() only checks !RoslynString.IsNullOrEmpty(...) — the actual environment names are never exposed, logged, or returned to any caller. The generic EnvironmentDetectionRuleWithResult<T> adds complexity for a feature (returning which LLM was detected) that isn't currently used.

If the string is intended for future telemetry/logging, consider adding a comment documenting that intent. Otherwise, this could be simplified to a bool check that short-circuits on the first match (avoiding unnecessary allocations from Select + Where + ToArray + string.Join).

{
private readonly string[] _variables;

public BooleanEnvironmentRule(params string[] variables)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The constructors use ?? throw new ArgumentNullException(nameof(...)) but the project's BannedSymbols.txt bans ArgumentNullException.#ctor in favor of ArgumentGuard.

Since this is a copy from dotnet/sdk, the deviation may be intentional to keep the code synchronized — but worth calling out for awareness. If strict alignment with project conventions is preferred, these should use ArgumentGuard.

// In LLM environments, prefer simple text output so that LLM can parse it easily.
// Note that NoAnsi also implies no progress.
if (noAnsi || LLMEnvironmentDetector.IsLLMEnvironment())
{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The comment inside this if block still reads "User explicitly specified --no-ansi. We should respect that." but the condition now also covers auto-detected LLM environments. Consider updating to reflect both paths, e.g.:

// User explicitly specified --no-ansi, or an LLM environment was auto-detected.
// Use plain text output for simpler parsing.

(This was flagged as a suppressed low-confidence comment by the automated reviewer — I agree it should be addressed.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The linked issue (#7647) specifically requests adding TESTINGPLATFORM_NOPROGRESS and TESTINGPLATFORM_NOANSI environment variables as defaults (overridable by CLI args). This PR takes a different approach (auto-detection via heuristics). Both approaches are complementary — auto-detection is great for zero-config UX, but explicit env vars give users deterministic control regardless of whether their tool is in the detection list.

Consider whether the env var support from #7647 should also be included here, or if that's deferred to a follow-up. The naming convention would fit naturally alongside existing vars in EnvironmentVariableConstants.cs (TESTINGPLATFORM_NOBANNER, TESTINGPLATFORM_DIAGNOSTIC, etc.).

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.

Add "no progress" and "no ANSI" environment variables

3 participants