Skip to content

Conversation

@dsarno
Copy link
Collaborator

@dsarno dsarno commented Jan 15, 2026

Parse types when provided as JSON string for read_console (fixes #561).

  • Validate entries and normalize to allowed values.
  • Add tests for JSON string and invalid entries.

Summary by Sourcery

Handle JSON string inputs and validation for the read_console types parameter.

Bug Fixes:

  • Parse the read_console types parameter when provided as a JSON string and ensure it is handled as a list.
  • Prevent invalid or non-string entries in the read_console types parameter from being sent by returning clear error responses.

Enhancements:

  • Normalize read_console types entries to a canonical set of allowed values and apply default types only when none are provided.

Tests:

  • Add integration tests covering JSON string types input, list handling, and validation failures for invalid or non-string entries in the types parameter.

Summary by CodeRabbit

  • New Features

    • Enhanced console message filtering to accept types as a JSON string or as a list, normalizing values and defaulting to error/warning/log.
    • Clear validation and user-friendly errors when invalid type values are supplied.
  • Tests

    • Added integration tests covering JSON-string parsing, list handling, and validation/error responses for invalid inputs.

✏️ Tip: You can customize this high-level summary in your review settings.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 15, 2026

Reviewer's Guide

Updates read_console to parse and validate the types parameter when passed as a JSON string or list, normalizing entries to a restricted set of allowed values and adding integration tests for JSON handling and validation failures.

Flow diagram for read_console types parsing and validation

flowchart TD
    A[Start read_console] --> B{types is None?}
    B -- Yes --> C[Set types to default list error, warning, log]
    B -- No --> D{types is string?}
    D -- Yes --> E[types = parse_json_payload types]
    D -- No --> F[Keep types as provided]
    E --> G{types is list?}
    F --> G
    G -- No --> H[Return error: success False, message 'types must be a list']
    G -- Yes --> I{types is not None?}
    I -- No --> C
    I -- Yes --> J[Initialize allowed_types and normalized_types]
    J --> K[Iterate over each entry in types]
    K --> L{entry is string?}
    L -- No --> M[Return error: success False, message 'types entries must be strings']
    L -- Yes --> N[normalized = entry stripped and lowercased]
    N --> O{normalized in allowed_types?}
    O -- No --> P[Return error: success False, message 'invalid types entry']
    O -- Yes --> Q[Append normalized to normalized_types]
    Q --> R{More entries?}
    R -- Yes --> K
    R -- No --> S[Set types = normalized_types]
    C --> T[Continue with read_console using types]
    S --> T
    T --> U[End types handling]
Loading

File-Level Changes

Change Details Files
Add parsing and validation logic for the read_console types parameter, supporting JSON string input and normalizing values to a fixed allowed set.
  • Parse types with parse_json_payload when provided as a string to support JSON-encoded input.
  • Return an error response when types is not a list after parsing, with guidance on the expected JSON format.
  • Validate that all types entries are strings and return a clear error when non-string entries are found.
  • Normalize types entries by trimming whitespace, lowercasing, and ensuring each is one of the allowed values {error, warning, log, all}, returning an error for invalid entries.
  • Set default types to ['error', 'warning', 'log'] only when no types value is provided.
Server/src/services/tools/read_console.py
Add integration tests to verify JSON string handling and validation behavior for the read_console types parameter.
  • Add a test that passes types as a JSON string, asserts that it is parsed into a list, and that normalized values are sent to Unity.
  • Add a test that ensures invalid types entries return a clear error and prevent the Unity command from being sent.
  • Add a test that ensures non-string types entries return a clear error and prevent the Unity command from being sent.
  • Use monkeypatch to stub send_with_unity_instance and capture the params sent by read_console for assertions.
Server/tests/integration/test_read_console_truncate.py

Assessment against linked issues

Issue Objective Addressed Explanation
#561 Allow the read_console tool to accept the types parameter when provided as a JSON string (instead of only a native list), avoiding the Pydantic validation error.
#561 Validate and normalize the types entries (ensuring they are strings and among the allowed values) and return clear error messages when invalid values are provided.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

The change updates read_console to accept types as either a list or a JSON string. It parses JSON strings, validates that the result is a list of allowed string values (error, warning, log, all), normalizes entries to lowercase, provides structured errors for invalid input, and defaults types to ['error','warning','log'] when omitted.

Changes

Cohort / File(s) Summary
Core Service Logic
Server/src/services/tools/read_console.py
Added parse_json_payload import; accept types as list or JSON str; parse JSON strings; validate that types is a list of strings from allowed values (error, warning, log, all); normalize to lowercase; default to ['error','warning','log']; return structured errors for invalid inputs.
Integration Tests
Server/tests/integration/test_read_console_truncate.py
Added tests covering JSON-string types parsing and validation for invalid entries; tests mock internal sending to assert params and error behavior.

Sequence Diagram(s)

(omitted — change is validation/normalization logic within a single component)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

bug

Poem

🐰 I parsed a string that once made folks groan,
Turned JSON to list, now the errors are flown.
Lowercased and checked, neat as a pin,
Console hops happy — let the logs roll in! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: parsing and validating the read_console types parameter, which directly addresses the PR objectives and issue #561.
Linked Issues check ✅ Passed The PR fully addresses issue #561 by implementing JSON string parsing for the types parameter, validation of entries, normalization to allowed values, and comprehensive integration tests.
Out of Scope Changes check ✅ Passed All changes are directly related to the objectives: the read_console method signature and validation logic, the import of parse_json_payload utility, and integration tests for the new functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b554546 and 9b3ba61.

📒 Files selected for processing (2)
  • Server/src/services/tools/read_console.py
  • Server/tests/integration/test_read_console_truncate.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • Server/tests/integration/test_read_console_truncate.py
  • Server/src/services/tools/read_console.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • Consider handling or surfacing parse_json_payload failures explicitly (e.g., catching JSON errors and returning a clear error message) so malformed JSON in types doesn’t bubble up as an unhandled exception.
  • The default list of types ['error', 'warning', 'log'] is now duplicated in both the validation block and the else branch; extracting this into a shared constant would reduce the chance of drift.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider handling or surfacing parse_json_payload failures explicitly (e.g., catching JSON errors and returning a clear error message) so malformed JSON in types doesn’t bubble up as an unhandled exception.
- The default list of types ['error', 'warning', 'log'] is now duplicated in both the validation block and the else branch; extracting this into a shared constant would reduce the chance of drift.

## Individual Comments

### Comment 1
<location> `Server/tests/integration/test_read_console_truncate.py:244-249` </location>
<code_context>
+        fake_send_with_unity_instance,
+    )
+
+    # Invalid entry in list should return a clear error and not send.
+    captured.clear()
+    resp = await read_console(ctx=DummyContext(), action="get", types='["error", "nope"]')
+    assert resp["success"] is False
+    assert "invalid types entry" in resp["message"]
+    assert captured == {}
+
+    # Non-string entry should return a clear error and not send.
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for JSON `types` that parse to non-list or are malformed JSON to cover the new validation branch.

