Skip to content

fix(cua-driver/macos): set_config accepts {key,value} shape (parity with Win/Linux) - #2059

Merged
f-trycua merged 1 commit into
mainfrom
fix/macos-set-config-key-value-shape
Jun 27, 2026
Merged

fix(cua-driver/macos): set_config accepts {key,value} shape (parity with Win/Linux)#2059
f-trycua merged 1 commit into
mainfrom
fix/macos-set-config-key-value-shape

Conversation

@f-trycua

@f-trycua f-trycua commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

What

macOS set_config read only the direct fields ({"capture_scope":"desktop"}) and silently ignored the {key, value} shape that Windows, Linux, and the CLI config set all accept. So an MCP client sending {"key":"capture_scope","value":"desktop"} was a no-op on macOS — the agent then saw capture_scope still "window". This is the cross-platform inconsistency flagged during the desktop-scope work (and it bit the macOS desktop-scope test until worked around).

Fix (additive, fully back-compat)

macOS now accepts both shapes: a direct field wins if both are present, otherwise it falls back to the {key, value} pair — mirroring the Linux normalization. Also adds key/value to the tool schema (they were rejected under additionalProperties: false).

The contract is now identical on all three platforms. Documented in the set_config reference.

Verification

Compiles clean (release). The canonical {key, value} shape is what transport_config_persistence_test already uses; no behavior change for direct-field callers.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation

    • Clarified the accepted input formats for configuration updates, including both direct fields and {key, value} pairs.
    • Noted that direct field values take precedence when both formats are supplied.
  • Bug Fixes

    • Expanded configuration updates to accept the CLI-style {key, value} shape in addition to direct field input.
    • Preserved existing validation and save behavior while making the input handling more flexible.

…ith Win/Linux)

macOS set_config read only the direct `capture_scope`/`capture_mode`/
`max_image_dimension` fields and silently ignored the `{key, value}` shape that
Windows, Linux, and the CLI `config set` all accept — so an MCP client sending
`{"key":"capture_scope","value":"desktop"}` was a no-op on macOS (the agent then
saw capture_scope still "window"). This bit the desktop-scope work.

Make macOS accept BOTH shapes (additive, fully back-compat): a direct field wins
if both are present, otherwise fall back to the `{key, value}` pair — mirroring
the Linux normalization. Adds `key`/`value` to the tool schema (they were
rejected under `additionalProperties:false`). The contract is now identical on
all three platforms; documented in the set_config reference.

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

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jun 27, 2026 3:04am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

set_config now accepts both direct-field arguments and {key, value} pairs, with direct fields taking precedence. The macOS tool schema and reference docs were updated to describe the alternate shape.

Changes

Set config input shape

Layer / File(s) Summary
Input contract
libs/cua-driver/rust/crates/platform-macos/src/tools/set_config.rs, docs/content/docs/reference/cua-driver/mcp-tools.mdx
set_config adds key and value to its schema and documents direct-field input alongside {key, value} input with direct-field precedence.
Runtime parsing
libs/cua-driver/rust/crates/platform-macos/src/tools/set_config.rs
invoke reads values from either direct fields or {key, value} pairs, prefers direct fields, and keeps max_image_dimension overflow validation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • trycua/cua#1518: Also changes the macOS set_config tool flow, updating how configuration updates are applied in .../tools/set_config.rs.
  • trycua/cua#1928: Also updates set_config to recognize the CLI-style { "key": ..., "value": ... } input shape.
  • trycua/cua#2034: Also modifies cua-driver set_config handling for the { key, value } input shape and related precedence logic.

Poem

