Skip to content

fix(cli): stop workspace-cli from silently stripping quotes on string args - #983

Merged
taylorwilsdon merged 4 commits into
taylorwilsdon:mainfrom
CapitalX:fix/cli-quoted-value-parsing
Aug 2, 2026
Merged

fix(cli): stop workspace-cli from silently stripping quotes on string args#983
taylorwilsdon merged 4 commits into
taylorwilsdon:mainfrom
CapitalX:fix/cli-quoted-value-parsing

Conversation

@CapitalX

@CapitalX CapitalX commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes a bug where workspace-cli silently strips surrounding quotes from string arguments.

_call_tool in core/cli.py parses each key=value argument by running json.loads(v) and only falling back to the raw string on JSONDecodeError:

k, v = arg.split("=", 1)
try:
    kwargs[k] = json.loads(v)
except json.JSONDecodeError:
    kwargs[k] = v

A quoted string value is itself valid JSON, so the surrounding quotes are silently stripped. For a Gmail exact-phrase query:

workspace-cli call search_gmail_messages query='"exact phrase"'

json.loads('"exact phrase"') returns exact phrase (unquoted), so the server runs an unquoted query. There is no error — it just silently returns different/empty results, which is easy to misread as "no matches."

Fix: add _coerce_cli_value(), which only attempts json.loads when the value actually looks like JSON (empty → ""; first non-space char is {/[; exactly true/false/null; or a numeric literal). Everything else is returned unchanged as a raw string, so quotes and other characters survive verbatim. page_size=3 still coerces to int and values=[["a"]] still parses to a list.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Testing

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have tested this change manually

Added tests/core/test_cli_value_coercion.py (15 cases): strings preserved verbatim (including quoted phrases and date-like values) and JSON scalars/containers that should still be coerced. Manually verified query='"grow therapy"' now reaches the server with the quotes intact.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have enabled "Allow edits from maintainers" for this pull request

Additional Notes

Scope is intentionally minimal — one helper plus a two-line change at the call site, no behavior change for existing JSON-typed args. ruff check is clean on the changed files and the new test module.

Summary by CodeRabbit

  • Bug Fixes

    • Improved command-line argument handling so quoted strings and Gmail phrase queries are preserved exactly as entered.
    • Continued converting JSON-like values, including numbers, booleans, lists, and objects, to their appropriate types.
    • Improved WebSocket compatibility and reliability for OAuth and dual-transport server connections.
  • Tests

    • Added coverage for string preservation and JSON-style value conversion.
    • Expanded development and test support for HTTP client integration.

workspace-cli _call_tool ran json.loads on every key=value value and only fell back to the raw string on JSONDecodeError. A quoted value like query='"exact phrase"' is itself valid JSON, so json.loads stripped the quotes and the server received an unquoted string, breaking Gmail phrase queries with no error.

Add _coerce_cli_value(), which only JSON-decodes values that look like JSON (containers, true/false/null, numbers) and returns everything else raw. page_size=3 and values=[["a"]] still coerce; quoted phrases survive verbatim. Adds unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a0e1499-650a-47fd-81b7-f2be1724d3de

📥 Commits

Reviewing files that changed from the base of the PR and between a4c9a7a and 9f9bb84.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • auth/oauth_callback_server.py
  • main.py
  • pyproject.toml

📝 Walkthrough

Walkthrough

The CLI preserves string values during selective JSON coercion. Uvicorn explicitly uses websockets-sansio in two server configurations. httpx2 is added to test and development dependency declarations.

Changes

CLI coercion

Layer / File(s) Summary
Selective CLI value coercion
core/cli.py
Adds _coerce_cli_value and uses it for CLI tool arguments. Strings remain unchanged, while JSON-like values are decoded.
Coercion regression coverage
tests/core/test_cli_value_coercion.py
Tests string preservation and conversion of numeric, boolean, null, array, nested-array, and object values.

WebSocket runtime configuration

Layer / File(s) Summary
Explicit Uvicorn WebSocket backend
auth/oauth_callback_server.py, main.py
Configures both Uvicorn servers to use websockets-sansio.
Test and development dependencies
pyproject.toml
Adds httpx2>=2.0.0 to optional dependency lists and dependency groups.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: taylorwilsdon

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main fix: preventing quote stripping from string arguments in the CLI.
Description check ✅ Passed The description follows the template, explains the bug and fix, documents testing, and completes the checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Replace the looks-like-JSON pre-check (number regex, literal set, empty-string
special case) with the rule it was approximating: decode as JSON, and keep the
raw text whenever the result is a string. Same behavior, no regex, and the
quote-stripping fix is expressed directly.
@taylorwilsdon taylorwilsdon self-assigned this Aug 2, 2026
@taylorwilsdon taylorwilsdon added the bug Something isn't working label Aug 2, 2026
@taylorwilsdon
taylorwilsdon merged commit 91003dd into taylorwilsdon:main Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants