Skip to content

fix(skills): parse system.which Record response in remote bin probe#28406

Closed
tony-shi wants to merge 1 commit into
openclaw:mainfrom
tony-shi:fix/remote-skills-system-which-parse
Closed

fix(skills): parse system.which Record response in remote bin probe#28406
tony-shi wants to merge 1 commit into
openclaw:mainfrom
tony-shi:fix/remote-skills-system-which-parse

Conversation

@tony-shi

Copy link
Copy Markdown

Summary

  • Problem: parseBinProbePayload only handles string[] and stdout formats, but system.which returns Record<string, string> (keys = bin names, values = resolved paths). Array.isArray() returns false for objects → always returns empty [].
  • Why it matters: Docker/Linux gateway + remote Mac node setups never recognize remote bins → skills always show "blocked". Not caught earlier because most users run gateway locally on Mac where hasBinary() resolves bins directly without the remote probe path.
  • What changed: parseBinProbePayload now extracts Object.keys() from Record-typed bins responses. Exported the function for direct unit testing.
  • What did NOT change (scope boundary): system.run fallback path, existing string[] handling, local bin detection, and all other skills logic.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Related: Docker gateway + remote Mac node skill resolution

User-visible / Behavior Changes

Skills that were previously shown as "blocked" in Docker gateway + remote Mac node setups will now correctly show as "eligible" when the remote node has the required binaries.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)

Repro + Verification

Environment

  • OS: macOS (node host) + Linux/Docker (gateway)
  • Runtime/container: Docker gateway with remote Mac node connected via WebSocket

Steps

  1. Run gateway in Docker container (Linux).
  2. Connect a Mac node host: openclaw node run --host <gateway-ip> --port 18789.
  3. Node host responds to system.which probe with { bins: { "git": "/usr/bin/git", ... } }.
  4. Check skills status in Control UI.

Expected

Skills that require remote bins (e.g., git) should show as "eligible".

Actual

All remote-bin-dependent skills show as "blocked" because parseBinProbePayload returned [].

Evidence

  • Failing test/log before + passing after

Root cause trace: parseBinProbePayload line 211 does Array.isArray(parsed.bins) which is false for Record<string, string> objects → falls through to stdout check (also fails) → returns [].

After fix: 10/10 tests pass including 8 new tests covering all three response formats (string[], Record, stdout) and edge cases.

Human Verification (required)

  • Verified scenarios: node host probe logs confirm system.which returns Record format; new unit tests validate all three parse paths.
  • Edge cases checked: empty bins object, whitespace in bin names, null/undefined input, invalid JSON, payload as second argument.
  • What you did not verify: end-to-end Docker gateway restart with the fix (requires image rebuild).

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert this commit; system.run fallback will be used for nodes that don't support system.which.
  • Files/config to restore: src/infra/skills-remote.ts
  • Known bad symptoms reviewers should watch for: skills showing incorrect eligibility status.

Risks and Mitigations

  • Risk: Object.keys() on unexpected payload shapes.
    • Mitigation: guarded by typeof parsed.bins === "object" check; wrapped in try/catch; existing string[] and stdout paths unchanged.

🤖 AI-assisted (fully tested, code understood)

@greptile-apps

greptile-apps Bot commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixed a bug in parseBinProbePayload (src/infra/skills-remote.ts:203) where system.which responses were incorrectly parsed, causing remote bin detection to fail in Docker gateway + remote Mac node setups.

Root cause: parseBinProbePayload only handled string[] and stdout formats. When system.which returns Record<string, string> (bin names → paths), Array.isArray(parsed.bins) returned false, falling through to the stdout check (which also failed), ultimately returning an empty array.

What changed:

  • Added Record format handling: checks if parsed.bins is an object (but not array), then extracts keys via Object.keys()
  • Exported parseBinProbePayload for direct unit testing
  • Added 8 comprehensive tests covering all three formats (string[], Record, stdout) plus edge cases

Impact: Skills requiring remote binaries will now correctly show as "eligible" instead of "blocked" when the remote node has the required binaries.

Confidence Score: 5/5

  • This PR is safe to merge with no risk
  • Straightforward bug fix with excellent test coverage (8 new tests). The change is minimal (adds one conditional block), backward compatible (preserves all existing code paths), and addresses a clear bug where Record-formatted responses from system.which were not being parsed. Verified the fix matches the actual return type from handleSystemWhich in src/node-host/invoke.ts:245 which returns { bins: Record<string, string> }.
  • No files require special attention

Last reviewed commit: 213aa8a

@tony-shi

tony-shi commented Mar 2, 2026

Copy link
Copy Markdown
Author

Related: #29254

This PR addresses a parsing-layer bug in parseBinProbePayload() that is part of the root cause described in #29254. The fix handles the Record<string, string> response format from system.which, which was previously unrecognized due to Array.isArray() returning false for plain objects.

This change is complementary to the sandbox eligibility probing work in #29327 — it covers the non-sandbox remote node deployment path (Docker gateway + bare-metal Mac node via openclaw node run), where parseBinProbePayload remains the sole response parser.

@tony-shi

tony-shi commented Mar 5, 2026

Copy link
Copy Markdown
Author

Friendly ping @steipete. This fixes a core parsing bug in parseBinProbePayload that drops Record<string, string> payloads from remote nodes.

Noting that this is completely orthogonal to PR #29303 (sandbox probing) and both are needed to fully resolve #29254. CI is green and tests are included.

@tony-shi

Copy link
Copy Markdown
Author

Gentle bump — noting that all other PRs addressing #29254 have since been closed (#29303, #29313, #29327). This is now the only open fix for this parsing bug. CI remains green and no conflicts.

@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Mar 31, 2026
@openclaw-barnacle

Copy link
Copy Markdown

Closing due to inactivity.
If you believe this PR should be revived, post in #pr-thunderdome-dangerzone on Discord to talk to a maintainer.
That channel is the escape hatch for high-quality PRs that get auto-closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: S stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant