Skip to content

Merge upstream master review#14

Merged
Kairotan merged 264 commits intomasterfrom
merge-upstream-master-review
Apr 3, 2026
Merged

Merge upstream master review#14
Kairotan merged 264 commits intomasterfrom
merge-upstream-master-review

Conversation

@Kairotan
Copy link
Copy Markdown
Owner

@Kairotan Kairotan commented Apr 3, 2026

Summary

Describe this PR in 2-5 bullets:

  • Base branch target (master for all contributions):
  • Problem:
  • Why it matters:
  • What changed:
  • What did not change (scope boundary):

Label Snapshot (required)

  • Risk label (risk: low|medium|high):
  • Size label (size: XS|S|M|L|XL, auto-managed/read-only):
  • Scope labels (core|agent|channel|config|cron|daemon|doctor|gateway|health|heartbeat|integration|memory|observability|onboard|provider|runtime|security|service|skillforge|skills|tool|tunnel|docs|dependencies|ci|tests|scripts|dev, comma-separated):
  • Module labels (<module>: <component>, for example channel: telegram, provider: kimi, tool: shell):
  • Contributor tier label (trusted contributor|experienced contributor|principal contributor|distinguished contributor, auto-managed/read-only; author merged PRs >=5/10/20/50):
  • If any auto-label is incorrect, note requested correction:

Change Metadata

  • Change type (bug|feature|refactor|docs|security|chore):
  • Primary scope (runtime|provider|channel|memory|security|ci|docs|multi):

Linked Issue

  • Closes #
  • Related #
  • Depends on # (if stacked)
  • Supersedes # (if replacing older PR)