Now that `types` can be a JSON string that isn’t a list, add a test where the JSON parses but yields a non-list value (e.g. `"error"`, `123`, `{}`) to assert the specific "types must be a list" error. If `parse_json_payload` propagates JSON parsing failures, also add a test for malformed JSON so the new error path is fully covered and protected against regressions.
</issue_to_address>

### Comment 2
<location> `Server/tests/integration/test_read_console_truncate.py:210-222` </location>
<code_context>
+        fake_send_with_unity_instance,
+    )
+
+    # Test with types as JSON string (the problematic case from issue #561)
+    resp = await read_console(ctx=DummyContext(), action="get", types='["error", "warning", "all"]')
+    assert resp["success"] is True
+    # Verify types was parsed correctly and sent as a list
+    assert isinstance(captured["params"]["types"], list)
+    assert captured["params"]["types"] == ["error", "warning", "all"]
+    
+    # Test with types as actual list (should still work)
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test that verifies normalization of `types` entries (case and surrounding whitespace).

Since `types` values are normalized with `strip().lower()` before validation against `{"error", "warning", "log", "all"}`, it would be useful to cover that explicitly. For example, add a case like `types='[" Error ", "WARNING"]'` and assert that `captured["params"]["types"] == ["error", "warning"]` to document and lock in this behavior.