I’m a rabbit with tidy config hops,
Two paths to set the same little stops.
Direct fields lead, but pairs still play,
A whisker-twitching, orderly day.
🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 summarizes the macOS set_config input-shape change and the cross-platform parity goal.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/macos-set-config-key-value-shape

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/content/docs/reference/cua-driver/mcp-tools.mdx`:
- Around line 527-528: Update the argument table in the MCP tools docs to list
capture_scope, key, and value so it matches the accepted inputs described in the
surrounding paragraph. Make sure the table reflects both supported shapes for
the config tool contract, and keep the existing direct-field vs {key, value}
behavior aligned with the documentation.

In `@libs/cua-driver/rust/crates/platform-macos/src/tools/set_config.rs`:
- Around line 112-116: Validate capture_mode in set_config’s capture_mode
handling so the {key, value} path enforces the same allowed values as the direct
field. Mirror the existing capture_scope validation near the capture_mode lookup
in the relevant config parsing flow, ensuring both args.opt_str("capture_mode")
and kv_str("capture_mode") reject any value outside ["som", "vision", "ax"]
before persisting it.
- Around line 87-116: The new `{key, value}` fallback in `invoke` only covers
`capture_mode`, `capture_scope`, and `max_image_dimension`, so PiP-related
settings can still silently no-op on macOS. Update `set_config.rs` so
`experimental_pip` and `experimental_pip_geometry` are also read from the same
`kv` fallback path, or explicitly reject `{key, value}` for those options with a
clear error. Keep the handling consistent with the existing `kv_str`/`kv_u64`
helpers and the direct-field precedence used for the other config keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 56b86b22-b8b1-484e-8523-c1a01af8322d

📥 Commits

Reviewing files that changed from the base of the PR and between af2255c and 42ae2a8.

📒 Files selected for processing (2)
  • docs/content/docs/reference/cua-driver/mcp-tools.mdx
  • libs/cua-driver/rust/crates/platform-macos/src/tools/set_config.rs

Comment on lines +527 to +528
Two equivalent argument shapes are accepted on every platform: a **direct field** (`{"capture_scope": "desktop"}`) or a **`{key, value}` pair** (`{"key": "capture_scope", "value": "desktop"}`, the same shape the CLI `config set` uses). A direct field wins if both are supplied.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the argument table to include capture_scope, key, and value.

The new paragraph documents the alternate shape, but the reference table below still omits those inputs, so the docs no longer fully match the tool contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/docs/reference/cua-driver/mcp-tools.mdx` around lines 527 - 528,
Update the argument table in the MCP tools docs to list capture_scope, key, and
value so it matches the accepted inputs described in the surrounding paragraph.
Make sure the table reflects both supported shapes for the config tool contract,
and keep the existing direct-field vs {key, value} behavior aligned with the
documentation.

Comment on lines +87 to +116
// Accept BOTH shapes, matching Windows/Linux + the CLI `config set`:
// - direct fields: {"capture_scope":"desktop"}
// - {key, value}: {"key":"capture_scope","value":"desktop"}
// A direct field wins if both are somehow present.
let kv: Option<(String, Value)> = args
.opt_str("key")
.and_then(|k| args.get("value").map(|v| (k, v.clone())));
let kv_str = |name: &str| -> Option<String> {
kv.as_ref()
.filter(|(k, _)| k == name)
.and_then(|(_, v)| v.as_str().map(str::to_owned))
};
let kv_u64 = |name: &str| -> Option<u64> {
kv.as_ref().filter(|(k, _)| k == name).and_then(|(_, v)| v.as_u64())
};

