From 63afbaa6c51e055578d4d575afc0919ca3ff8fc0 Mon Sep 17 00:00:00 2001 From: Reid <61492567+reidliu41@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:07:26 +0800 Subject: [PATCH] fix(setup): drain residual terminal events before secret input (#747) (#849) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(ci): secrets can't be used in step if conditions [skip-regression-check] (#787) GitHub Actions step-level `if:` doesn't have access to `secrets` context. Replace `if: secrets.X != ''` with `continue-on-error: true` and let the Set token step handle the fallback. Co-authored-by: Claude Sonnet 4.6 * fix(ci): clean up staging pipeline — remove hacks, skip redundant checks [skip-regression-check] (#794) - Remove continue-on-error from staging-ci.yml app token steps (secrets are configured) - Skip test.yml and code_style.yml on PRs targeting staging (staging-ci.yml already runs tests before promoting, promotion PR gets full CI on main) - Allow ironclaw-ci[bot] in Claude Code review for bot-created promotion PRs Co-authored-by: Claude Opus 4.6 * fix(ci): run fmt + clippy on staging PRs, skip Windows clippy [skip-regression-check] (#802) - Remove branches:[main] filter from code_style.yml so it runs on all PRs - Gate clippy-windows with `if: github.base_ref == 'main'` (skip on staging PRs) - Update rollup job to allow skipped clippy-windows - Simplify claude-review.yml to only trigger on labeled event (avoids duplicate runs) Co-authored-by: Claude Opus 4.6 * feat: persist user_id in save_job and expose job_id on routine runs (#709) * feat: persist worker events to DB and fix activity tab rendering In-process Worker (used by Scheduler::dispatch_job) now persists events via save_job_event at key execution points: plan creation, LLM responses, tool_use, tool_result, and job completion/failure/stuck. Event data shapes match the container worker format so the gateway activity tab renders them correctly. Frontend: tool_result errors now show a red X icon with danger styling instead of a silent empty output. The result event falls back to the error field when message is absent. Co-Authored-By: Claude Opus 4.6 * feat: wire RoutineEngine into gateway for direct manual trigger firing Replace the message-channel hack in routines_trigger_handler with a direct call to RoutineEngine::fire_manual(), ensuring FullJob routines dispatch correctly when triggered from the web UI. Inject the engine into GatewayState from Agent::run after construction. Also persists user_id in save_job for both PG and libSQL backends, removes the source='sandbox' filter so all jobs are visible, and exposes job_id on RoutineRunInfo for the frontend job link. Co-Authored-By: Claude Opus 4.6 * fix: remove stale gateway_state argument from Agent::new test call sites The gateway_state parameter was removed from Agent::new during rebase (replaced by post-construction set_routine_engine_slot), but three test call sites still passed the extra None argument. Co-Authored-By: Claude Opus 4.6 * fix: address PR review — restore sandbox source filter, remove blank lines - Revert removal of `source = 'sandbox'` filter in all SandboxStore queries (8 sites across PG and libSQL). Sandbox-specific APIs should stay scoped to sandbox jobs; unified job listing for the Jobs tab should use a separate query path. - Remove extra blank lines in agent_loop.rs and worker.rs that caused formatting CI failure. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 * fix: address review — regenerate Cargo.lock, add user_id regression test - Regenerate Cargo.lock from main's lockfile to eliminate dependency version downgrades (anyhow, syn, etc.) that were churn from rebase. - Add regression test verifying user_id round-trips through save_job and get_job in the libSQL backend. Co-Authored-By: Claude Opus 4.6 * style: remove trailing blank line in libsql jobs.rs [skip-regression-check] Co-Authored-By: Claude Opus 4.6 * test: add Postgres-side regression test for user_id persistence in save_job Mirrors the existing libSQL test (test_save_job_persists_user_id) for the Postgres backend. Gated behind #[cfg(feature = "postgres")] + #[ignore] since it requires a running PostgreSQL instance (integration tier). Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 * feat(llm): per-provider unsupported parameter filtering (#749, #728) (#809) Add declarative `unsupported_params` field to provider definitions in providers.json. Parameters listed are stripped from requests before sending, preventing 400 errors from providers that reject them (e.g. gpt-5 family and kimi-k2.5 rejecting custom temperature values). - Add `unsupported_params` to ProviderDefinition and RegistryProviderConfig - Propagate from registry through config resolution - Generic strip helpers handle temperature, max_tokens, stop_sequences - Apply filtering in RigAdapter and AnthropicOAuthProvider - Mark openai and tinfoil providers as unsupporting temperature - Update openai default model to gpt-5-mini Co-authored-by: Claude Opus 4.6 * fix: skip the regression check [skip-regression-check] --------- Co-authored-by: Henry Park Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Illia Polosukhin --- src/setup/README.md | 19 +++++++++---------- src/setup/prompts.rs | 10 ++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/setup/README.md b/src/setup/README.md index b94b3d0b..4b734e36 100644 --- a/src/setup/README.md +++ b/src/setup/README.md @@ -209,19 +209,18 @@ env-var mode or skipped secrets. | Anthropic | API key | `anthropic_api_key` | `ANTHROPIC_API_KEY` | | OpenAI | API key | `openai_api_key` | `OPENAI_API_KEY` | | Ollama | None | - | - | -| OpenRouter¹ | API key | `llm_compatible_api_key` | `LLM_API_KEY` | -| OpenAI-compatible¹ | Optional API key | `llm_compatible_api_key` | `LLM_API_KEY` | +| OpenRouter | API key | `llm_openrouter_api_key` | `OPENROUTER_API_KEY` | +| OpenAI-compatible | Optional API key | `llm_compatible_api_key` | `LLM_API_KEY` | | AWS Bedrock | AWS credentials (IAM, SSO, instance roles) | - | - | -¹ OpenRouter and OpenAI-compatible share the same secret name and env var because -OpenRouter is stored as `llm_backend = "openai_compatible"` under the hood. -Switching between them overwrites the same credential slot. +**OpenRouter** is a standalone registry provider (`providers.json` id `"openrouter"`) +with its own secret name and env var. It is **not** stored as `openai_compatible`. -**OpenRouter** (`setup_openrouter`): -- Pre-configured OpenAI-compatible preset with base URL `https://openrouter.ai/api/v1` -- Delegates to `setup_api_key_provider()` with a display name override ("OpenRouter") -- Sets `llm_backend = "openai_compatible"` and `openai_compatible_base_url` automatically -- Clears `selected_model` so Step 4 prompts for a model name (manual text input, no API-based model fetching) +**OpenRouter** (`setup.kind = "api_key"` in `providers.json`): +- Standalone provider with base URL `https://openrouter.ai/api/v1` +- Delegates to `setup_api_key_provider()` with display name "OpenRouter" +- API key is required (`api_key_required: true`) +- Default model: `openai/gpt-4o` **API-key providers** (`setup_api_key_provider`): 1. Check env var → if set, ask to reuse, persist to secrets store diff --git a/src/setup/prompts.rs b/src/setup/prompts.rs index df4cbbc2..a52a8b68 100644 --- a/src/setup/prompts.rs +++ b/src/setup/prompts.rs @@ -200,6 +200,16 @@ fn read_secret_line() -> io::Result { let mut input = String::new(); let mut stdout = io::stdout(); + // Drain any residual key events (e.g. Enter from a prior `read_line` prompt) + // that are already queued before we start reading. Without this, on + // Windows the leftover Enter is immediately consumed and the function + // returns an empty string before the user can type anything. + // Uses Duration::ZERO so we never block waiting for new input — only + // events already in the queue are consumed. + while event::poll(std::time::Duration::ZERO)? { + let _ = event::read()?; + } + loop { if let Event::Key(KeyEvent { code, modifiers, ..