Skip to content

fix(chat): propagate API failures across CLIs - #3166

Open
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/chat-error-exit-parity
Open

fix(chat): propagate API failures across CLIs#3166
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/chat-error-exit-parity

Conversation

@tang-vu

@tang-vu tang-vu commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Why this matters

The macOS chat command currently renders an API error message as ordinary output and exits zero when an OpenAI-compatible backend returns an error-only JSON payload with HTTP 200. The Windows command catches transport or JSON failures, prints an error, and also falls through with exit zero; it likewise accepts a 2xx response with no assistant content. Shell scripts and operators therefore cannot distinguish a generated answer from a failed request by exit status.

This aligns both CLIs with the existing Linux behavior. macOS requires assistant message content via jq -e, surfaces the backend error message, and returns nonzero when content is absent. Windows validates non-empty assistant content, turns malformed success envelopes into the same failure path, and exits nonzero from its catch boundary.

Behavioral invariant: chat exits zero only after receiving non-empty assistant content; transport failures and API error or malformed payloads must be visible failures.

Overlap check

Searched open and closed PRs for chat exit code macOS Windows, ods chat error response, and the changed production functions in ods/installers/macos/ods-macos.sh and ods/installers/windows/ods.ps1. No PR covers this behavior.

Linux ods-cli already uses jq -er and exits through error() for missing assistant content. The new parity contract treats that implementation as the established boundary and leaves it unchanged.

Regression test

tests/test-macos-cli-mode-routing.sh now drives the real macOS chat command with a successful HTTP response containing only the backend error model unavailable. Before the fix it printed that message and returned zero; the regression requires a nonzero exit and an actionable LLM error: model unavailable receipt.

tests/test-chat-error-exit-parity.sh verifies all three platform implementations reject error-only or missing-content responses and that the Windows catch path exits nonzero. Existing local/cloud route and authentication assertions continue to run around the new negative case.

Validation

  • bash tests/test-macos-cli-mode-routing.sh ? passed all local, cloud, auth, routing, and API-error cases
  • bash tests/test-chat-error-exit-parity.sh ? passed Linux/macOS/Windows contract
  • bash tests/test-ods-cli-pipefail-tolerance.sh ? 16 passed, 0 failed, 0 skipped
  • make lint ? passed
  • PowerShell parser on installers/windows/ods.ps1 ? passed
  • git diff --check ? passed

The macOS regression executes the real CLI with boundary shims. Windows validation is parser and static-contract based because no live Windows inference endpoint was used; it proves control-flow placement, not a real network request. Reverting restores the false-success exit codes and needs no state migration.

Batch compatibility

This PR was validated on synthetic integration head 9af795fc, which applies #3158 through #3167 in numeric order on upstream/main (6ff9b4fc). Combined make lint, make test, make smoke, make simulate, and all 418 BATS cases passed (one root-specific permission assertion skipped by design).

Recommended merge order: #3158 ? #3159 ? #3160 ? #3161 ? #3162 ? #3163 ? #3164 ? #3165 ? #3166 ? #3167. The only manual reconciliation observed was the adjacent Makefile test insertion shared by #3164 and #3166; retain both test-unix-restart-recreate-env.sh and test-chat-error-exit-parity.sh lines. Production code merged automatically across the full batch.

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