// Validate max_image_dimension up front so both branches share the
// u32 check and we never half-apply.
let max_dim: Option<u32> = match args.opt_u64("max_image_dimension") {
let max_dim: Option<u32> = match args.opt_u64("max_image_dimension").or_else(|| kv_u64("max_image_dimension")) {
Some(dim) => match u32::try_from(dim) {
Ok(d) => Some(d),
Err(_) => return ToolResult::error(format!("max_image_dimension {dim} exceeds u32::MAX")),
},
None => None,
};
let capture_mode = args.opt_str("capture_mode");
let capture_mode = args.opt_str("capture_mode").or_else(|| kv_str("capture_mode"));

// Validate capture_scope up front so both branches share the check and
// we never half-apply an invalid value.
let capture_scope = args.opt_str("capture_scope");
let capture_scope = args.opt_str("capture_scope").or_else(|| kv_str("capture_scope"));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle {key, value} for the PiP settings too, or reject them explicitly.

The new fallback only feeds capture_mode, capture_scope, and max_image_dimension. experimental_pip and experimental_pip_geometry are still read from direct fields only later in invoke, so requests like {"key":"experimental_pip","value":true} now validate against the schema/docs but still no-op on macOS. That breaks the “equivalent argument shapes” contract this PR is adding.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-macos/src/tools/set_config.rs` around
lines 87 - 116, The new `{key, value}` fallback in `invoke` only covers
`capture_mode`, `capture_scope`, and `max_image_dimension`, so PiP-related
settings can still silently no-op on macOS. Update `set_config.rs` so
`experimental_pip` and `experimental_pip_geometry` are also read from the same
`kv` fallback path, or explicitly reject `{key, value}` for those options with a
clear error. Keep the handling consistent with the existing `kv_str`/`kv_u64`
helpers and the direct-field precedence used for the other config keys.

Comment on lines +112 to +116
let capture_mode = args.opt_str("capture_mode").or_else(|| kv_str("capture_mode"));

// Validate capture_scope up front so both branches share the check and
// we never half-apply an invalid value.
let capture_scope = args.opt_str("capture_scope");
let capture_scope = args.opt_str("capture_scope").or_else(|| kv_str("capture_scope"));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate capture_mode on the {key, value} path.

kv_str("capture_mode") accepts any string, but the direct-field shape is constrained to ["som", "vision", "ax"]. That means {"key":"capture_mode","value":"anything"} can persist an invalid mode that the direct-field contract would reject. Please mirror the capture_scope check here so both input shapes enforce the same values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-macos/src/tools/set_config.rs` around
lines 112 - 116, Validate capture_mode in set_config’s capture_mode handling so
the {key, value} path enforces the same allowed values as the direct field.
Mirror the existing capture_scope validation near the capture_mode lookup in the
relevant config parsing flow, ensuring both args.opt_str("capture_mode") and
kv_str("capture_mode") reject any value outside ["som", "vision", "ax"] before
persisting it.

@github-actions

Copy link
Copy Markdown
Contributor

Linux visual regression artifacts

Matrix jobs now run independently. Download visual artifacts from this workflow run.
Each background-GUI job uploads a .gif of the interaction plus two annotated PNGs (<app>.png raw, <app>-atspi.png with AT-SPI element boxes); the cua-driver-linux-som-overlays artifact adds <app>-som.png cua Set-of-Marks overlays:

  • cua-driver-linux-cursor-click-gif
  • cua-driver-linux-background-terminal-gif
  • cua-driver-linux-parallel-drag-xserver
  • cua-driver-linux-background-gui-chromium
  • cua-driver-linux-background-gui-tk
  • cua-driver-linux-background-gui-gtk3-gedit
  • cua-driver-linux-background-gui-gtk3-mousepad
  • cua-driver-linux-background-gui-gtk3-scite
  • cua-driver-linux-background-gui-gtk4-characters
  • cua-driver-linux-background-gui-qt5-manuskript
  • cua-driver-linux-background-gui-qt5-klog
  • cua-driver-linux-background-gui-qt5-openambit
  • cua-driver-linux-background-gui-qt6-kate
  • cua-driver-linux-background-gui-qt6-kcalc
  • cua-driver-linux-background-gui-qt6-okular
  • cua-driver-linux-background-gui-qt6-qownnotes
  • cua-driver-linux-background-gui-electron-zettlr
  • cua-driver-linux-background-gui-electron-joplin
  • cua-driver-linux-background-gui-electron-logseq
  • cua-driver-linux-som-overlays

Open workflow run and download artifacts

@f-trycua
f-trycua merged commit 3def0d7 into main Jun 27, 2026
73 checks passed
@f-trycua
f-trycua deleted the fix/macos-set-config-key-value-shape branch June 27, 2026 03:35
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.

1 participant