Add Haze CLI provider#2199
Conversation
Implements a new CLI provider that drives Haze headlessly through a small Node.js bridge (haze_headless.mjs). Haze is a model-agnostic terminal agent; this lets Kōan use any OpenAI-compatible backend Haze is configured against (OpenRouter, OpenAI, Z.ai, local endpoints, etc.). Includes: - koan/app/provider/haze.py — HazeProvider implementation - koan/app/provider/haze_headless.mjs — bridge script that imports Haze's runAgentTurn core and emits Koan-compatible JSONL events - koan/tests/test_haze_provider.py — 68 tests covering registry, command building, quota/auth detection, and provider selection - docs/providers/haze.md — setup and troubleshooting guide - README.md / docs/README.md / cli_provider.py / provider/__init__.py updates Co-Authored-By: Claude <noreply@anthropic.com>
|
needs to be finalized once DenizOkcu/haze#9 is available |
Agreed. Two things to settle when PR #9 lands: bridge imports private dist/ paths (streaming.js, settings.js, providers.js) — repoint at the stable headless entry and pin a min haze version. Also |
PR Review — Add Haze CLI providerSolid scaffolding for a new provider, but blocked on upstream and carrying a real model-override bug — not merge-ready, consistent with the maintainer's own note. What's done well:
What needs attention:
Note: I could not read 🟡 Important
1. Monkey-patching an ESM namespace export will throw at runtime
|
Koan-Bot
left a comment
There was a problem hiding this comment.
Blocking issues found.
- Monkey-patching an ESM namespace export will throw at runtime
- Brittle deep imports into Haze's compiled dist/ with no version pinning
- Undocumented magic positional args to runAgentTurn
Implements a new CLI provider that drives Haze headlessly through a small Node.js bridge, so Kōan can use any OpenAI-compatible backend Haze is configured against (OpenRouter, OpenAI, Z.ai, local endpoints, etc.).
What changed
Verification
.venv/bin/ruff check koan/
All checks passed! passes
platform linux -- Python 3.14.4, pytest-9.1.1, pluggy-1.6.0 -- /home/baby/workspace/koan/.venv/bin/python3
cachedir: .pytest_cache
rootdir: /home/baby/workspace/koan
configfile: pyproject.toml
plugins: cov-7.1.0, xdist-3.8.0, timeout-2.4.0
timeout: 60.0s
timeout method: signal
timeout func_only: False
collecting ... collected 68 items
koan/tests/test_haze_provider.py::TestHazePackageStructure::test_import_from_provider_package PASSED [ 1%]
koan/tests/test_haze_provider.py::TestHazePackageStructure::test_import_from_haze_module PASSED [ 2%]
koan/tests/test_haze_provider.py::TestHazePackageStructure::test_facade_reexports_haze PASSED [ 4%]
koan/tests/test_haze_provider.py::TestHazePackageStructure::test_haze_in_provider_registry PASSED [ 5%]
koan/tests/test_haze_provider.py::TestHazePackageStructure::test_registry_creates_haze_instance PASSED [ 7%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_binary PASSED [ 8%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_shell_command PASSED [ 10%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_name PASSED [ 11%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_supports_stream_json PASSED [ 13%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_supports_last_message_file PASSED [ 14%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_last_message_file_args PASSED [ 16%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_last_message_file_args_empty PASSED [ 17%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_add_last_message_file_args PASSED [ 19%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_add_last_message_file_args_empty_path PASSED [ 20%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_does_not_support_stdin_prompt_passing PASSED [ 22%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_invocation_lock_name PASSED [ 23%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_tool_args_allowed_ignored PASSED [ 25%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_tool_args_disallowed_ignored PASSED [ 26%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_tool_args_empty PASSED [ 27%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_model_args PASSED [ 29%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_model_args_empty PASSED [ 30%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_model_args_fallback_ignored PASSED [ 32%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_output_args PASSED [ 33%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_max_turns_args PASSED [ 35%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_mcp_args PASSED [ 36%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_plugin_args_ignored PASSED [ 38%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_effort_args_ignored PASSED [ 39%]
koan/tests/test_haze_provider.py::TestHazeProvider::test_permission_args PASSED [ 41%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_minimal PASSED [ 42%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_includes_bridge_script PASSED [ 44%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_with_model PASSED [ 45%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_system_prompt_prepended PASSED [ 47%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_fallback_ignored PASSED [ 48%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_tools_ignored PASSED [ 50%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_mcp_ignored PASSED [ 51%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_plugin_dirs_ignored PASSED [ 52%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_full_command_shape PASSED [ 54%]
koan/tests/test_haze_provider.py::TestHazeBuildCommand::test_build_command_when_not_installed PASSED [ 55%]
koan/tests/test_haze_provider.py::TestHazeExtraFlags::test_with_model PASSED [ 57%]
koan/tests/test_haze_provider.py::TestHazeExtraFlags::test_with_disallowed_tools PASSED [ 58%]
koan/tests/test_haze_provider.py::TestHazeExtraFlags::test_combined PASSED [ 60%]
koan/tests/test_haze_provider.py::TestHazeProviderSelection::test_env_var_selects_haze PASSED [ 61%]
koan/tests/test_haze_provider.py::TestHazeProviderSelection::test_get_provider_returns_haze PASSED [ 63%]
koan/tests/test_haze_provider.py::TestHazeProviderSelection::test_build_full_command_uses_haze PASSED [ 64%]
koan/tests/test_haze_provider.py::TestResolveHazeRoot::test_override_env_var PASSED [ 66%]
koan/tests/test_haze_provider.py::TestResolveHazeRoot::test_override_env_var_invalid_path_returns_none PASSED [ 67%]
koan/tests/test_haze_provider.py::TestResolveHazeRoot::test_returns_none_when_not_installed PASSED [ 69%]
koan/tests/test_haze_provider.py::TestHazeIsAvailable::test_available PASSED [ 70%]
koan/tests/test_haze_provider.py::TestHazeIsAvailable::test_not_available_no_node PASSED [ 72%]
koan/tests/test_haze_provider.py::TestHazeIsAvailable::test_not_available_no_haze PASSED [ 73%]
koan/tests/test_haze_provider.py::TestHazeQuotaDetection::test_detects_quota_in_stderr PASSED [ 75%]
koan/tests/test_haze_provider.py::TestHazeQuotaDetection::test_detects_rate_limit_in_stderr PASSED [ 76%]
koan/tests/test_haze_provider.py::TestHazeQuotaDetection::test_detects_quota_in_result_error_event PASSED [ 77%]
koan/tests/test_haze_provider.py::TestHazeQuotaDetection::test_does_not_flag_success_result PASSED [ 79%]
koan/tests/test_haze_provider.py::TestHazeQuotaDetection::test_ignores_plain_quota_words_on_success_stdout PASSED [ 80%]
koan/tests/test_haze_provider.py::TestHazeQuotaDetection::test_ignores_benign_prose_on_failed_stdout PASSED [ 82%]
koan/tests/test_haze_provider.py::TestHazeAuthDetection::test_detects_401_in_stderr PASSED [ 83%]
koan/tests/test_haze_provider.py::TestHazeAuthDetection::test_detects_invalid_api_key_in_stderr PASSED [ 85%]
koan/tests/test_haze_provider.py::TestHazeAuthDetection::test_detects_no_provider_configured_in_result PASSED [ 86%]
koan/tests/test_haze_provider.py::TestHazeAuthDetection::test_detects_auth_in_assistant_text PASSED [ 88%]
koan/tests/test_haze_provider.py::TestHazeAuthDetection::test_returns_false_on_success_exit PASSED [ 89%]
koan/tests/test_haze_provider.py::TestHazeAuthDetection::test_returns_false_for_unrelated_error PASSED [ 91%]
koan/tests/test_haze_provider.py::TestHazeQuotaCheck::test_success PASSED [ 92%]
koan/tests/test_haze_provider.py::TestHazeQuotaCheck::test_not_installed PASSED [ 94%]
koan/tests/test_haze_provider.py::TestHazeQuotaCheck::test_timeout_proceeds_optimistically PASSED [ 95%]
koan/tests/test_haze_provider.py::TestHazeQuotaCheck::test_generic_error_proceeds_optimistically PASSED [ 97%]
koan/tests/test_haze_provider.py::TestHazeQuotaCheck::test_auth_failure_blocks_preflight PASSED [ 98%]
koan/tests/test_haze_provider.py::TestHazeQuotaCheck::test_quota_failure_blocks_preflight PASSED [100%]
============================== 68 passed in 0.23s ============================== — 68 passed
🤖 Generated with Claude Code