2.0.6 — remove copilot_cli backend + upstream Geny CLI compat patches#208
Merged
Merged
Conversation
…patches
Two coordinated changes, bumping the version to 2.0.6.
== Removed: ``copilot_cli`` provider ==
The ``gh copilot`` CLI advertises (and the ``CopilotCLIClient`` honestly
mirrored) ``supports_streaming=False``, ``supports_tools=False``,
``supports_mcp_passthrough=False`` — it is a one-shot text-in /
text-out subprocess that cannot participate in the executor's
Stage-10 dispatch / Sub-Worker delegation flows. Keeping the backend
encouraged consumers to enable a provider that would fail on the
first tool call, so it's removed entirely:
- ``llm_client/copilot.py`` (the ``CopilotCLIClient``) — deleted.
- ``llm_client/registry.py`` ``_copilot_cli_factory`` + registration.
- ``llm_client/__init__.py`` re-exports of ``CopilotCLIClient``.
- ``llm_client/translators/_cli.py`` ``compose_copilot_prompt`` /
``copilot_argv`` / ``parse_plain_text_to_response`` helpers.
- ``llm_client/translators/__init__.py`` re-exports of the above.
- ``core/pipeline.py:_creds_to_client_kwargs`` ``"copilot_cli"``
branch.
- ``tests/_fixtures/fake_gh.py`` + ``tests/llm_client/{unit,
conformance}/test_copilot*.py`` test suites.
== Upstreamed: four Claude-Code CLI compatibility fixes from Geny ==
The Geny project's ``service/llm_patches.py`` carried four runtime
monkey-patches over executor 2.0.5's claude_code surface, none of
which were specific to Geny. They're folded into the executor proper
here so every consumer benefits without dragging a patch layer.
A. ``--verbose`` auto-injected with stream-json. Claude Code CLI ≥
2.1.x exits with ``Error: When using --print, --output-format=
stream-json requires --verbose`` unless ``--verbose`` is present.
``claude_code_argv`` now emits it alongside the stream-json
switches automatically.
B. ``--bare`` auto-stripped on the OAuth path. The ``--bare`` flag
explicitly disables OAuth + keychain reads, which crashes every
subscription user with ``"Not logged in · Please run /login"``.
``claude_code_argv`` now checks for ``ANTHROPIC_API_KEY`` in the
spawning process's env and omits ``--bare`` when no key is
reachable, so the same ``bare_mode=True`` default works for both
API-key and OAuth auth transparently.
C. Dropped the auto-``--tools \"\"`` emit when MCP is configured.
Earlier executor versions disabled the CLI's built-in palette
(``Bash`` / ``Read`` / ``Write`` / ``Edit`` / …) whenever a host
MCP config was attached, on the theory that the LLM would
otherwise hallucinate against unknown built-ins. In practice
most hosts want *both* surfaces (e.g. a Sub-Worker writing files
via ``Write`` while delegating to MCP-wrapped host tools). Hosts
that want the old MCP-only behaviour can still pass
``extra_args=(\"--tools\", \"\")`` explicitly. ``--strict-mcp-config``
still emits — the MCP surface stays scoped to the host's bridge.
D. ``StreamJsonAccumulator.finalize`` (and ``parse_json_output_to_response``)
now strip ``tool_use`` content blocks from the assembled
``APIResponse``. Claude Code CLI 2.1.x runs the entire agentic
loop *internally* — each intermediate turn arrives as its own
``\"assistant\"`` envelope and the accumulator collected every
block from every envelope. Host pipelines (Geny's Stage 10
etc.) treated those as pending and tried to re-dispatch them
against their own tool registries, producing instant ``ERROR
(0 ms) — No output`` ghost failures for every CLI tool call.
The Phase-I design contract is explicit: ``Stage 10 receives
that assistant message, sees no tool_use blocks (they were
executed inside the CLI), and naturally no-ops`` — so we strip
the blocks at the accumulator boundary. ``stop_reason`` is
preserved verbatim so callers can still distinguish ``end_turn``
from ``tool_use``; hosts that want the raw per-block records
can still get them from the ``feed()`` event stream.
== Test updates ==
Adapted the affected claude_code unit + conformance tests to assert
the new semantics:
- ``test_argv_non_stream_uses_json_output`` / ``test_argv_carries_bare_and_workspace``:
monkeypatch ``ANTHROPIC_API_KEY`` to keep exercising the API-key
path where ``--bare`` is expected.
- ``test_argv_stream_uses_stream_json_io_with_verbose``: assert
the new ``--verbose`` auto-injection.
- ``test_argv_bare_stripped_on_oauth_path``: new test for the
OAuth-path strip.
- ``test_argv_host_mcp_emits_strict_and_keeps_builtins`` /
``test_argv_host_mcp_with_explicit_allow_tools_emits_allowedtools``:
rewritten — built-ins now stay; only ``--strict-mcp-config`` is
emitted in the MCP path.
- ``test_parse_json_output_drops_tool_use_blocks`` /
``test_assemble_drops_tool_use_blocks`` /
``test_send_oneshot_tool_use_blocks_dropped`` /
``test_tool_use_blocks_dropped``: rewritten to assert
``resp.tool_calls == []`` while ``stop_reason`` is preserved.
3127 unit + conformance tests pass, 0 failures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CocoRoF
added a commit
to CocoRoF/Geny
that referenced
this pull request
May 20, 2026
…s.py (#828) geny-executor 2.0.6 (released today, see CocoRoF/geny-executor#208) absorbed four of the five compat patches that previously lived in ``service/llm_patches.py``: A. ``--verbose`` auto-injected when ``--print --output-format= stream-json`` is used (required by Claude Code CLI ≥ 2.1.x). B. ``--bare`` auto-stripped when no ``ANTHROPIC_API_KEY`` is in env, so the OAuth subscription path no longer crashes. C. Dropped the auto-``--tools ""`` emit on MCP-configured spawns — CLI built-ins (``Bash`` / ``Read`` / ``Write`` / ``Edit`` / …) now stay available alongside MCP-wrapped host tools, which is what every host (notably Geny's Sub-Worker) actually wants. D. ``StreamJsonAccumulator.finalize`` (and ``parse_json_output_to_response``) now drop the ``tool_use`` blocks the CLI dispatched internally, so Stage 10 naturally no-ops instead of ghost-erroring against the ``mcp__geny__<name>`` ids it has no registration for. Plus the executor lost the dead ``copilot_cli`` provider entirely (Geny had already removed its end of that wiring in #827). This bumps both pins (``pyproject.toml`` + ``requirements.txt``) from ``>=2.0.5`` to ``>=2.0.6``. ``llm_patches.py`` shrinks from ~830 lines to ~479 lines. Two patches remain — both are Geny-specific and won't fold upstream without the executor gaining hooks Geny is the only consumer of: 1. Friendly Korean error messages for ``is_error`` stream-json result envelopes (auth-expired → Settings card hint, generic API errors → structured short message). Will fold upstream once the executor gains a proper i18n hook. 2. CLI-tool observability into Geny's :class:`SessionLogger` via the new :data:`cli_stream_logger_ctx` ContextVar — taps ``StreamJsonAccumulator.feed`` to surface CLI built-in tool calls (Bash / Read / Write / Edit / …) into the session log alongside the MCP tool entries that ``mcp_bridge_controller`` already emits. ``mcp__*`` prefixed names are skipped so the bridge-side log isn't double-rendered. Will fold upstream once the executor emits first-class CLI-tool events on the pipeline event bus. Tests are rewritten end-to-end: - Old: 21 tests for ``_patched_argv`` predicate + idempotent installer (the patched-argv function is gone). - New: 14 focused tests covering: - ``_friendly_error_message_for_result_envelope`` (3 cases: auth, generic API error, fallback). - ``_maybe_extract_error_envelope`` (bytes/str input + 7 parametrised non-match cases). - ``install_llm_patches`` idempotency + re-export coverage. - Assembler patch end-to-end: raises Korean friendly error on auth-failure envelope; passes through clean streams. - Stream observability: emits ``log_tool_use`` for non-MCP tool blocks; skips ``mcp__*`` to avoid bridge double-render; emits ``log_tool_result`` with duration; handles both string and content-block-list result shapes; inert when no ContextVar is set. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two coordinated changes, bumping the version to 2.0.6.
Removed: `copilot_cli` provider
The `gh copilot` CLI advertises (and the `CopilotCLIClient` honestly mirrored) `supports_streaming=False`, `supports_tools=False`, `supports_mcp_passthrough=False` — it is a one-shot text-in / text-out subprocess that cannot participate in the executor's Stage-10 dispatch or Sub-Worker delegation flows. Keeping the backend encouraged consumers to enable a provider that would fail on the first tool call, so it's removed entirely:
Upstreamed: four Claude-Code CLI compatibility fixes from Geny
The Geny project's `service/llm_patches.py` carried four runtime monkey-patches over 2.0.5's claude_code surface, none of which were specific to Geny. Folded into the executor here:
A. `--verbose` auto-injected with stream-json
Claude Code CLI ≥ 2.1.x exits with `Error: When using --print, --output-format=stream-json requires --verbose` unless `--verbose` is present. `claude_code_argv` now emits it alongside the stream-json switches automatically.
B. `--bare` auto-stripped on the OAuth path
The `--bare` flag explicitly disables OAuth + keychain reads, which crashes every subscription user with `Not logged in · Please run /login`. `claude_code_argv` now checks `ANTHROPIC_API_KEY` and omits `--bare` when no key is reachable, so the same `bare_mode=True` default works for both API-key and OAuth auth transparently.
C. Dropped auto-`--tools ""` emit when MCP is configured
Earlier executor versions disabled the CLI's built-in palette (`Bash` / `Read` / `Write` / `Edit` / …) whenever a host MCP config was attached, on the theory that the LLM would otherwise hallucinate against unknown built-ins. In practice most hosts want both surfaces (e.g. a Sub-Worker writing files via `Write` while delegating to MCP-wrapped host tools). Hosts that want the old MCP-only behaviour can pass `extra_args=("--tools", "")` explicitly. `--strict-mcp-config` still emits.
D. `tool_use` blocks stripped from the assembled `APIResponse`
Claude Code CLI 2.1.x runs the entire agentic loop internally — each intermediate turn arrives as its own `"assistant"` envelope and the accumulator collected every block from every envelope. Host pipelines (Geny's Stage 10 etc.) treated those as pending and tried to re-dispatch them against their own tool registries, producing instant `ERROR (0 ms) — No output` ghost failures for every CLI tool call.
The Phase-I design contract is explicit:
So we strip the blocks at the accumulator boundary (`StreamJsonAccumulator.finalize` + `parse_json_output_to_response`). `stop_reason` is preserved verbatim so callers can still distinguish `end_turn` from `tool_use` for telemetry / retry decisions; hosts that want the raw per-block records can still get them from the `feed()` event stream.
Test results
3127 passed, 8 skipped, 0 failed (1.66 s for claude_code-only subset; 28.9 s for the full suite excluding integration).
Test updates:
Companion changes downstream
The Geny project lands a matching PR (CocoRoF/Geny#827) that:
🤖 Generated with Claude Code