diff --git a/.github/workflows/ci-run.yml b/.github/workflows/ci-run.yml index a0a0cbd1a..3eac81d42 100644 --- a/.github/workflows/ci-run.yml +++ b/.github/workflows/ci-run.yml @@ -93,7 +93,7 @@ jobs: - name: Build binary (smoke check) run: cargo build --profile release-fast --locked --verbose - name: Check binary size - run: ./scripts/ci/check_binary_size.sh target/release/zeroclaw + run: bash scripts/ci/check_binary_size.sh target/release-fast/zeroclaw docs-only: name: Docs-Only Fast Path diff --git a/.github/workflows/pub-release.yml b/.github/workflows/pub-release.yml index d561b146e..dde489d42 100644 --- a/.github/workflows/pub-release.yml +++ b/.github/workflows/pub-release.yml @@ -208,7 +208,7 @@ jobs: - name: Check binary size (Unix) if: runner.os != 'Windows' - run: ./scripts/ci/check_binary_size.sh "target/${{ matrix.target }}/release-fast/${{ matrix.artifact }}" "${{ matrix.target }}" + run: bash scripts/ci/check_binary_size.sh "target/${{ matrix.target }}/release-fast/${{ matrix.artifact }}" "${{ matrix.target }}" - name: Package (Unix) if: runner.os != 'Windows' diff --git a/src/agent/agent.rs b/src/agent/agent.rs index d1affdaaf..67ef5baf7 100644 --- a/src/agent/agent.rs +++ b/src/agent/agent.rs @@ -421,7 +421,7 @@ impl Agent { .iter() .map(|call| self.execute_tool_call(call)) .collect(); - futures::future::join_all(futs).await + futures_util::future::join_all(futs).await } fn classify_model(&self, user_message: &str) -> String { diff --git a/src/agent/loop_.rs b/src/agent/loop_.rs index 0b8d25118..fbedd4835 100644 --- a/src/agent/loop_.rs +++ b/src/agent/loop_.rs @@ -1083,7 +1083,7 @@ async fn execute_tools_parallel( }) .collect(); - let results = futures::future::join_all(futures).await; + let results = futures_util::future::join_all(futures).await; results.into_iter().collect() } diff --git a/src/memory/cli.rs b/src/memory/cli.rs index 168375549..0e7637081 100644 --- a/src/memory/cli.rs +++ b/src/memory/cli.rs @@ -4,7 +4,9 @@ use super::{ MemoryBackendKind, }; use crate::config::Config; -use anyhow::{bail, Context, Result}; +use anyhow::{bail, Result}; +#[cfg(feature = "memory-postgres")] +use anyhow::Context; use console::style; /// Handle `zeroclaw memory ` CLI commands. @@ -39,6 +41,7 @@ fn create_cli_memory(config: &Config) -> Result> { MemoryBackendKind::None => { bail!("Memory backend is 'none' (disabled). No entries to manage."); } + #[cfg(feature = "memory-postgres")] MemoryBackendKind::Postgres => { let sp = &config.storage.provider.config; let db_url = sp @@ -53,6 +56,10 @@ fn create_cli_memory(config: &Config) -> Result> { super::PostgresMemory::new(db_url, &sp.schema, &sp.table, sp.connect_timeout_secs)?; Ok(Box::new(mem)) } + #[cfg(not(feature = "memory-postgres"))] + MemoryBackendKind::Postgres => { + bail!("memory backend 'postgres' requires the 'memory-postgres' feature to be enabled"); + } _ => create_memory_for_migration(&backend, &config.workspace_dir), } } diff --git a/src/providers/reliable.rs b/src/providers/reliable.rs index 6a8ec1a96..c430a93a2 100644 --- a/src/providers/reliable.rs +++ b/src/providers/reliable.rs @@ -659,115 +659,6 @@ impl Provider for ReliableProvider { .any(|(_, provider)| provider.supports_vision()) } - async fn chat( - &self, - request: ChatRequest<'_>, - model: &str, - temperature: f64, - ) -> anyhow::Result { - let models = self.model_chain(model); - let mut failures = Vec::new(); - - for current_model in &models { - for (provider_name, provider) in &self.providers { - let mut backoff_ms = self.base_backoff_ms; - - for attempt in 0..=self.max_retries { - let req = ChatRequest { - messages: request.messages, - tools: request.tools, - }; - match provider.chat(req, current_model, temperature).await { - Ok(resp) => { - if attempt > 0 || *current_model != model { - tracing::info!( - provider = provider_name, - model = *current_model, - attempt, - original_model = model, - "Provider recovered (failover/retry)" - ); - } - return Ok(resp); - } - Err(e) => { - let non_retryable_rate_limit = is_non_retryable_rate_limit(&e); - let non_retryable = is_non_retryable(&e) || non_retryable_rate_limit; - let rate_limited = is_rate_limited(&e); - let failure_reason = failure_reason(rate_limited, non_retryable); - let error_detail = compact_error_detail(&e); - - push_failure( - &mut failures, - provider_name, - current_model, - attempt + 1, - self.max_retries + 1, - failure_reason, - &error_detail, - ); - - if rate_limited && !non_retryable_rate_limit { - if let Some(new_key) = self.rotate_key() { - tracing::info!( - provider = provider_name, - error = %error_detail, - "Rate limited, rotated API key (key ending ...{})", - &new_key[new_key.len().saturating_sub(4)..] - ); - } - } - - if non_retryable { - tracing::warn!( - provider = provider_name, - model = *current_model, - error = %error_detail, - "Non-retryable error, moving on" - ); - - if is_context_window_exceeded(&e) { - anyhow::bail!( - "Request exceeds model context window; retries and fallbacks were skipped. Attempts:\n{}", - failures.join("\n") - ); - } - - break; - } - - if attempt < self.max_retries { - let wait = self.compute_backoff(backoff_ms, &e); - tracing::warn!( - provider = provider_name, - model = *current_model, - attempt = attempt + 1, - backoff_ms = wait, - reason = failure_reason, - error = %error_detail, - "Provider call failed, retrying" - ); - tokio::time::sleep(Duration::from_millis(wait)).await; - backoff_ms = (backoff_ms.saturating_mul(2)).min(10_000); - } - } - } - } - - tracing::warn!( - provider = provider_name, - model = *current_model, - "Exhausted retries, trying next provider/model" - ); - } - } - - anyhow::bail!( - "All providers/models failed. Attempts:\n{}", - failures.join("\n") - ) - } - async fn chat_with_tools( &self, messages: &[ChatMessage],