Adopt felix 0.3.0 native async providers#32
Merged
Conversation
Deliberation now runs natively on the event loop via acomplete() instead of asyncio.to_thread: - ClaudeCodeProvider.acomplete(): true async subprocess (create_subprocess_exec); timeout and cancellation kill the CLI process instead of orphaning it. complete() and acomplete() share _build_invocation/_parse_cli_output. - RimWorldRoleAgent: _acall_provider (native acomplete with worker-thread fallback for providers without async support), aprocess_task (async mirror of the SDK pipeline — the SDK exposes async only at the provider layer), adeliberate + async parse-retry. - Game loop awaits adeliberate directly; a deliberation timeout now cancels the in-flight provider request rather than leaving a hung worker thread running until the provider timeout. Sync deliberate() is kept for tests and non-loop callers. Smoke test wall-clock dropped 40.6s -> 27.8s with identical scores. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI smoke test runs --dry-run, whose MagicMock provider only set complete.return_value; the async deliberation path got a bare AsyncMock coroutine back. Mirror complete.return_value on acomplete. Co-Authored-By: Claude Fable 5 <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.
Summary
Follow-up to #31: actually adopt the 0.3.0 async provider interface instead of just bumping the pin.
asyncio.create_subprocess_exec; timeout and cancellation now kill the CLI process instead of orphaning it.complete()/acomplete()share extracted_build_invocation/_parse_cli_outputhelpers._acall_provider()(nativeacomplete()with a worker-thread fallback for providers that lack async),aprocess_task()(async mirror of the SDK pipeline — the SDK exposes async only at the provider layer,LLMAgent.process_taskis still sync),adeliberate()+ async parse-retry. No-think prefill, Weave wrapping, and token accounting all preserved on the async path.adeliberate()directly;ROLE_TIMEOUT_Snow cancels the in-flight request rather than leaving a hung thread running until the provider timeout (the old "Python threads can't be killed" caveat no longer applies).Sync
deliberate()is kept for tests and non-loop callers.Verification
pytest: 458 passed (8 new async tests: adeliberate pipeline, no-async fallback, no-think prefill on async path, subprocess kill on timeout/cancellation)ruff+mypy src/(strict): clean🤖 Generated with Claude Code