```suggestion
    # Test with types as JSON string (the problematic case from issue #561)
    resp = await read_console(ctx=DummyContext(), action="get", types='["error", "warning", "all"]')
    assert resp["success"] is True
    # Verify types was parsed correctly and sent as a list
    assert isinstance(captured["params"]["types"], list)
    assert captured["params"]["types"] == ["error", "warning", "all"]

    # Test normalization of types entries (whitespace and case)
    captured.clear()
    resp = await read_console(
        ctx=DummyContext(),
        action="get",
        types='[" Error ", "WARNING"]',
    )
    assert resp["success"] is True
    assert isinstance(captured["params"]["types"], list)
    assert captured["params"]["types"] == ["error", "warning"]

    # Test with types as actual list (should still work)
    captured.clear()
    resp = await read_console(ctx=DummyContext(), action="get", types=["error", "warning"])
    assert resp["success"] is True
    assert isinstance(captured["params"]["types"], list)
    assert captured["params"]["types"] == ["error", "warning"]
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +244 to +255
# Invalid entry in list should return a clear error and not send.
captured.clear()
resp = await read_console(ctx=DummyContext(), action="get", types='["error", "nope"]')
assert resp["success"] is False
assert "invalid types entry" in resp["message"]
assert captured == {}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Add tests for JSON types that parse to non-list or are malformed JSON to cover the new validation branch.

Now that types can be a JSON string that isn’t a list, add a test where the JSON parses but yields a non-list value (e.g. "error", 123, {}) to assert the specific "types must be a list" error. If parse_json_payload propagates JSON parsing failures, also add a test for malformed JSON so the new error path is fully covered and protected against regressions.

Comment on lines 210 to 228
# Test with types as JSON string (the problematic case from issue #561)
resp = await read_console(ctx=DummyContext(), action="get", types='["error", "warning", "all"]')
assert resp["success"] is True
# Verify types was parsed correctly and sent as a list
assert isinstance(captured["params"]["types"], list)
assert captured["params"]["types"] == ["error", "warning", "all"]

# Test with types as actual list (should still work)
captured.clear()
resp = await read_console(ctx=DummyContext(), action="get", types=["error", "warning"])
assert resp["success"] is True
assert isinstance(captured["params"]["types"], list)
assert captured["params"]["types"] == ["error", "warning"]
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Consider adding a test that verifies normalization of types entries (case and surrounding whitespace).

Since types values are normalized with strip().lower() before validation against {"error", "warning", "log", "all"}, it would be useful to cover that explicitly. For example, add a case like types='[" Error ", "WARNING"]' and assert that captured["params"]["types"] == ["error", "warning"] to document and lock in this behavior.

Suggested change
# Test with types as JSON string (the problematic case from issue #561)
resp = await read_console(ctx=DummyContext(), action="get", types='["error", "warning", "all"]')
assert resp["success"] is True
# Verify types was parsed correctly and sent as a list
assert isinstance(captured["params"]["types"], list)
assert captured["params"]["types"] == ["error", "warning", "all"]
# Test with types as actual list (should still work)
captured.clear()
resp = await read_console(ctx=DummyContext(), action="get", types=["error", "warning"])
assert resp["success"] is True
assert isinstance(captured["params"]["types"], list)
assert captured["params"]["types"] == ["error", "warning"]
# Test with types as JSON string (the problematic case from issue #561)
resp = await read_console(ctx=DummyContext(), action="get", types='["error", "warning", "all"]')
assert resp["success"] is True
# Verify types was parsed correctly and sent as a list
assert isinstance(captured["params"]["types"], list)
assert captured["params"]["types"] == ["error", "warning", "all"]
# Test normalization of types entries (whitespace and case)
captured.clear()
resp = await read_console(
ctx=DummyContext(),
action="get",
types='[" Error ", "WARNING"]',
)
assert resp["success"] is True
assert isinstance(captured["params"]["types"], list)
assert captured["params"]["types"] == ["error", "warning"]
# Test with types as actual list (should still work)
captured.clear()
resp = await read_console(ctx=DummyContext(), action="get", types=["error", "warning"])
assert resp["success"] is True
assert isinstance(captured["params"]["types"], list)
assert captured["params"]["types"] == ["error", "warning"]

@dsarno dsarno force-pushed the fix/read-console-types branch from b554546 to 9b3ba61 Compare January 15, 2026 16:55
@dsarno dsarno merged commit 10e93b8 into CoplayDev:main Jan 15, 2026
2 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jan 15, 2026
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.

Error validating tool 'read_console': 1 validation error for call[read_console]

1 participant