Commit Graph
596 Commits
Author SHA1 Message Date
Henry ParkandGitHub ea0fa7c2c5 Merge pull request #1196 from nearai/staging-promote/e74214dc-23104855330
chore: promote staging to staging-promote/97b11ffd-23104193988 (2026-03-15 06:18 UTC)
2026-03-16 13:28:17 -07:00
Henry ParkandGitHub f2587e1f44 Merge pull request #1193 from nearai/staging-promote/97b11ffd-23104193988
chore: promote staging to staging-promote/15ab156d-23103553911 (2026-03-15 05:30 UTC)
2026-03-16 13:27:34 -07:00
Henry ParkandGitHub 218e8778b9 Merge pull request #1192 from nearai/staging-promote/15ab156d-23103553911
chore: promote staging to staging-promote/c79754df-23099429381 (2026-03-15 04:45 UTC)
2026-03-16 13:26:42 -07:00
Henry ParkandGitHub 4890e73a34 Merge pull request #1132 from nearai/staging-promote/e805ec61-23059634819
chore: promote staging to main (2026-03-13 16:09 UTC)
2026-03-16 09:22:58 -07:00
Henry ParkandGitHub b8ddbeadb4 Merge pull request #1188 from nearai/staging-promote/c79754df-23099429381
chore: promote staging to staging-promote/8753c482-23098316440 (2026-03-15 00:13 UTC)
2026-03-16 09:01:36 -07:00
Henry ParkandGitHub 9aca6a1053 Merge pull request #1186 from nearai/staging-promote/8753c482-23098316440
chore: promote staging to staging-promote/71b1a677-23096345848 (2026-03-14 23:05 UTC)
2026-03-16 08:57:16 -07:00
Henry ParkandGitHub 4c7afdb0ca Merge pull request #1134 from nearai/staging-promote/bc672520-23062088162
chore: promote staging to staging-promote/e805ec61-23059634819 (2026-03-13 17:11 UTC)
2026-03-16 07:51:56 -07:00
Henry ParkandGitHub a580c1d75f Merge pull request #1137 from nearai/staging-promote/f53c1bb1-23064256940
chore: promote staging to staging-promote/bc672520-23062088162 (2026-03-13 18:08 UTC)
2026-03-16 07:51:41 -07:00
Henry ParkandGitHub d1c1bc79c5 Merge pull request #1145 from nearai/staging-promote/7d745d54-23066609095
chore: promote staging to staging-promote/f53c1bb1-23064256940 (2026-03-13 19:12 UTC)
2026-03-16 07:51:24 -07:00
Henry ParkandGitHub 4277a5a33a Merge pull request #1159 from nearai/staging-promote/f9b880c2-23080458788
chore: promote staging to staging-promote/7d745d54-23066609095 (2026-03-14 04:31 UTC)
2026-03-16 07:51:12 -07:00
Henry ParkandGitHub 190c70cdbe Merge pull request #1176 from nearai/staging-promote/17706632-23094430993
chore: promote staging to staging-promote/f9b880c2-23080458788 (2026-03-14 19:08 UTC)
2026-03-16 07:50:48 -07:00
Henry ParkandGitHub aa3fac3edc Merge pull request #1182 from nearai/staging-promote/579c4fdb-23095333790
chore: promote staging to staging-promote/17706632-23094430993 (2026-03-14 20:03 UTC)
2026-03-16 07:50:37 -07:00
Henry ParkandGitHub ccdce69309 Merge pull request #1185 from nearai/staging-promote/71b1a677-23096345848
chore: promote staging to staging-promote/579c4fdb-23095333790 (2026-03-14 21:05 UTC)
2026-03-16 07:49:51 -07:00
de214c23e0 feat: add LLM_CHEAP_MODEL for generic smart routing across all backends (#1081)
* feat: add LLM_CHEAP_MODEL for generic smart routing across all backends

Add generic cheap model support that works with any LLM backend, not just
NearAI. New env vars: LLM_CHEAP_MODEL (cheap model for any backend) and
SMART_ROUTING_CASCADE (top-level cascade flag).

Resolution order: LLM_CHEAP_MODEL > NEARAI_CHEAP_MODEL (backward compat).
Registry-based providers (OpenAI, Anthropic, Groq, etc.) clone their
RegistryProviderConfig with the cheap model swapped in. Bedrock returns
an explicit error (not yet supported). All error paths use ok_or_else
with proper LlmError variants -- no unwrap/expect in production code.

* refactor: address Gemini review — remove unnecessary async, extract cheap_model_name()

- Remove async from create_cheap_provider_for_backend() and
  create_cheap_llm_provider() — neither contains .await calls
- Extract duplicated cheap model resolution logic into
  LlmConfig::cheap_model_name() helper method (DRY)
- Revert tests from tokio::test async back to sync #[test]
- Add test_cheap_model_name_resolution() unit test for the helper

---------

Co-authored-by: SMKRV <[email protected]>
2026-03-16 08:06:51 +00:00
0245c0f9e9 feat(orchestrator): read ORCHESTRATOR_PORT env var for configurable API port (#1113)
* feat(orchestrator): read ORCHESTRATOR_PORT env var for configurable API port

The orchestrator internal API port was hardcoded to 50051 in two places
(ContainerJobConfig and OrchestratorApi::start call), making it impossible
to run multiple IronClaw instances on the same host — the second instance
fails with "Address already in use".

NETWORK_SECURITY.md already documents ORCHESTRATOR_PORT as configurable,
and ContainerJobConfig.orchestrator_port is propagated to worker containers
via IRONCLAW_ORCHESTRATOR_URL, but the env var was never actually read.

Extract resolve_orchestrator_port() that reads ORCHESTRATOR_PORT and falls
back to 50051. Includes tests for valid, invalid, and out-of-range values.

* test: add ENV_LOCK mutex for env-var test serialization

Address Gemini review: add std::sync::Mutex to serialize env var access
across test threads. Keep unsafe blocks — required in Rust edition 2024
where std::env::set_var/remove_var are unsafe functions.

---------

Co-authored-by: SMKRV <[email protected]>
2026-03-16 07:58:48 +00:00
877f117096 feat(transcription): add Chat Completions API provider for audio transcription (#1130)
* feat(transcription): add Chat Completions API provider for audio transcription

The existing transcription pipeline only supports the OpenAI Whisper API
(/v1/audio/transcriptions with multipart upload). Providers like OpenRouter
expose audio transcription through the Chat Completions API instead, using
base64-encoded audio in the `input_audio` content type.

Add `ChatCompletionsTranscriptionProvider` that sends audio as base64 in
a chat completion request and extracts the transcript from the response.
Compatible with OpenRouter, OpenAI GPT-4o-audio, and any provider that
supports audio input via Chat Completions.

Config changes:
- TRANSCRIPTION_PROVIDER=chat_completions selects the new provider
- TRANSCRIPTION_API_KEY overrides provider-specific keys
- LLM_API_KEY used as fallback for chat_completions provider
- Default model per provider (whisper-1 for openai, gemini-2.0-flash for
  chat_completions)

* style: address review feedback — formatting, idiomatic patterns

- Fix rustfmt formatting for provider constructor chain
- Use or_else for resolve_api_key priority chain (Gemini review)
- Use trim_end_matches('/') instead of while loop (Gemini review)

---------

Co-authored-by: SMKRV <[email protected]>
2026-03-16 07:57:58 +00:00
pikaxingeandGitHub c4e098d4e3 Fix subagent monitor events being treated as user input (#1173)
* Fix subagent monitor routing to avoid LLM re-entry

* Update yanked uds_windows dependency in lockfile
2026-03-15 06:00:19 +00:00
ReidandGitHub e74214dce8 fix(config): unify ChannelsConfig resolution to env > settings > default (#1124)
ChannelsConfig::resolve() ignored most ChannelSettings fields, reading
  exclusively from env vars. This made `config set` ineffective for gateway,
  HTTP, CLI, and WASM channel settings — a prerequisite blocker for #86
  (hot-reload) and CLI management commands.

  - Add gateway and CLI fields to ChannelSettings with correct defaults
  - Rewrite resolve() to fall back to settings when env var is unset
  - Keep strict boolean validation via parse_bool_env for all bool fields
  - Fix GATEWAY_PORT default divergence (3001 -> 3000) in extension manager
  - Export DEFAULT_GATEWAY_PORT constant as single source of truth
  - Add 8 tests: settings fallback, env override, DB roundtrip, invalid bool rejection

  Part of #1119 (Phase 1: Channels pilot)
[skip-regression-check]
2026-03-15 05:59:08 +00:00
NigeandGitHub dac420840d fix(web-chat): normalize chat copy to plain text (#1114)
* fix(web-chat): force plain-text clipboard copy from chat messages

* test(e2e): make chat copy test target deterministic message
2026-03-15 05:52:47 +00:00
Xing JiandGitHub 3f6d2ab6c2 fix(skill): treat empty url param as absent when installing skills (#1128)
LLMs sometimes pass "" for optional parameters instead of omitting them.
Previously, passing url: "" to skill_install would match the explicit-URL
branch and attempt to fetch from an empty string, producing an invalid URL
error instead of falling back to the catalog lookup.

Fix by adding .filter(|s| !s.is_empty()) so an empty url is treated the
same as a missing field.

A unit test verifies the parameter filtering behaviour directly; the full
execute path (catalog lookup + install) requires a real catalog and database
and cannot be covered at the unit level.
2026-03-15 05:50:39 +00:00
NigeGitHubgemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
f059d50331 fix: preserve AuthError type in oauth_http_client cache (#1152)
* fix(mcp): cache oauth client init error as AuthError

* Update src/tools/mcp/auth.rs

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* fix(mcp): use AuthError::Http in oauth client cache and add regression test

* test(mcp): annotate test assert for no-panics CI matcher

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-15 05:49:42 +00:00
a70e58f44e fix(web): prevent Safari IME composition Enter from sending message (#1140)
* fix(web): handle Safari IME composition Enter key

Safari sets e.isComposing=false on the keydown event that ends IME
composition, unlike Chrome/Firefox. This caused pressing Enter to confirm
CJK input to immediately send the message.

Track composition state manually via compositionstart/compositionend and
guard the send condition with both e.isComposing and _isComposing.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* fix(web): improve Safari IME comment with WebKit bug reference

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-03-15 05:47:21 +00:00
62d16e69ac fix(mcp): handle 400 auth errors, clear auth mode after OAuth, trim tokens (#1158)
* fix(mcp): handle 400 auth errors, clear auth mode after OAuth, trim tokens

Three bugs prevented MCP server authentication (e.g. GitHub MCP) from
working correctly:

1. **400 treated as auth-required**: GitHub's MCP endpoint returns 400
   "Authorization header is badly formatted" instead of 401 when auth
   is missing. Broadened auth detection in activate_mcp, send_request,
   and discover_via_401 to also match 400+authorization errors.

2. **Auth mode not cleared after OAuth callback**: The OAuth callback
   handler and setup submit handler did not call clear_auth_mode(),
   leaving pending_auth on the thread. The next user message was
   intercepted as a token instead of triggering an LLM turn.

3. **Token trimming**: Tokens with leading/trailing whitespace or
   newlines produced malformed Authorization headers. Now trimmed
   before storage (configure) and before use (build_request_headers).

Adds E2E tests with a mock MCP server (JSON-RPC + OAuth discovery +
DCR + token exchange) covering install -> activate -> OAuth callback ->
LLM turn lifecycle, plus a GitHub-style 400 error variant.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(mcp): add TTL to PendingAuth and clear auth mode on all failure paths

Auth mode (pending_auth on a Thread) had no timeout and several code
paths that failed to clear it, causing user messages to be swallowed
indefinitely. This adds defense-in-depth:

- Add created_at + 5-minute TTL to PendingAuth; auto-clear on next
  message if expired (safety net for edge cases like user closing
  browser mid-OAuth)
- Clear auth mode on OAuth callback failure paths (unknown/consumed
  state, expired flow)
- Move clear_auth_mode before configure() match in setup_submit so
  it runs on failure too (addresses Copilot review feedback)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(ci): exclude test hunks from unwrap/assert pre-commit check

The pre-commit safety script only excluded files in tests/ but not
#[cfg(test)] mod tests blocks inside src/ files. Use the git diff @@
hunk header context (which includes the enclosing function name) to
detect and skip test hunks.

Also removes unnecessary // safety: comments from test assertions.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix: restore formatting in test assertions

The replace_all edit that removed // safety: comments collapsed
newlines. Restore proper line breaks.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix: address Copilot review - tighten pre-commit filter, document TTL sync

- pre-commit-safety.sh: only exclude `mod tests` hunks (not `fn test_*`)
  to avoid hiding unwrap/assert in production functions like test_server()
- session.rs: extract AUTH_MODE_TTL_SECS constant and add doc comment
  linking to OAUTH_FLOW_EXPIRY to prevent silent drift

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(mcp): return error on expired auth input, clear auth on all OAuth paths

- When auth mode TTL expires and the user sends a message (possibly a
  pasted token), return an explicit "expired, please retry" response
  instead of forwarding the content to the LLM/history
- Add clear_auth_mode() to all early-return paths in oauth_callback_handler
  (provider error, missing state/code, no extension manager)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-15 05:42:49 +00:00
27e21fdabe feat: add pre-push git hook with delta lint mode (#833)
* feat: add pre-push git hook with delta lint mode

Add pre-push hook and CI quality gate scripts:
- .githooks/pre-push: runs quality gate before push
- scripts/ci/quality_gate.sh: baseline fmt + clippy correctness + tests
- scripts/ci/delta_lint.sh: clippy warnings filtered to changed lines only
- Updated dev-setup.sh to install pre-push hook

Supports environment-gated modes:
- IRONCLAW_STRICT_LINT=1: deny all clippy warnings
- IRONCLAW_STRICT_DELTA_LINT=1: deny warnings only on changed lines

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: use git rev-parse for SCRIPT_DIR, add python3 check

- Fix SCRIPT_DIR resolution in pre-push hook to work correctly
  with symlinks by using git rev-parse --show-toplevel
- Add python3 availability check in delta_lint.sh

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: delta lint stderr handling, --locked flag, path normalization

- Stop suppressing clippy stderr; capture it and show compilation
  errors if clippy produces no JSON output
- Add --locked flag to clippy for lockfile consistency
- Use repo root (via git rev-parse) for path normalization instead
  of os.getcwd() which may differ from repo root

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: dynamically detect upstream base branch in delta_lint.sh

Instead of hard-coding `origin/main`, derive the base ref by checking
`refs/remotes/origin/HEAD`, then falling back to `origin/main` and
`origin/master`. If none can be resolved, skip delta lint gracefully
with a warning and exit 0.

Addresses PR #833 review feedback.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* chore: re-trigger CI after adding skip-regression-check label

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: address PR #833 review feedback for delta lint

- Pass remote name ($1) from pre-push hook to delta_lint.sh
- Accept optional remote name arg, fall back to dynamic detection
- Treat error-level diagnostics as always blocking
- Check span overlap [line_start, line_end] vs changed ranges
- Handle +++ /dev/null (file deletions) in parse_diff
- Catch git merge-base failure with graceful skip
- Add CLIPPY_STDERR to EXIT trap cleanup

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: drop -D warnings from delta lint, scope pre-push tests to --lib

1. Remove `-D warnings` from the clippy invocation in delta_lint.sh.
   With -D warnings, all warnings are promoted to error level in JSON
   output, which bypasses the delta filter entirely (errors are always
   blocking). The Python filter already handles the blocking decision
   for warnings based on changed-line overlap.

2. Scope pre-push tests to `cargo test --lib` (unit tests only) instead
   of the full test suite. Full integration tests can take minutes and
   will train developers to use --no-verify. The full suite runs in CI.
   Skip tests entirely with IRONCLAW_PREPUSH_TEST=0.

Addresses zmanian's review feedback on PR #833.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-15 05:41:29 +00:00
ReidandGitHub 67b2c08a7c feat(cli): add logs command for gateway log access (#1105)
- Add `ironclaw logs` to tail gateway.log with reverse-seek (O(output) memory, no full-file load)
  - Add `--follow` for live SSE streaming from /api/logs/events
  - Add `--level` to get/set runtime log level via /api/logs/level
  - Support --json, --plain, --local-time, --url, --token, --timeout flags
  - Respect --config for gateway address/token resolution (consistent with other CLI commands)
  - Fail explicitly when --config points to invalid file instead of silent fallback
  - Wire Logs variant into Command enum and main.rs dispatch
  - Add 9 unit tests (tail_file chunked read, colorize, timestamp conversion, JSON output)
  - Update FEATURE_PARITY.md: logs 🚧
2026-03-15 05:32:10 +00:00
ReidandGitHub 97b11ffd10 feat: add Feishu/Lark WASM channel plugin (#1110)
part of #1046

  - Implement Feishu Event Subscription v2.0 webhook (URL verification + im.message.receive_v1)
  - Token exchange via workspace-cached app credentials with 5-min pre-expiry refresh
  - Host-side secret injection into config JSON (setup.rs) so WASM can access app_id/app_secret without env vars
  - Reply and broadcast via /open-apis/im/v1/messages
  - Enforce allow_from user filtering in message handler
  - DM pairing flow with owner_id restriction
  - Dual API base support: open.feishu.cn (Feishu) / open.larksuite.com (Lark)
  - Registry manifest, bundled channel entry, messaging bundle integration
  - Strip raw config_json debug log to prevent secret leakage
2026-03-15 05:25:05 +00:00
15ab156d62 feat: add Criterion benchmarks for safety layer hot paths (#836)
* feat: add Criterion benchmarks for safety layer hot paths

Add benchmark suite using Criterion.rs for performance-critical paths:

- benches/safety_check.rs: Sanitizer (clean/adversarial), Validator
  (normal/long/tool params), LeakDetector (clean/secrets/HTTP scan)
- benches/tool_dispatch.rs: JSON parsing, schema validation patterns,
  tool output serialization

CI compiles benchmarks on every PR to prevent regressions.
Run locally with: cargo bench

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: add bench-compile to CI roll-up job

Include bench-compile in the run-tests roll-up job's needs array
so benchmark compilation failures block PRs.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: add black_box to benchmarks, use real SafetyLayer pipeline

- Wrap all benchmark inputs in criterion::black_box to prevent
  compiler optimization from skewing results
- Replace generic JSON benchmarks in tool_dispatch.rs with actual
  SafetyLayer pipeline benchmarks (sanitize_tool_output, wrap_for_llm,
  scan_inbound_for_secrets)
- Keep JSON parsing benchmarks for tool parameter overhead measurement

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: apply cargo fmt to benchmark files

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: copy benches/ in Dockerfile to fix manifest parse error

Cargo.toml references [[bench]] targets that must exist for manifest
parsing to succeed. Add COPY benches/ to the Docker build stage.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* chore: re-trigger CI after adding skip-regression-check label

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: address PR review comments on criterion benchmarks

- Move header string allocations outside b.iter() closure in
  http_request_scan to avoid measuring allocation overhead
- Add .unwrap() to serde_json::from_str results in JSON parsing
  benchmarks to catch invalid JSON instead of silently benchmarking
  error construction
- Add comment explaining why benches/ COPY is needed in Dockerfile
  ([[bench]] entries require source files for cargo manifest parsing)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* chore: update Cargo.lock with criterion dependencies

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(bench): build secret-like strings at runtime to avoid CI secret scanners

Construct AWS key and GitHub token patterns via format!() concatenation
so the literal strings don't appear in source and trigger push protection
or secret scanning in CI pipelines. The resulting strings still match
LeakDetector patterns for valid benchmarking.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: rename tool_dispatch bench, drop async_tokio, replace JSON benchmarks

1. Rename `tool_dispatch.rs` → `safety_pipeline.rs` to match actual
   content (SafetyLayer pipeline benchmarks).
2. Drop unused `async_tokio` feature from criterion dependency.
3. Replace serde_json::from_str benchmarks (third-party only) with
   Validator::validate_tool_params exercising IronClaw's recursive
   validation on simple, complex, and deeply nested JSON inputs.
4. Add `--all-features` to CI bench-compile to match clippy/test
   convention and verify both DB backends.

Addresses zmanian's review feedback on PR #836.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-15 03:26:50 +00:00
716629809c fix: eliminate panic paths in production code (#1184)
* fix: eliminate panic paths in production code and document infallible operations

PolicyRule::new() now returns Result instead of panicking on invalid
caller-supplied regex. CreateJobTool returns ToolError when job_manager
is unconfigured instead of panicking. Remaining infallible unwrap/expect
calls (hardcoded regexes, compile-time constants, guarded accesses)
are annotated with SAFETY comments. Where possible, unwraps are replaced
with safer patterns: split_last(), if-let, match-destructure, and
reusing peek() values.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix: use inline lowercase safety comments to match CI pattern

The no-panics CI check greps for '// safety:' (lowercase, inline)
to suppress false positives. Switch from block SAFETY comments to
inline safety comments on the .unwrap() lines.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* test: add regression tests for panic-path fixes

- PolicyRule::new returns Err on invalid regex (not panic)
- CreateJobTool::execute_sandbox returns ToolError when job_manager is None

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix: add inline // safety: comments on all infallible unwrap/expect lines

The CI no-panics check requires '// safety:' on the same line as
unwrap()/expect() to suppress false positives. Move safety annotations
from block comments to inline comments on every infallible production
unwrap/expect across all touched files.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* chore: trigger CI with skip-regression-check label

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* refactor: remove redundant block-level SAFETY comments

Each unwrap/expect now carries its own inline // safety: annotation,
making the standalone block comments above them redundant.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-15 03:17:03 +00:00
Henry ParkandGitHub c79754df28 Fix schema-guided tool parameter coercion (#1143)
* Fix schema-guided tool parameter coercion

* Fix CI checks for coercion regression tests

* Finish panic-scan annotations

* Avoid redundant worker param preparation

* Keep panic-scan annotations rustfmt-stable

* Handle nullable WASM schema review feedback

* Address param coercion review notes
2026-03-14 16:27:18 -07:00
Henry ParkandGitHub fda5160940 Make no-panics CI check test-aware (#1160)
* Make no-panics check test-aware

* Handle proc-macro test attrs in no-panics check

* Pin Python for no-panics CI job
2026-03-14 16:26:39 -07:00
NigeandGitHub 8753c48233 perf(mcp): avoid reallocating SSE buffer on each chunk (#1153) 2026-03-14 15:47:48 -07:00
71b1a6778b fix(deps): update yanked uds_windows 1.2.0 -> 1.2.1 (#1183)
Fixes cargo-deny CI failure due to yanked crate.
[skip-regression-check]

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-14 20:44:37 +00:00
NigeandGitHub e291d3b6f1 feat(routines): human-readable cron schedule summaries in web UI (#1154)
* feat(routines): render cron triggers as human-readable summaries

* test(routines): annotate multiline cron assertions for no-panics CI

* test(routines): avoid multiline assert lint false positives
2026-03-14 13:07:05 -07:00
Nick PismenkovandGitHub 994a0b194f fix: N+1 query pattern in event trigger loop (routine_engine) (#1163)
* fix: N+1 query pattern in event trigger loop (routine_engine)

* fix: linter
2026-03-14 13:06:59 -07:00
NigeandGitHub ffe384b66e fix(llm): add stop_sequences parity for tool completions (#1170)
* fix(llm): add stop_sequences parity for tool completions

* refactor(web-openai): dedupe request builders and satisfy no-panics gate

* test(llm): mark multiline assert with safety comment for CI gate

* test(llm): make safety-marked assert formatting-stable
2026-03-14 13:06:48 -07:00
NigeandGitHub cc52a046c1 fix(channels): use live owner binding during wasm hot activation (#1171)
* fix(channels): use live owner binding during wasm hot activation

* test(channels): cover owner-id store fallback without panic macros
2026-03-14 13:06:42 -07:00
NigeGitHubgemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
5f0ed66a6b perf(routines): avoid full message history clone each tool iteration (#1172)
* perf(routines): bound tool-loop history snapshot clone cost

* test(ci): annotate snapshot assertions for no-panics matcher

* test(ci): keep no-panics suppression on single-line assertion

* test(ci): keep snapshot tail assert single-line for no-panics

* Update src/agent/routine_engine.rs

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* chore(deps): bump yanked uds_windows in lockfile for cargo-deny

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-14 13:06:36 -07:00
Nick PismenkovandGitHub 3f2796b745 fix: Non-transactional multi-step context updates between metadata/to… (#1161)
* fix: Non-transactional multi-step context updates between metadata/token setup and DB

* fix: code style
2026-03-14 13:06:30 -07:00
NigeandGitHub 8dfad332d9 fix(webhook): avoid lock-held awaits in server lifecycle paths (#1168)
* fix(webhook): avoid holding mutex across async shutdown

* test(webhook): add regression coverage for begin_shutdown split path

* test(webhook): satisfy no-panics rule in begin_shutdown regression
2026-03-14 13:06:24 -07:00
NigeandGitHub 7c017ea6fd chore(registry): align manifest versions with published artifacts (#1169) 2026-03-14 13:06:04 -07:00
579c4fdbca chore: remove __pycache__ from repo and add to .gitignore (#1177)
Python bytecode cache files were accidentally committed. Remove them
from tracking and prevent future occurrences via .gitignore.

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-14 19:17:48 +00:00
Nick PismenkovandGitHub 1770663279 fix: Google Sheets returns 403 PERMISSION_DENIED after completing OAuth (#1164)
* fix: Google Sheets returns 403 PERMISSION_DENIED after completing OAuth

* fix: linter

* fix: linter

* fix: ci

* fix

* fix

* fix

* fix
2026-03-14 12:01:47 -07:00
8fb2f70258 fix: HTTP webhook secret transmitted in request body rather than via header, docs inconsistency and security concern (#1162)
Implement industry-standard HMAC-SHA256 header-based webhook authentication
to resolve issue #722. The X-Hub-Signature-256 header follows GitHub's
webhook security model, replacing the non-standard X-IronClaw-Signature header.

**Changes:**
- Rename HTTP webhook signature header from X-IronClaw-Signature to X-Hub-Signature-256
- X-Hub-Signature-256 is the standard used by GitHub, Stripe, and other webhook providers
- HMAC-SHA256 signatures continue to use sha256=<hex> format
- Body 'secret' field remains supported as deprecated fallback for backward compatibility
- All error messages and documentation updated to reflect new header name

**Security impact:**
- Signatures verified via HTTP header instead of request body
- Signature visible in Authorization header only, not logged in request body
- Follows industry best practices for webhook authentication
- Fail-closed policy: rejects requests without authentication

**Backward compatibility:**
- Requests without X-Hub-Signature-256 header fall back to 'secret' field in body (with deprecation warning)
- Deprecation path: migrate to header-based auth, body field support will be removed in a future release

**Test coverage:**

Unit tests (20 tests in src/channels/http.rs):
- 6 header-based auth tests (valid/invalid/malformed signatures, header encoding)
- 2 backward compatibility tests (deprecated body secret fallback)
- 3 error handling tests (missing auth, invalid JSON, content-type validation)
- 4 signature verification unit tests (valid digest, invalid digest, missing prefix, invalid hex)
- 5 advanced tests (concurrency, dynamic updates, header precedence, no deadlocks, runtime clearing)

E2E tests (12 tests in tests/e2e/scenarios/test_webhook.py):
- Valid HMAC-SHA256 signature acceptance
- Invalid/wrong/malformed signature rejection
- Header precedence over body secret
- Deprecated body secret backward compatibility
- Missing auth rejection (fail-closed)
- Content-Type validation
- Invalid JSON handling
- Case-insensitive header lookup
- Message queuing and processing
- Fixture for running server with HTTP_WEBHOOK_SECRET configured

All 3,033 lib tests pass with zero clippy warnings.

**Example usage after fix:**

BODY='{"content": "hello"}'
SECRET="your-webhook-secret"
SIG=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')

curl -X POST http://127.0.0.1:9090/webhook \
  -H "Content-Type: application/json" \
  -H "X-Hub-Signature-256: sha256=$SIG" \
  -d "$BODY"

Co-authored-by: Claude Haiku 4.5 <[email protected]>
2026-03-14 12:01:38 -07:00
c916069dd2 refactor(registry): move MCP servers from code to JSON manifests (#1144)
* refactor(registry): move MCP server entries from code to JSON manifests

Move 8 hardcoded MCP server RegistryEntry structs from
builtin_entries() into data-driven JSON files under
registry/mcp-servers/, matching the existing pattern used by
tools and channels. Exclude the GitHub MCP entry which conflicts
with the WASM GitHub tool's OAuth flow.

Extend ManifestKind with McpServer, make version/source optional
on ExtensionManifest (MCP servers don't need them), and add
url/auth fields for MCP-specific config. Update build.rs,
embedded catalog, catalog loader, installer, and CLI display
to handle the new kind and optional fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(registry): address PR review — add missing slack-mcp, remove .expect(), fix fmt

- Add missing slack-mcp.json (was dropped during migration)
- Remove production .expect() in get_strict(), replace with .ok_or_else()
- Clean up unwrap_or_default() in key_for() to use .next() directly
- Log warning for MCP manifests missing url field instead of silent empty
- Run cargo fmt to fix formatting diffs

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* ci: re-trigger CI with correct base branch (staging)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(ci): improve no-panics check to properly exclude test modules

The grep-based filter only excluded lines literally containing
#[cfg(test)], #[test], or 'mod tests' — not lines *inside* test
modules. Use awk to track hunk context from diff @@ headers and
skip all added lines within test module hunks.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* refactor(registry): remove slack-mcp MCP entry (conflicts with WASM slack tool)

Remove slack-mcp.json alongside the already-excluded github MCP
entry — both conflict with existing WASM tools of the same name.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix(registry): address re-review — skip invalid MCP entries, fix install order

- to_registry_entry() now returns Option<RegistryEntry>; MCP manifests
  missing a url field are skipped with a warning instead of creating
  broken entries with empty URLs
- Move McpServer early-return before require_source() in install paths
  so the error message is clear ("cannot install MCP servers") rather
  than the misleading "missing source spec"
- Add test for MCP manifest with missing URL returning None

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-14 18:59:55 +00:00
757d24bd90 feat(web): add follow-up suggestion chips and ghost text (#1156)
* feat(web): add follow-up suggestion chips and ghost text to chat UI

The LLM now always generates 1-3 follow-up command suggestions via
<suggestions> tags in its response. These are extracted server-side,
broadcast as SSE events, and rendered as clickable chips above the
chat input. The first suggestion also appears as ghost text in the
input field (Tab to accept). Includes debug logging for LLM responses
in the agentic loop and removes noisy NEAR AI status logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix: resolve deferred review items from PR #1156 [skip-regression-check]

- Remove literal backslashes from raw string prompt (reasoning.rs)
- Make WASM channels skip Suggestions status (no-op instead of empty callback)
- Add !e.shiftKey guard to Tab-to-accept ghost text handler
- Cap extracted suggestions at 3 and trim whitespace-only entries
- Extract suggestions in approval-resume path (prevents tag leaking)
- Remove stale .has-ghost class during showSuggestionChips reset

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-14 18:57:24 +00:00
Henry ParkandGitHub f9b880c2e9 fix(ci): exclude ironclaw_safety from release automation (#1146) 2026-03-13 21:20:02 -07:00
Henry ParkandGitHub 3debe41f71 Merge pull request #1149 from nearai/staging-promote/2b625ef3-23068472433
chore: promote staging to staging-promote/7d745d54-23066609095 (2026-03-13 20:06 UTC)
2026-03-13 13:19:17 -07:00
2b625ef3df fix(registry): bump versions for github, web-search, and discord extensions (#1106)
Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-13 19:12:48 +00:00
Henry ParkandGitHub 7d745d5479 tools: improve routine schema guidance (#1089) 2026-03-13 11:24:45 -07:00
Henry ParkandGitHub 1bc10fe4ca test: add event-trigger routine e2e coverage (#1088) 2026-03-13 11:24:25 -07:00