Supersede Attribution (required when Supersedes # is used)

  • Superseded PRs + authors (#<pr> by @<author>, one per line):
  • Integrated scope by source PR (what was materially carried forward):
  • Co-authored-by trailers added for materially incorporated contributors? (Yes/No)
  • If No, explain why (for example: inspiration-only, no direct code/design carry-over):
  • Trailer format check (separate lines, no escaped \n): (Pass/Fail)

Validation Evidence (required)

Commands and result summary:

cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test
  • Evidence provided (test/log/trace/screenshot/perf):
  • If any command is intentionally skipped, explain why:

Security Impact (required)

  • New permissions/capabilities? (Yes/No)
  • New external network calls? (Yes/No)
  • Secrets/tokens handling changed? (Yes/No)
  • File system access scope changed? (Yes/No)
  • If any Yes, describe risk and mitigation:

Privacy and Data Hygiene (required)

  • Data-hygiene status (pass|needs-follow-up):
  • Redaction/anonymization notes:
  • Neutral wording confirmation (use ZeroClaw/project-native labels if identity-like wording is needed):

Compatibility / Migration

  • Backward compatible? (Yes/No)
  • Config/env changes? (Yes/No)
  • Migration needed? (Yes/No)
  • If yes, exact upgrade steps:

i18n Follow-Through (required when docs or user-facing wording changes)

  • i18n follow-through triggered? (Yes/No)
  • If Yes, locale navigation parity updated in README*, docs/README*, and docs/SUMMARY.md for supported locales (en, zh-CN, ja, ru, fr, vi)? (Yes/No)
  • If Yes, localized runtime-contract docs updated where equivalents exist (minimum for fr/vi: commands-reference, config-reference, troubleshooting)? (Yes/No/N.A.)
  • If Yes, Vietnamese canonical docs under docs/i18n/vi/** synced and compatibility shims under docs/*.vi.md validated? (Yes/No/N.A.)
  • If any No/N.A., link follow-up issue/PR and explain scope decision:

Human Verification (required)

What was personally validated beyond CI:

  • Verified scenarios:
  • Edge cases checked:
  • What was not verified:

Side Effects / Blast Radius (required)

  • Affected subsystems/workflows:
  • Potential unintended effects:
  • Guardrails/monitoring for early detection:

Agent Collaboration Notes (recommended)

  • Agent tools used (if any):
  • Workflow/plan summary (if any):
  • Verification focus:
  • Confirmation: naming + architecture boundaries followed (AGENTS.md + CONTRIBUTING.md):

Rollback Plan (required)

  • Fast rollback command/path:
  • Feature flags or config toggles (if any):
  • Observable failure symptoms:

Risks and Mitigations

List real risks in this PR (or write None).

  • Risk:
    • Mitigation:

singlerider and others added 30 commits March 28, 2026 15:06
…claw-labs#4805)

* fix(matrix): preserve thread context on first follow-up message

Always root a thread at the incoming message event ID instead of
leaving thread_ts as None for non-threaded messages. This prevents
a session key mismatch where the first exchange is stored under a
room-level key but follow-up messages use a thread-scoped key,
causing the bot to lose context from the initial question and
response.

The bot now explicitly threads its response back to the user's
original message rather than relying on Matrix implicit threading.
Thread root is the user's question, not the bot's answer.

Documents threading behavior in the E2EE guide. In encrypted rooms,
the SDK decrypts events transparently before thread context is
evaluated, so threading works identically.

Closes zeroclaw-labs#4804

* fix(lint): apply cargo fmt to context_compressor.rs
…abs#4632)

The fetch_paircode function was constructing URLs without considering
the gateway.path_prefix configuration option. This caused the CLI
command "zeroclaw gateway get-paircode" to fail when path_prefix
was configured (e.g., for reverse proxy deployments).

Changes:
- Add path_prefix parameter to fetch_paircode function
- Include path_prefix in admin API URLs (/admin/paircode and /admin/paircode/new)
- Extract path_prefix from config in GetPaircode command handler

Fixes zeroclaw-labs#4456
… paths on macOS (zeroclaw-labs#4529)

Co-authored-by: wangyingtao.10 <wangyingtao.10@jd.com>
…users (zeroclaw-labs#4438)

* fix(gateway): improve web dashboard unavailable message for Homebrew users (zeroclaw-labs#3655)

The error shown when the web dashboard is not bundled now includes
context-specific guidance for Homebrew users (brew reinstall zeroclaw),
manual build-from-source instructions, and a Docker alternative.

Also harden the pub-homebrew-core workflow's Node.js dependency injection
so it falls back gracefully when the 'rust' depends_on line is absent,
ensuring node is always declared as a build dependency in the formula.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(wati): add missing attachments field to ChannelMessage initializer

Pre-existing build error from feat(channels): add automatic media understanding pipeline (zeroclaw-labs#4402).

---------

Co-authored-by: SpaceLobster <spacelobster@SpaceLobsters-Mac-mini.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…w-labs#4341)

Add /usr/local, /bin, and /sbin as read-only bind mounts in the
bubblewrap sandbox configuration. This fixes a regression where
Python and other system tools installed in these directories
were not accessible within the sandbox.

Fixes zeroclaw-labs#4338
…ix (zeroclaw-labs#4552)

The executable basename was lowercased by the caller, but the allowlist
entry was compared in its original case. This caused mixed-case entries
like "icalBuddy" to fail matching on Unix, while working on Windows
(which had its own lowercase fallback).

Lowercase the allowlist entry before comparison so "icalBuddy" in config
matches the "icalbuddy" executable.

Closes zeroclaw-labs#4446

Co-authored-by: rareba <rareba@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…roclaw-labs#4378)

Enable cron jobs to deliver messages to Feishu/Lark channels using
the same pattern as existing channel implementations.

Changes:
- Add "lark" and "feishu" to validated delivery channels in cron/mod.rs
- Add delivery logic in cron/scheduler.rs with channel-lark feature gating
- Update agent loop default injection to support lark/feishu
- Update tool schemas and help text for lark/feishu

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
zeroclaw-labs#4448)

Remove the separate channel message notifications for tool calls since
they are already displayed via the draft updater progress messages.
This fixes the issue where agent chat was sending multiple messages
instead of a single consolidated response.

The tool call progress (🔧 tool name, ⏳/✅ status) is already sent through
the on_delta channel and displayed in the draft message. Sending additional
separate channel messages was causing spammy/duplicate output.

Fixes zeroclaw-labs#3513
…roclaw-labs#4322)

* feat(config): add provider_env for injecting API keys from config

New [provider_env] section allows storing provider API keys directly
in config.toml instead of relying on shell environment. Keys are
injected as process env vars at startup (only if not already set).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(onboard): add missing provider_env field to wizard Config constructors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…law-labs#4436)

* fix(agent): consolidate multiple messages into single response (zeroclaw-labs#3513)

Suppress intermediate tool_call and tool_result WebSocket events from
being rendered as separate chat message bubbles in AgentChat. Internal
tool invocations are processing steps — only the final 'done' event
with full_response should appear as an agent message.

Also removes dead i18n keys (agent.tool_call_prefix,
agent.tool_result_prefix) that were only used by the removed handlers.

Fixes zeroclaw-labs#3513

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(wati): add missing attachments field to ChannelMessage initializer

Pre-existing build error from feat(channels): add automatic media understanding pipeline (zeroclaw-labs#4402).
The attachments field was added to ChannelMessage but not all initializers were updated.

---------

Co-authored-by: SpaceLobster <spacelobster@SpaceLobsters-Mac-mini.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…eroclaw-labs#4883)

* fix(tests): serialize Bedrock env-var tests to prevent parallel race

Closes zeroclaw-labs#4809

* style: fix pre-existing fmt and clippy warnings

- cargo fmt: wrap long assert! macros in uf2.rs and uno_q_bridge.rs
- clippy: use underscored hex literal 0x0200_0000 in schema.rs
- clippy: gate unix-only TempDir import behind #[cfg(unix)]

---------

Co-authored-by: rareba <rareba@users.noreply.github.com>
- Dockerfile: add `debian` target alongside existing `dev` and `release`
  targets, replacing the separate Dockerfile.debian
- Dockerfile.ci: use VARIANT build-arg (distroless|debian) to replace
  the separate Dockerfile.debian.ci
- Update release workflows to use `build-args: VARIANT=debian`
- Update docker-compose.yml to use `target: debian`
- Remove Dockerfile.debian and Dockerfile.debian.ci

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…zeroclaw-labs#4213)

* feat(debug): add --log-llm flag to dump LLM provider message payloads

Adds a global --log-llm flag that logs the exact messages sent to the
LLM provider on each turn: full system prompt + history on turn one,
growing history on subsequent turns.

Usage:
  zeroclaw agent --log-llm
  zeroclaw agent --log-llm -m "hello"
  zeroclaw daemon --log-llm

Implementation:
- Global `--log-llm` flag on `Cli` (available to all subcommands)
- When set, adds a `zeroclaw::providers::reliable=trace` directive to
  the tracing subscriber filter so only LLM message traces surface,
  without flooding other TRACE-level noise
- `ReliableProvider::chat()` emits one TRACE log per message (role,
  char count, full content) on the first attempt of each call; retries
  and failover attempts are not re-logged
- Gated on `tracing::enabled!(TRACE)` so the iteration over messages
  is a no-op at runtime when the flag is not set

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: apply rustfmt to --log-llm subscriber setup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(debug): pretty-print LLM messages as JSON array under --log-llm

Replaces the per-message trace loop with a single serde_json::to_string_pretty
of the full messages slice, producing a clean JSON array that mirrors the
actual wire payload sent to the provider.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…idate-dockerfiles

refactor: consolidate Dockerfiles from 4 to 2
* fix(channels): skip tools summary for native tools

* test(channels): adapt native-tools prompt respin to autonomy arg
…atible providers (zeroclaw-labs#4333)

Custom OpenAI-compatible providers (configured via "custom:<url>") were
incorrectly falling back to the /v1/responses API when chat completions
returned 404. This caused errors because most custom providers only support
the standard /v1/chat/completions endpoint.

Changes:
- Add new constructor new_with_vision_no_responses_fallback() to
  OpenAiCompatibleProvider
- Update custom provider factory to use the new constructor

Fixes zeroclaw-labs#4296
…_CTX (zeroclaw-labs#3518)

* Ignore JetBrains .idea folder

* fix(ollama): support stringified JSON tool call arguments

* providers: allow ZEROCLAW_PROVIDER_URL env var to override Ollama base URL

Supports container deployments where Ollama runs on a Docker network host
(e.g. http://ollama:11434) without requiring config.toml changes.

Includes regression test ensuring the environment override works.

* fix(clippy): replace Default::default() with ProviderRuntimeOptions::default()

* feat(ollama): allow configurable context size via ZEROCLAW_OLLAMA_NUM_CTX

---------

Co-authored-by: Argenis <theonlyhennygod@gmail.com>
…ers (zeroclaw-labs#4173)

The Ollama provider previously stripped the :cloud suffix from model names
for any non-localhost endpoint, assuming all remote endpoints were Ollama
Cloud (ollama.com). This caused a 404 when a private Ollama server (e.g.
a LAN server at 192.168.x.x) was configured as api_url: the local server
stores cloud-proxy models under their full name (e.g. "glm-5:cloud"), so
stripping the tag results in "model not found" instead of the correct
"quota exhausted" (429) error.

Fix: introduce is_ollama_cloud_endpoint() which matches only ollama.com.
The :cloud suffix is now stripped (and auth required) only when targeting
Ollama Cloud. Private remote servers receive the model name as-is, letting
them serve the cloud-proxy model correctly and return the proper 429 when
cloud quota is exhausted — which triggers fallback to a local model.

Two new tests cover the private-server behavior.

Co-authored-by: ZeroClaw <zeroclaw@zeroclaw.bot>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…fails (zeroclaw-labs#4538)

Cherry-picked from PR zeroclaw-labs#4411:
- Add Clone derive to ResponsesRequest and related structs for retry
- Retry with stream=false when streaming decode fails
- Add missing field initializers for ChannelMessage (already present in master)

Co-authored-by: OpenClaw Assistant <assistant@openclaw.ai>
…claw-labs#4358)

Explicitly discard the Result from `client.encryption().backups().disable().await`
with `let _ = ...` to silence the unused Result compiler warning when building
with `--features channel-matrix`.

Closes zeroclaw-labs#4339

Co-authored-by: rareba <rareba@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
…on (zeroclaw-labs#4148)

* fix: prevent panic on UTF-8 multi-byte char boundary in slug truncation

Use char_indices to find a valid UTF-8 boundary when truncating slugs
longer than 64 bytes, preventing panics with CJK input.

Closes zeroclaw-labs#4139

Signed-off-by: majiayu000 <1835304752@qq.com>

* chore: bump version to 0.5.6

Signed-off-by: majiayu000 <1835304752@qq.com>

* chore: sync Cargo.lock with version 0.5.6

Signed-off-by: majiayu000 <1835304752@qq.com>

---------

Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
…aw-labs#4108)

Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
…eroclaw-labs#4835)

Channel mode was using a hardcoded constant (50) for history message
limit instead of respecting the user-configured max_history_messages
value from the agent configuration.

Changes:
- Remove hardcoded MAX_CHANNEL_HISTORY constant from src/channels/mod.rs
- Use ctx.prompt_config.agent.max_history_messages in append_sender_turn()
- Maintains backward compatibility via default value of 50

Fixes zeroclaw-labs#4740

Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
zeroclaw-labs#4359)

Drop the original `delta_tx` sender before awaiting the draft-updater
task.  Without this, the mpsc channel never closes because the original
sender stays alive on the stack even after `run_tool_call_loop` drops
its clone, causing `draft_updater.await` to block indefinitely.

Added tracing::debug! at the start and end of the post-loop draft
shutdown path for observability.

Fixes zeroclaw-labs#4300

Co-authored-by: rareba <rareba@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
Change "exposed to the internet" to "exposed on all network interfaces"
which is more accurate — 0.0.0.0 binds to all interfaces, not
necessarily the internet (e.g. VM/container environments).  Also
remove "(NOT recommended)" qualifier since containers/VMs are a
valid use case, and broaden Docker guidance to cover VMs too.

Closes zeroclaw-labs#4762

Co-authored-by: rareba <rareba@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
…...) (zeroclaw-labs#4734)

Field type changed to Option<String> (#serde default) but test fixtures
were not updated, causing E0308 compile errors on master.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
…abs#4410)

Restores the --interactive flag to the onboard command to allow users
to force interactive wizard mode regardless of TTY auto-detection.

- Add --interactive argument to onboard command
- Modify auto-detection logic to respect --interactive flag
- Update test to verify flag acceptance instead of rejection

Fixes zeroclaw-labs#3658

Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
…-labs#4334)

* fix(tools): make shell timeout configurable via config.toml

Add `shell_timeout_secs` field to `[autonomy]` config section, wired
through `SecurityPolicy` to `ShellTool`.  The hardcoded 60-second
constant is kept as the default fallback so behaviour is unchanged for
existing configurations.

Closes zeroclaw-labs#4331

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add shell_timeout_secs to all AutonomyConfig construction sites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: rareba <rareba@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…roclaw-labs#4544)

web_search_tool expects "query" as its parameter but was missing from
the default_param_for_tool match, falling through to the catch-all
"input". This caused GLM-style shortened tool calls to produce
{"input": "..."} instead of {"query": "..."}, silently failing.

Also moved web_search from the URL group to the query group (search
tools use "query", not "url") and added web_fetch to the URL group.

Closes zeroclaw-labs#4542

Co-authored-by: rareba <rareba@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: SimianAstronaut7 <79373020+SimianAstronaut7@users.noreply.github.com>
@Kairotan Kairotan merged commit 7a975f9 into master Apr 3, 2026
20 checks passed
@Kairotan Kairotan deleted the merge-upstream-master-review branch April 3, 2026 04:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment