From 1440ec742259646f9c8eae944e301599764d217c Mon Sep 17 00:00:00 2001 From: Henry Park Date: Mon, 9 Mar 2026 16:58:56 -0700 Subject: [PATCH 1/7] 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 --- .github/workflows/staging-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/staging-ci.yml b/.github/workflows/staging-ci.yml index 9e887436..22d70030 100644 --- a/.github/workflows/staging-ci.yml +++ b/.github/workflows/staging-ci.yml @@ -115,7 +115,7 @@ jobs: - name: Generate GitHub App token id: app-token - if: ${{ secrets.GH_RELEASES_MANAGER_APP_ID != '' }} + continue-on-error: true uses: actions/create-github-app-token@v2 with: app-id: ${{ secrets.GH_RELEASES_MANAGER_APP_ID }} @@ -230,7 +230,7 @@ jobs: - name: Generate GitHub App token id: app-token - if: ${{ secrets.GH_RELEASES_MANAGER_APP_ID != '' }} + continue-on-error: true uses: actions/create-github-app-token@v2 with: app-id: ${{ secrets.GH_RELEASES_MANAGER_APP_ID }} From b53986f00b994060f36808ca18a60903cb8626ef Mon Sep 17 00:00:00 2001 From: Henry Park Date: Mon, 9 Mar 2026 17:35:06 -0700 Subject: [PATCH 2/7] =?UTF-8?q?fix(ci):=20clean=20up=20staging=20pipeline?= =?UTF-8?q?=20=E2=80=94=20remove=20hacks,=20skip=20redundant=20checks=20[s?= =?UTF-8?q?kip-regression-check]=20(#794)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .github/workflows/claude-review.yml | 1 + .github/workflows/code_style.yml | 2 ++ .github/workflows/staging-ci.yml | 2 -- .github/workflows/test.yml | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 86d1bb2f..24d2fe98 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -28,6 +28,7 @@ jobs: uses: anthropics/claude-code-action@v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + allowed_bots: "ironclaw-ci[bot]" claude_args: "--max-turns 50 --model claude-haiku-4-5-20251001 --allowedTools 'Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*),Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh search:*),Bash(git blame:*),Bash(git log:*),Bash(git diff:*)'" prompt: | Code review this pull request. Follow these steps precisely: diff --git a/.github/workflows/code_style.yml b/.github/workflows/code_style.yml index 526c7740..c65aa0df 100644 --- a/.github/workflows/code_style.yml +++ b/.github/workflows/code_style.yml @@ -1,6 +1,8 @@ name: Code Style on: pull_request: + branches: + - main jobs: format: diff --git a/.github/workflows/staging-ci.yml b/.github/workflows/staging-ci.yml index 22d70030..8e3693b2 100644 --- a/.github/workflows/staging-ci.yml +++ b/.github/workflows/staging-ci.yml @@ -115,7 +115,6 @@ jobs: - name: Generate GitHub App token id: app-token - continue-on-error: true uses: actions/create-github-app-token@v2 with: app-id: ${{ secrets.GH_RELEASES_MANAGER_APP_ID }} @@ -230,7 +229,6 @@ jobs: - name: Generate GitHub App token id: app-token - continue-on-error: true uses: actions/create-github-app-token@v2 with: app-id: ${{ secrets.GH_RELEASES_MANAGER_APP_ID }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index efa28648..bb29dd2a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,8 @@ name: Run Tests on: workflow_call: pull_request: + branches: + - main push: branches: - main From 6e12ce6f2db8e6632ff5c95bbd0b8285ba90d4ca Mon Sep 17 00:00:00 2001 From: Henry Park Date: Mon, 9 Mar 2026 18:43:16 -0700 Subject: [PATCH 3/7] 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 --- .github/workflows/claude-review.yml | 2 +- .github/workflows/code_style.yml | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 24d2fe98..3836a5f9 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -2,7 +2,7 @@ name: Claude Code Review on: pull_request: - types: [opened, labeled] + types: [labeled] permissions: contents: read diff --git a/.github/workflows/code_style.yml b/.github/workflows/code_style.yml index c65aa0df..620760ae 100644 --- a/.github/workflows/code_style.yml +++ b/.github/workflows/code_style.yml @@ -1,8 +1,6 @@ name: Code Style on: pull_request: - branches: - - main jobs: format: @@ -46,6 +44,7 @@ jobs: clippy-windows: name: Clippy Windows (${{ matrix.name }}) + if: github.base_ref == 'main' runs-on: windows-latest strategy: fail-fast: false @@ -78,7 +77,12 @@ jobs: needs: [format, clippy, clippy-windows] steps: - run: | - if [[ "${{ needs.format.result }}" != "success" || "${{ needs.clippy.result }}" != "success" || "${{ needs.clippy-windows.result }}" != "success" ]]; then + if [[ "${{ needs.format.result }}" != "success" || "${{ needs.clippy.result }}" != "success" ]]; then echo "One or more jobs failed" exit 1 fi + # clippy-windows only runs on main PRs, so skip/success are both acceptable + if [[ "${{ needs.clippy-windows.result }}" == "failure" ]]; then + echo "Windows clippy failed" + exit 1 + fi From bcef04b82108222c9041e733de459130badd4cd7 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Tue, 10 Mar 2026 01:51:43 +0000 Subject: [PATCH 4/7] feat: persist user_id in save_job and expose job_id on routine runs (#709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- src/channels/web/handlers/routines.rs | 2 ++ src/channels/web/server.rs | 2 ++ src/channels/web/types.rs | 1 + src/db/libsql/jobs.rs | 5 +++- src/db/libsql/mod.rs | 18 +++++++++++++ src/history/store.rs | 37 ++++++++++++++++++++++++++- 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/channels/web/handlers/routines.rs b/src/channels/web/handlers/routines.rs index d7c4f764..8fbcc97b 100644 --- a/src/channels/web/handlers/routines.rs +++ b/src/channels/web/handlers/routines.rs @@ -108,6 +108,7 @@ pub async fn routines_detail_handler( status: format!("{:?}", run.status), result_summary: run.result_summary.clone(), tokens_used: run.tokens_used, + job_id: run.job_id, }) .collect(); @@ -252,6 +253,7 @@ pub async fn routines_runs_handler( status: format!("{:?}", run.status), result_summary: run.result_summary.clone(), tokens_used: run.tokens_used, + job_id: run.job_id, }) .collect(); diff --git a/src/channels/web/server.rs b/src/channels/web/server.rs index d6605eee..f454363d 100644 --- a/src/channels/web/server.rs +++ b/src/channels/web/server.rs @@ -2017,6 +2017,7 @@ async fn routines_detail_handler( status: format!("{:?}", run.status), result_summary: run.result_summary.clone(), tokens_used: run.tokens_used, + job_id: run.job_id, }) .collect(); @@ -2169,6 +2170,7 @@ async fn routines_runs_handler( status: format!("{:?}", run.status), result_summary: run.result_summary.clone(), tokens_used: run.tokens_used, + job_id: run.job_id, }) .collect(); diff --git a/src/channels/web/types.rs b/src/channels/web/types.rs index 4d85c671..b6d0d05a 100644 --- a/src/channels/web/types.rs +++ b/src/channels/web/types.rs @@ -776,6 +776,7 @@ pub struct RoutineRunInfo { pub status: String, pub result_summary: Option, pub tokens_used: Option, + pub job_id: Option, } // --- Settings --- diff --git a/src/db/libsql/jobs.rs b/src/db/libsql/jobs.rs index d5172360..0750873d 100644 --- a/src/db/libsql/jobs.rs +++ b/src/db/libsql/jobs.rs @@ -28,14 +28,16 @@ impl JobStore for LibSqlBackend { r#" INSERT INTO agent_jobs ( id, conversation_id, title, description, category, status, source, + user_id, budget_amount, budget_token, bid_amount, estimated_cost, estimated_time_secs, actual_cost, repair_attempts, created_at, started_at, completed_at - ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17) + ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18) ON CONFLICT (id) DO UPDATE SET title = excluded.title, description = excluded.description, category = excluded.category, status = excluded.status, + user_id = excluded.user_id, estimated_cost = excluded.estimated_cost, estimated_time_secs = excluded.estimated_time_secs, actual_cost = excluded.actual_cost, @@ -51,6 +53,7 @@ impl JobStore for LibSqlBackend { opt_text(ctx.category.as_deref()), status, "direct", + ctx.user_id.as_str(), opt_text_owned(ctx.budget.map(|d| d.to_string())), opt_text(ctx.budget_token.as_deref()), opt_text_owned(ctx.bid_amount.map(|d| d.to_string())), diff --git a/src/db/libsql/mod.rs b/src/db/libsql/mod.rs index 2845c757..404441e6 100644 --- a/src/db/libsql/mod.rs +++ b/src/db/libsql/mod.rs @@ -482,6 +482,24 @@ mod tests { assert_eq!(timeout, 5000); } + /// Regression test: save_job must persist user_id and get_job must return it. + #[tokio::test] + async fn test_save_job_persists_user_id() { + use crate::context::JobContext; + use crate::db::JobStore; + + let dir = tempfile::tempdir().unwrap(); + let db_path = dir.path().join("test_user_id.db"); + let backend = LibSqlBackend::new_local(&db_path).await.unwrap(); + backend.run_migrations().await.unwrap(); + + let ctx = JobContext::with_user("test-user-42", "Test Job", "A test job"); + backend.save_job(&ctx).await.unwrap(); + + let loaded = backend.get_job(ctx.job_id).await.unwrap().unwrap(); + assert_eq!(loaded.user_id, "test-user-42"); + } + #[tokio::test] async fn test_concurrent_writes_succeed() { // Use a temp file so connections share state (in-memory DBs are connection-local) diff --git a/src/history/store.rs b/src/history/store.rs index f0b0b144..1153f3e4 100644 --- a/src/history/store.rs +++ b/src/history/store.rs @@ -149,14 +149,16 @@ impl Store { r#" INSERT INTO agent_jobs ( id, conversation_id, title, description, category, status, source, + user_id, budget_amount, budget_token, bid_amount, estimated_cost, estimated_time_secs, actual_cost, repair_attempts, created_at, started_at, completed_at - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) ON CONFLICT (id) DO UPDATE SET title = EXCLUDED.title, description = EXCLUDED.description, category = EXCLUDED.category, status = EXCLUDED.status, + user_id = EXCLUDED.user_id, estimated_cost = EXCLUDED.estimated_cost, estimated_time_secs = EXCLUDED.estimated_time_secs, actual_cost = EXCLUDED.actual_cost, @@ -172,6 +174,7 @@ impl Store { &ctx.category, &status, &"direct", // source + &ctx.user_id, &ctx.budget, &ctx.budget_token, &ctx.bid_amount, @@ -2133,4 +2136,36 @@ mod tests { assert_eq!(summary.channel, ch); } } + + /// Regression test: save_job must persist user_id and get_job must return it. + /// Requires a running PostgreSQL instance (integration tier). + #[cfg(feature = "postgres")] + #[tokio::test] + #[ignore] + async fn test_save_job_persists_user_id() { + use crate::config::Config; + use crate::context::JobContext; + + let _ = dotenvy::dotenv(); + let config = Config::from_env().await.expect("Failed to load config"); + let store = Store::new(&config.database) + .await + .expect("Failed to connect to database"); + store + .run_migrations() + .await + .expect("Failed to run migrations"); + + let ctx = JobContext::with_user("test-user-42", "PG user_id test", "regression test"); + store.save_job(&ctx).await.unwrap(); + + let loaded = store.get_job(ctx.job_id).await.unwrap().unwrap(); + assert_eq!(loaded.user_id, "test-user-42"); + + // Clean up + let conn = store.conn().await.unwrap(); + conn.execute("DELETE FROM agent_jobs WHERE id = $1", &[&ctx.job_id]) + .await + .unwrap(); + } } From 2016693b0c26eabaae00c4fd1602d3d7819fdbaa Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Tue, 10 Mar 2026 07:11:26 +0000 Subject: [PATCH 5/7] 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 --- providers.json | 4 +- src/config/llm.rs | 10 +++ src/llm/anthropic_oauth.rs | 44 ++++++++++- src/llm/config.rs | 4 + src/llm/mod.rs | 12 ++- src/llm/registry.rs | 56 ++++++++++++++ src/llm/rig_adapter.rs | 146 ++++++++++++++++++++++++++++++++++++- src/setup/wizard.rs | 1 + 8 files changed, 267 insertions(+), 10 deletions(-) diff --git a/providers.json b/providers.json index a9398a87..f7574f4c 100644 --- a/providers.json +++ b/providers.json @@ -9,8 +9,9 @@ "api_key_required": true, "base_url_env": "OPENAI_BASE_URL", "model_env": "OPENAI_MODEL", - "default_model": "gpt-4o", + "default_model": "gpt-5-mini", "description": "OpenAI GPT models (direct API)", + "unsupported_params": ["temperature"], "setup": { "kind": "api_key", "secret_name": "llm_openai_api_key", @@ -86,6 +87,7 @@ "model_env": "TINFOIL_MODEL", "default_model": "kimi-k2-5", "description": "Tinfoil private inference (hardware-attested TEE)", + "unsupported_params": ["temperature"], "setup": { "kind": "api_key", "secret_name": "llm_tinfoil_api_key", diff --git a/src/config/llm.rs b/src/config/llm.rs index 08a59866..cc02cd31 100644 --- a/src/config/llm.rs +++ b/src/config/llm.rs @@ -209,6 +209,7 @@ impl LlmConfig { extra_headers_env, api_key_required, base_url_required, + unsupported_params, ) = if let Some(def) = def { ( def.id.as_str(), @@ -221,6 +222,7 @@ impl LlmConfig { def.extra_headers_env.as_deref(), def.api_key_required, def.base_url_required, + def.unsupported_params.clone(), ) } else { // Absolute fallback: treat as generic openai_completions @@ -235,6 +237,7 @@ impl LlmConfig { Some("LLM_EXTRA_HEADERS"), false, true, + Vec::new(), ) }; @@ -338,6 +341,7 @@ impl LlmConfig { extra_headers, oauth_token, cache_retention, + unsupported_params, }) } } @@ -624,6 +628,12 @@ mod tests { let provider = cfg.provider.expect("provider config should be present"); assert_eq!(provider.base_url, "https://inference.tinfoil.sh/v1"); assert_eq!(provider.model, "kimi-k2-5"); + assert!( + provider + .unsupported_params + .contains(&"temperature".to_string()), + "tinfoil should propagate unsupported_params from registry" + ); } #[test] diff --git a/src/llm/anthropic_oauth.rs b/src/llm/anthropic_oauth.rs index 104778ad..0badda93 100644 --- a/src/llm/anthropic_oauth.rs +++ b/src/llm/anthropic_oauth.rs @@ -6,6 +6,8 @@ //! //! Pattern follows `nearai_chat.rs`: direct HTTP calls via `reqwest::Client`. +use std::collections::HashSet; + use async_trait::async_trait; use reqwest::Client; use rust_decimal::Decimal; @@ -35,6 +37,8 @@ pub struct AnthropicOAuthProvider { model: String, base_url: Option, active_model: std::sync::RwLock, + /// Parameter names that this provider does not support. + unsupported_params: HashSet, } impl AnthropicOAuthProvider { @@ -61,15 +65,45 @@ impl AnthropicOAuthProvider { Some(config.base_url.clone()) }; + let unsupported_params: HashSet = + config.unsupported_params.iter().cloned().collect(); + Ok(Self { client, token, model: config.model.clone(), base_url, active_model, + unsupported_params, }) } + /// Strip unsupported fields from a `CompletionRequest` in place. + fn strip_unsupported_completion_params(&self, req: &mut CompletionRequest) { + if self.unsupported_params.is_empty() { + return; + } + if self.unsupported_params.contains("temperature") { + req.temperature = None; + } + if self.unsupported_params.contains("max_tokens") { + req.max_tokens = None; + } + } + + /// Strip unsupported fields from a `ToolCompletionRequest` in place. + fn strip_unsupported_tool_params(&self, req: &mut ToolCompletionRequest) { + if self.unsupported_params.is_empty() { + return; + } + if self.unsupported_params.contains("temperature") { + req.temperature = None; + } + if self.unsupported_params.contains("max_tokens") { + req.max_tokens = None; + } + } + fn api_url(&self) -> String { if let Some(ref base) = self.base_url { let base = base.trim_end_matches('/'); @@ -197,8 +231,9 @@ impl AnthropicOAuthProvider { #[async_trait] impl LlmProvider for AnthropicOAuthProvider { - async fn complete(&self, req: CompletionRequest) -> Result { - let model = req.model.unwrap_or_else(|| self.active_model_name()); + async fn complete(&self, mut req: CompletionRequest) -> Result { + let model = req.model.take().unwrap_or_else(|| self.active_model_name()); + self.strip_unsupported_completion_params(&mut req); let (system, messages) = convert_messages(req.messages); let request = AnthropicRequest { @@ -233,9 +268,10 @@ impl LlmProvider for AnthropicOAuthProvider { async fn complete_with_tools( &self, - req: ToolCompletionRequest, + mut req: ToolCompletionRequest, ) -> Result { - let model = req.model.unwrap_or_else(|| self.active_model_name()); + let model = req.model.take().unwrap_or_else(|| self.active_model_name()); + self.strip_unsupported_tool_params(&mut req); let (system, messages) = convert_messages(req.messages); let tools: Vec = req diff --git a/src/llm/config.rs b/src/llm/config.rs index c36280c2..1902f128 100644 --- a/src/llm/config.rs +++ b/src/llm/config.rs @@ -87,6 +87,10 @@ pub struct RegistryProviderConfig { pub oauth_token: Option, /// Prompt cache retention (Anthropic-specific). pub cache_retention: CacheRetention, + /// Parameter names that this provider does not support (e.g., `["temperature"]`). + /// Supported keys: `"temperature"`, `"max_tokens"`, `"stop_sequences"`. + /// Listed parameters are stripped from requests before sending to avoid 400 errors. + pub unsupported_params: Vec, } /// Configuration for AWS Bedrock (native Converse API). diff --git a/src/llm/mod.rs b/src/llm/mod.rs index ffcc70a6..ebbbd31e 100644 --- a/src/llm/mod.rs +++ b/src/llm/mod.rs @@ -228,7 +228,9 @@ fn create_openai_compat_from_registry( "Using OpenAI-compatible provider" ); - Ok(Arc::new(RigAdapter::new(model, &config.model))) + let adapter = RigAdapter::new(model, &config.model) + .with_unsupported_params(config.unsupported_params.clone()); + Ok(Arc::new(adapter)) } fn create_anthropic_from_registry( @@ -296,7 +298,9 @@ fn create_anthropic_from_registry( ); Ok(Arc::new( - RigAdapter::new(model, &config.model).with_cache_retention(cache_retention), + RigAdapter::new(model, &config.model) + .with_cache_retention(cache_retention) + .with_unsupported_params(config.unsupported_params.clone()), )) } @@ -324,7 +328,9 @@ fn create_ollama_from_registry( "Using Ollama provider" ); - Ok(Arc::new(RigAdapter::new(model, &config.model))) + let adapter = RigAdapter::new(model, &config.model) + .with_unsupported_params(config.unsupported_params.clone()); + Ok(Arc::new(adapter)) } /// Create a cheap/fast LLM provider for lightweight tasks (heartbeat, routing, evaluation). diff --git a/src/llm/registry.rs b/src/llm/registry.rs index 273690a1..36cb7001 100644 --- a/src/llm/registry.rs +++ b/src/llm/registry.rs @@ -152,6 +152,11 @@ pub struct ProviderDefinition { /// Setup wizard hints. #[serde(default)] pub setup: Option, + /// Parameter names that this provider does not support (e.g., `["temperature"]`). + /// Supported keys: `"temperature"`, `"max_tokens"`, `"stop_sequences"`. + /// Listed parameters are stripped from requests before sending to avoid 400 errors. + #[serde(default)] + pub unsupported_params: Vec, } /// Registry of known LLM providers. @@ -378,6 +383,7 @@ mod tests { description: "Custom tinfoil".to_string(), extra_headers_env: None, setup: None, + unsupported_params: vec![], }); let registry = ProviderRegistry::new(all); let tf = registry.find("tinfoil").expect("tinfoil should exist"); @@ -517,6 +523,7 @@ mod tests { description: "No setup".to_string(), extra_headers_env: None, setup: None, // no setup hint + unsupported_params: vec![], }]; let registry = ProviderRegistry::new(providers.clone()); @@ -546,6 +553,7 @@ mod tests { can_list_models: false, models_filter: None, }), + unsupported_params: vec![], }); let registry = ProviderRegistry::new(providers); @@ -587,6 +595,7 @@ mod tests { can_list_models: false, models_filter: None, }), + unsupported_params: vec![], }, // User override removes setup ProviderDefinition { @@ -603,6 +612,7 @@ mod tests { description: "No setup now".to_string(), extra_headers_env: None, setup: None, + unsupported_params: vec![], }, ]; @@ -640,6 +650,7 @@ mod tests { display_name: "A".to_string(), can_list_models: false, }), + unsupported_params: vec![], }, ProviderDefinition { id: "bbb".to_string(), @@ -658,6 +669,7 @@ mod tests { display_name: "B".to_string(), can_list_models: false, }), + unsupported_params: vec![], }, ProviderDefinition { id: "ccc".to_string(), @@ -676,6 +688,7 @@ mod tests { display_name: "C".to_string(), can_list_models: false, }), + unsupported_params: vec![], }, // User override for B ProviderDefinition { @@ -695,6 +708,7 @@ mod tests { display_name: "B".to_string(), can_list_models: false, }), + unsupported_params: vec![], }, ]; @@ -708,6 +722,48 @@ mod tests { ); } + #[test] + fn test_unsupported_params_deserialized() { + let providers: Vec = + serde_json::from_str(include_str!("../../providers.json")).unwrap(); + + // Tinfoil should have temperature in unsupported_params + let tinfoil = providers.iter().find(|p| p.id == "tinfoil").unwrap(); + assert!( + tinfoil + .unsupported_params + .contains(&"temperature".to_string()), + "tinfoil should have 'temperature' in unsupported_params" + ); + + // OpenAI should also have temperature in unsupported_params + let openai = providers.iter().find(|p| p.id == "openai").unwrap(); + assert!( + openai + .unsupported_params + .contains(&"temperature".to_string()), + "openai should have 'temperature' in unsupported_params" + ); + + // Providers without the field in JSON should deserialize to empty vec + let groq = providers.iter().find(|p| p.id == "groq").unwrap(); + assert!( + groq.unsupported_params.is_empty(), + "groq should have empty unsupported_params (field absent in JSON)" + ); + + // Every non-empty entry should contain valid param names + for def in &providers { + for param in &def.unsupported_params { + assert!( + !param.is_empty(), + "{}: unsupported_params contains empty string", + def.id + ); + } + } + } + #[test] fn test_all_builtin_api_key_providers_have_api_key_env() { // Every built-in provider with SetupHint::ApiKey must have api_key_env diff --git a/src/llm/rig_adapter.rs b/src/llm/rig_adapter.rs index 87a0b65c..5b835536 100644 --- a/src/llm/rig_adapter.rs +++ b/src/llm/rig_adapter.rs @@ -42,6 +42,9 @@ pub struct RigAdapter { /// via `additional_params` for Anthropic automatic caching. Also controls /// the cost multiplier for cache-creation tokens. cache_retention: CacheRetention, + /// Parameter names that this provider does not support (e.g., `"temperature"`). + /// These are stripped from requests before sending to avoid 400 errors. + unsupported_params: HashSet, } impl RigAdapter { @@ -56,6 +59,7 @@ impl RigAdapter { input_cost, output_cost, cache_retention: CacheRetention::None, + unsupported_params: HashSet::new(), } } @@ -84,6 +88,44 @@ impl RigAdapter { } self } + + /// Set the list of unsupported parameter names for this provider. + /// + /// Parameters in this set are stripped from requests before sending. + /// Supported parameter names: `"temperature"`, `"max_tokens"`, `"stop_sequences"`. + pub fn with_unsupported_params(mut self, params: Vec) -> Self { + self.unsupported_params = params.into_iter().collect(); + self + } + + /// Strip unsupported fields from a `CompletionRequest` in place. + fn strip_unsupported_completion_params(&self, req: &mut CompletionRequest) { + if self.unsupported_params.is_empty() { + return; + } + if self.unsupported_params.contains("temperature") { + req.temperature = None; + } + if self.unsupported_params.contains("max_tokens") { + req.max_tokens = None; + } + if self.unsupported_params.contains("stop_sequences") { + req.stop_sequences = None; + } + } + + /// Strip unsupported fields from a `ToolCompletionRequest` in place. + fn strip_unsupported_tool_params(&self, req: &mut ToolCompletionRequest) { + if self.unsupported_params.is_empty() { + return; + } + if self.unsupported_params.contains("temperature") { + req.temperature = None; + } + if self.unsupported_params.contains("max_tokens") { + req.max_tokens = None; + } + } } // -- Type conversion helpers -- @@ -539,7 +581,10 @@ where } } - async fn complete(&self, request: CompletionRequest) -> Result { + async fn complete( + &self, + mut request: CompletionRequest, + ) -> Result { if let Some(requested_model) = request.model.as_deref() && requested_model != self.model_name.as_str() { @@ -550,6 +595,8 @@ where ); } + self.strip_unsupported_completion_params(&mut request); + let mut messages = request.messages; crate::llm::provider::sanitize_tool_messages(&mut messages); let (preamble, history) = convert_messages(&messages); @@ -599,7 +646,7 @@ where async fn complete_with_tools( &self, - request: ToolCompletionRequest, + mut request: ToolCompletionRequest, ) -> Result { if let Some(requested_model) = request.model.as_deref() && requested_model != self.model_name.as_str() @@ -611,6 +658,8 @@ where ); } + self.strip_unsupported_tool_params(&mut request); + let known_tool_names: HashSet = request.tools.iter().map(|t| t.name.clone()).collect(); @@ -1156,4 +1205,97 @@ mod tests { assert!(!supports_prompt_cache("gpt-4o")); assert!(!supports_prompt_cache("llama3")); } + + #[test] + fn test_with_unsupported_params_populates_set() { + use rig::client::CompletionClient; + use rig::providers::openai; + + let client: openai::Client = openai::Client::builder() + .api_key("test-key") + .base_url("http://localhost:0") + .build() + .unwrap(); + let client = client.completions_api(); + let model = client.completion_model("test-model"); + let adapter = RigAdapter::new(model, "test-model") + .with_unsupported_params(vec!["temperature".to_string()]); + + assert!(adapter.unsupported_params.contains("temperature")); + assert!(!adapter.unsupported_params.contains("max_tokens")); + } + + #[test] + fn test_strip_unsupported_completion_params() { + use rig::client::CompletionClient; + use rig::providers::openai; + + let client: openai::Client = openai::Client::builder() + .api_key("test-key") + .base_url("http://localhost:0") + .build() + .unwrap(); + let client = client.completions_api(); + let model = client.completion_model("test-model"); + let adapter = RigAdapter::new(model, "test-model").with_unsupported_params(vec![ + "temperature".to_string(), + "stop_sequences".to_string(), + ]); + + let mut req = CompletionRequest::new(vec![ChatMessage::user("hi")]); + req.temperature = Some(0.7); + req.max_tokens = Some(100); + req.stop_sequences = Some(vec!["STOP".to_string()]); + + adapter.strip_unsupported_completion_params(&mut req); + + assert!(req.temperature.is_none(), "temperature should be stripped"); + assert_eq!(req.max_tokens, Some(100), "max_tokens should be preserved"); + assert!( + req.stop_sequences.is_none(), + "stop_sequences should be stripped" + ); + } + + #[test] + fn test_strip_unsupported_tool_params() { + use rig::client::CompletionClient; + use rig::providers::openai; + + let client: openai::Client = openai::Client::builder() + .api_key("test-key") + .base_url("http://localhost:0") + .build() + .unwrap(); + let client = client.completions_api(); + let model = client.completion_model("test-model"); + let adapter = RigAdapter::new(model, "test-model") + .with_unsupported_params(vec!["temperature".to_string(), "max_tokens".to_string()]); + + let mut req = ToolCompletionRequest::new(vec![ChatMessage::user("hi")], vec![]); + req.temperature = Some(0.5); + req.max_tokens = Some(200); + + adapter.strip_unsupported_tool_params(&mut req); + + assert!(req.temperature.is_none(), "temperature should be stripped"); + assert!(req.max_tokens.is_none(), "max_tokens should be stripped"); + } + + #[test] + fn test_unsupported_params_empty_by_default() { + use rig::client::CompletionClient; + use rig::providers::openai; + + let client: openai::Client = openai::Client::builder() + .api_key("test-key") + .base_url("http://localhost:0") + .build() + .unwrap(); + let client = client.completions_api(); + let model = client.completion_model("test-model"); + let adapter = RigAdapter::new(model, "test-model"); + + assert!(adapter.unsupported_params.is_empty()); + } } diff --git a/src/setup/wizard.rs b/src/setup/wizard.rs index 38a5d46d..86142bff 100644 --- a/src/setup/wizard.rs +++ b/src/setup/wizard.rs @@ -3787,6 +3787,7 @@ mod tests { description: "Custom provider with no setup wizard".to_string(), extra_headers_env: None, setup: None, + unsupported_params: vec![], }); let registry = crate::llm::ProviderRegistry::new(providers); From be57a7684de4e01ba01e1a58be1768e224e1062d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 16:30:41 +0000 Subject: [PATCH 6/7] chore: release v0.17.0 (#842) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CHANGELOG.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d48749..fcdcd349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,81 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.17.0](https://github.com/nearai/ironclaw/compare/v0.16.1...v0.17.0) - 2026-03-10 + +### Added + +- *(llm)* per-provider unsupported parameter filtering (#749, #728) ([#809](https://github.com/nearai/ironclaw/pull/809)) +- persist user_id in save_job and expose job_id on routine runs ([#709](https://github.com/nearai/ironclaw/pull/709)) +- *(ci)* chained promotion PRs with multi-agent Claude review ([#776](https://github.com/nearai/ironclaw/pull/776)) +- add background sandbox reaper for orphaned Docker containers ([#634](https://github.com/nearai/ironclaw/pull/634)) +- *(wasm)* lazy schema injection on WASM tool errors ([#638](https://github.com/nearai/ironclaw/pull/638)) +- add AWS Bedrock LLM provider via native Converse API ([#713](https://github.com/nearai/ironclaw/pull/713)) +- full image support across all channels ([#725](https://github.com/nearai/ironclaw/pull/725)) +- *(skills)* exclude_keywords veto in skill activation scoring ([#688](https://github.com/nearai/ironclaw/pull/688)) +- *(mcp)* transport abstraction, stdio/UDS transports, and OAuth fixes ([#721](https://github.com/nearai/ironclaw/pull/721)) +- add PID-based gateway lock to prevent multiple instances ([#717](https://github.com/nearai/ironclaw/pull/717)) +- configurable LLM request timeout via LLM_REQUEST_TIMEOUT_SECS ([#615](https://github.com/nearai/ironclaw/pull/615)) ([#630](https://github.com/nearai/ironclaw/pull/630)) +- *(timezone)* add timezone-aware session context ([#671](https://github.com/nearai/ironclaw/pull/671)) +- *(setup)* Anthropic OAuth onboarding with setup-token support ([#384](https://github.com/nearai/ironclaw/pull/384)) +- *(llm)* add Google Gemini, AWS Bedrock, io.net, Mistral, Yandex, and Cloudflare WS AI providers ([#676](https://github.com/nearai/ironclaw/pull/676)) +- unified thread model for web gateway ([#607](https://github.com/nearai/ironclaw/pull/607)) +- WASM channel attachments with LLM pipeline integration ([#596](https://github.com/nearai/ironclaw/pull/596)) +- enable Anthropic prompt caching via automatic cache_control injection ([#660](https://github.com/nearai/ironclaw/pull/660)) +- *(routines)* approval context for autonomous job execution ([#577](https://github.com/nearai/ironclaw/pull/577)) +- *(llm)* declarative provider registry ([#618](https://github.com/nearai/ironclaw/pull/618)) +- *(gateway)* show IronClaw version in status popover [skip-regression-check] ([#636](https://github.com/nearai/ironclaw/pull/636)) +- Wire memory hygiene retention policy into heartbeat loop ([#629](https://github.com/nearai/ironclaw/pull/629)) + +### Fixed + +- *(ci)* run fmt + clippy on staging PRs, skip Windows clippy [skip-regression-check] ([#802](https://github.com/nearai/ironclaw/pull/802)) +- *(ci)* clean up staging pipeline — remove hacks, skip redundant checks [skip-regression-check] ([#794](https://github.com/nearai/ironclaw/pull/794)) +- *(ci)* secrets can't be used in step if conditions [skip-regression-check] ([#787](https://github.com/nearai/ironclaw/pull/787)) +- prevent irreversible context loss when compaction archive write fails ([#754](https://github.com/nearai/ironclaw/pull/754)) +- button styles ([#637](https://github.com/nearai/ironclaw/pull/637)) +- *(mcp)* JSON-RPC spec compliance — flexible id, correct notification format ([#685](https://github.com/nearai/ironclaw/pull/685)) +- preserve tool-call history across thread hydration ([#568](https://github.com/nearai/ironclaw/pull/568)) ([#670](https://github.com/nearai/ironclaw/pull/670)) +- CLI commands ignore runtime DATABASE_BACKEND when both features compiled ([#740](https://github.com/nearai/ironclaw/pull/740)) +- *(web)* prevent fetch error when hostname is an IP address in TEE check ([#672](https://github.com/nearai/ironclaw/pull/672)) +- add timezone conversion support to time tool ([#687](https://github.com/nearai/ironclaw/pull/687)) +- standardize libSQL timestamps as RFC 3339 UTC ([#683](https://github.com/nearai/ironclaw/pull/683)) +- *(docker)* bind postgres to localhost only ([#686](https://github.com/nearai/ironclaw/pull/686)) +- *(repl)* skip /quit on EOF when stdin is not a TTY ([#724](https://github.com/nearai/ironclaw/pull/724)) +- *(web)* prevent Enter key from sending message during IME composition ([#715](https://github.com/nearai/ironclaw/pull/715)) +- *(config)* init_secrets no longer overwrites entire config ([#726](https://github.com/nearai/ironclaw/pull/726)) +- *(cli)* status command ignores config.toml and settings.json ([#354](https://github.com/nearai/ironclaw/pull/354)) ([#734](https://github.com/nearai/ironclaw/pull/734)) +- *(setup)* preserve model name when re-running onboarding with same provider ([#600](https://github.com/nearai/ironclaw/pull/600)) ([#694](https://github.com/nearai/ironclaw/pull/694)) +- *(setup)* initialize secrets crypto for env-var security option ([#666](https://github.com/nearai/ironclaw/pull/666)) ([#706](https://github.com/nearai/ironclaw/pull/706)) +- persist /model selection across restarts ([#707](https://github.com/nearai/ironclaw/pull/707)) +- *(routines)* resolve message tool channel/target from per-job metadata ([#708](https://github.com/nearai/ironclaw/pull/708)) +- sanitize HTML error bodies from MCP servers to prevent web UI white screen ([#263](https://github.com/nearai/ironclaw/pull/263)) ([#656](https://github.com/nearai/ironclaw/pull/656)) +- prevent Instant duration overflow on Windows ([#657](https://github.com/nearai/ironclaw/pull/657)) ([#664](https://github.com/nearai/ironclaw/pull/664)) +- enable libsql remote + tls features for Turso cloud sync ([#587](https://github.com/nearai/ironclaw/pull/587)) +- *(tests)* replace hardcoded /tmp paths with tempdir + add 300 unit tests ([#659](https://github.com/nearai/ironclaw/pull/659)) +- *(llm)* nudge LLM when it expresses tool intent without calling tools ([#653](https://github.com/nearai/ironclaw/pull/653)) +- *(llm)* report zero cost for OpenRouter free-tier models ([#463](https://github.com/nearai/ironclaw/pull/463)) ([#613](https://github.com/nearai/ironclaw/pull/613)) +- reliable network tests and improved tool error messages ([#626](https://github.com/nearai/ironclaw/pull/626)) +- *(wasm)* use per-engine cache dirs on Windows to avoid file lock error ([#624](https://github.com/nearai/ironclaw/pull/624)) +- *(libsql)* support flexible embedding dimensions ([#534](https://github.com/nearai/ironclaw/pull/534)) + +### Other + +- Restructure CLAUDE.md into modular rules + add pr-shepherd command ([#750](https://github.com/nearai/ironclaw/pull/750)) +- make src/llm/ self-contained for crate extraction ([#767](https://github.com/nearai/ironclaw/pull/767)) +- add simplified Chinese (zh-CN) README translation ([#488](https://github.com/nearai/ironclaw/pull/488)) +- *(job)* cover job tool validation and state transitions ([#681](https://github.com/nearai/ironclaw/pull/681)) +- *(agent)* wire TestRig job tools through the scheduler ([#716](https://github.com/nearai/ironclaw/pull/716)) +- Fix single-message mode to exit after one turn when background channels are enabled ([#719](https://github.com/nearai/ironclaw/pull/719)) +- remove dead code ([#648](https://github.com/nearai/ironclaw/pull/648)) ([#703](https://github.com/nearai/ironclaw/pull/703)) +- add reviewer-feedback guardrails (CLAUDE.md, pre-commit hook, skill) ([#665](https://github.com/nearai/ironclaw/pull/665)) +- update WASM artifact SHA256 checksums [skip ci] ([#631](https://github.com/nearai/ironclaw/pull/631)) +- add explanatory comments to coverage workflow ([#610](https://github.com/nearai/ironclaw/pull/610)) +- build system prompt once per turn, skip tools on force-text ([#583](https://github.com/nearai/ironclaw/pull/583)) +- add comprehensive subdirectory CLAUDE.md files and update root ([#589](https://github.com/nearai/ironclaw/pull/589)) +- Improve test infrastructure: StubChannel, gateway helpers, security tests, search edge cases ([#623](https://github.com/nearai/ironclaw/pull/623)) +- *(workspace)* regression test for document_path in search results ([#509](https://github.com/nearai/ironclaw/pull/509)) + ### Added - AWS Bedrock LLM provider via native Converse API with IAM and SSO auth support (feature-gated: `--features bedrock`) diff --git a/Cargo.lock b/Cargo.lock index 064f3493..be0bdb23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3350,7 +3350,7 @@ dependencies = [ [[package]] name = "ironclaw" -version = "0.16.1" +version = "0.17.0" dependencies = [ "aes-gcm", "aho-corasick", diff --git a/Cargo.toml b/Cargo.toml index 1e1d909a..b3551b44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ exclude = [ [package] name = "ironclaw" -version = "0.16.1" +version = "0.17.0" edition = "2024" rust-version = "1.92" description = "Secure personal AI assistant that protects your data and expands its capabilities on the fly" From 9d4cf308eff0e414a4758b2c2f79fef3f39fe30b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:55:38 +0000 Subject: [PATCH 7/7] chore: update WASM artifact SHA256 checksums [skip ci] (#876) Co-authored-by: github-actions[bot] --- registry/channels/discord.json | 2 +- registry/channels/slack.json | 2 +- registry/channels/telegram.json | 2 +- registry/channels/whatsapp.json | 2 +- registry/tools/github.json | 2 +- registry/tools/gmail.json | 2 +- registry/tools/google-calendar.json | 2 +- registry/tools/google-docs.json | 2 +- registry/tools/google-drive.json | 2 +- registry/tools/google-sheets.json | 2 +- registry/tools/google-slides.json | 2 +- registry/tools/slack.json | 2 +- registry/tools/telegram.json | 2 +- registry/tools/web-search.json | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/registry/channels/discord.json b/registry/channels/discord.json index abd29d82..1351c96d 100644 --- a/registry/channels/discord.json +++ b/registry/channels/discord.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/discord-wasm32-wasip2.tar.gz", - "sha256": "030707431717bca3411a48f311c6ab5f92a45c747de26cafe4f6e3e23a8b3b2d" + "sha256": "85b424604482da3fb9badb56a0360ff4c93670bc7be0ad7f57ef9d85ff972b6f" } }, "auth_summary": { diff --git a/registry/channels/slack.json b/registry/channels/slack.json index f123798f..218fc12a 100644 --- a/registry/channels/slack.json +++ b/registry/channels/slack.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/slack-wasm32-wasip2.tar.gz", - "sha256": "6ed36077b67ac70a041f06f760f93ba79b33269885413c3c3f2c8c87ee60807e" + "sha256": "9190b8250bd20c22a8c97b1ea19a6590624a69d6c63a5f5c240a7840a4966286" } }, "auth_summary": { diff --git a/registry/channels/telegram.json b/registry/channels/telegram.json index 42fd7fb3..965c469d 100644 --- a/registry/channels/telegram.json +++ b/registry/channels/telegram.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/telegram-wasm32-wasip2.tar.gz", - "sha256": "98c86895a9c4b0a1e19fe8a47f1ccbfe7e972e112b05e584bc897130dc32283a" + "sha256": "55f2a56e7afd129a48fd49b019f12f9638705defa53fa323ad3b8978d7c59664" } }, "auth_summary": { diff --git a/registry/channels/whatsapp.json b/registry/channels/whatsapp.json index 84a69dc0..098f51d7 100644 --- a/registry/channels/whatsapp.json +++ b/registry/channels/whatsapp.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/whatsapp-wasm32-wasip2.tar.gz", - "sha256": "bd35cad18d87292ea8d2f52db9b514ed9f814a414de910f59073d475c26c4c14" + "sha256": "06bcf315df93af9f683134f4055eb810c602863d8c4a632e3733a10217cc5a89" } }, "auth_summary": { diff --git a/registry/tools/github.json b/registry/tools/github.json index 67d41882..2ba222ba 100644 --- a/registry/tools/github.json +++ b/registry/tools/github.json @@ -20,7 +20,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/github-wasm32-wasip2.tar.gz", - "sha256": "6fcd32719a4ff15641a4b50fff8984686550f0c491dce60518f4126857d0c544" + "sha256": "c443328a3f10b6a4cf4d3d62c9217aca204f6467ef753d986b58ca966ca53514" } }, "auth_summary": { diff --git a/registry/tools/gmail.json b/registry/tools/gmail.json index f1e7ab6e..9ef1a0f9 100644 --- a/registry/tools/gmail.json +++ b/registry/tools/gmail.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/gmail-wasm32-wasip2.tar.gz", - "sha256": "023da7000b17568bf0e64b2e5013c8a042b2f323c85f1632339231c73d500e39" + "sha256": "e4f0095890d22e3de8e9d516f2e1e91964f8ff4acdaaa19f0a7094a1f2d7786b" } }, "auth_summary": { diff --git a/registry/tools/google-calendar.json b/registry/tools/google-calendar.json index cfc6ec92..40342b48 100644 --- a/registry/tools/google-calendar.json +++ b/registry/tools/google-calendar.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/google-calendar-wasm32-wasip2.tar.gz", - "sha256": "fc42277b65881d6e9bcc5403dc54c7f5b3ddeaaaf04617fce2c5da05d76325f0" + "sha256": "2d202bd838de94677c91ea6473c7155f021c0500cf91794d17639b1b27446b3d" } }, "auth_summary": { diff --git a/registry/tools/google-docs.json b/registry/tools/google-docs.json index 3f7107b2..9aaf9d17 100644 --- a/registry/tools/google-docs.json +++ b/registry/tools/google-docs.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/google-docs-wasm32-wasip2.tar.gz", - "sha256": "385c04abd1e6b8011ccc330e1f4bd7ce58577e488959b51594aa04eb26cbe7cc" + "sha256": "7a5e40fe58199e34f7625e11d22e5601cdfd2a94a10193a83f1925180bbb66df" } }, "auth_summary": { diff --git a/registry/tools/google-drive.json b/registry/tools/google-drive.json index d0e02f56..74bc825c 100644 --- a/registry/tools/google-drive.json +++ b/registry/tools/google-drive.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/google-drive-wasm32-wasip2.tar.gz", - "sha256": "1b107d575a5d52cc8c76d9a681802190f4373fb485f7f54f445533f097fa37c0" + "sha256": "d19f856fde0ae0320fd3f636a34116af1df0b59698c3684b686e8412a60e887f" } }, "auth_summary": { diff --git a/registry/tools/google-sheets.json b/registry/tools/google-sheets.json index 8eb88ced..716880db 100644 --- a/registry/tools/google-sheets.json +++ b/registry/tools/google-sheets.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/google-sheets-wasm32-wasip2.tar.gz", - "sha256": "c4f6b1e8c5126ac2c8a4b98e4283a3afa32223d2488fc3c3a609758c0c9beb90" + "sha256": "e113c317f9fa21ea68d0ec8accbba4a62a8222ff3c4655ae85e1e58e01de3250" } }, "auth_summary": { diff --git a/registry/tools/google-slides.json b/registry/tools/google-slides.json index 6c3a187c..25e9a64a 100644 --- a/registry/tools/google-slides.json +++ b/registry/tools/google-slides.json @@ -18,7 +18,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/google-slides-wasm32-wasip2.tar.gz", - "sha256": "7110b8565340c888e51f99e9c013bf4de8f8a7f7b33bace00eb8fc47831ff20b" + "sha256": "7875a5ae1283e57937e0618bf14465f4bb4ee7f49110312382670202f4c567a5" } }, "auth_summary": { diff --git a/registry/tools/slack.json b/registry/tools/slack.json index c1102021..e9f7e6d2 100644 --- a/registry/tools/slack.json +++ b/registry/tools/slack.json @@ -18,7 +18,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/slack-tool-wasm32-wasip2.tar.gz", - "sha256": "6ed36077b67ac70a041f06f760f93ba79b33269885413c3c3f2c8c87ee60807e" + "sha256": "9190b8250bd20c22a8c97b1ea19a6590624a69d6c63a5f5c240a7840a4966286" } }, "auth_summary": { diff --git a/registry/tools/telegram.json b/registry/tools/telegram.json index d96d8985..a01b1961 100644 --- a/registry/tools/telegram.json +++ b/registry/tools/telegram.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/telegram-mtproto-wasm32-wasip2.tar.gz", - "sha256": "98c86895a9c4b0a1e19fe8a47f1ccbfe7e972e112b05e584bc897130dc32283a" + "sha256": "55f2a56e7afd129a48fd49b019f12f9638705defa53fa323ad3b8978d7c59664" } }, "auth_summary": { diff --git a/registry/tools/web-search.json b/registry/tools/web-search.json index 7112d9b2..e61ab0dd 100644 --- a/registry/tools/web-search.json +++ b/registry/tools/web-search.json @@ -19,7 +19,7 @@ "artifacts": { "wasm32-wasip2": { "url": "https://github.com/nearai/ironclaw/releases/latest/download/web-search-wasm32-wasip2.tar.gz", - "sha256": "66cb2b9b00652385e9f30f17c74902b9222c17c53e9d3bd1ef42f5cab705bcf6" + "sha256": "dd7e54956ee0b3037ca3506dbcbd20efcc4cd2749175ed511b3640b09f77506a" } }, "auth_summary": {