Commit Graph

982 Commits

Author SHA1 Message Date
argenis de la rosa
7bcc8d5d26 fix(agent): address review feedback on session state persistence
- Validate version field on load; bail on unsupported versions
- Refresh stale system prompt from history[0] on resume
- Use write-to-temp-then-rename for atomic saves
- Add tests for nonexistent file, malformed JSON, unsupported version,
  and stale system prompt refresh
2026-03-13 18:42:28 -04:00
TOTHEMOON\youdo
95c9080a37 feat(agent): 支持交互会话状态持久化与恢复 2026-03-13 18:08:17 +08:00
Darren.Zeng
2cb57e6b2d
fix(cli): honor config default_temperature in agent command (#3106)
* fix(cli): honor config default_temperature in agent command

Fixes #3033

The agent command was using a hardcoded default_value of 0.7 for the
--temperature parameter, which ignored the default_temperature setting
in the config file.

Changes:
- Changed temperature from f64 to Option<f64>
- Removed hardcoded default_value
- Use config.default_temperature when --temperature is not provided

Users can now set default_temperature in config.toml and have it
honored when running 'zeroclaw agent' without --temperature.

Risk: low (behavior change: now honors config instead of hardcoded value)

* fix: resolve moved value error for config in agent command

Extract final_temperature before passing config to agent::run() to
avoid use-of-moved-value error (config is moved as the first argument
while config.default_temperature was being accessed in the same call).

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

---------

Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:34:32 -04:00
Argenis
448682c440
feat(providers): add Azure OpenAI provider support (#3246)
Closes #3176
2026-03-12 00:06:11 -04:00
Argenis
3fe3fe23b1
feat(build): add 32-bit system support via feature gates (#3245)
Closes #3174
2026-03-12 00:06:08 -04:00
ImanHashemi
273bd00d08
feat(hooks): add webhook-audit builtin hook (#3212)
Co-authored-by: ImanHashemi
2026-03-11 23:34:17 -04:00
Darren.Zeng
d33b73974b
feat(provider): add vision support for Anthropic provider (#3177)
Add vision support to Anthropic provider to enable image understanding:

- Add ImageSource struct for Anthropic's image content block format
- Add Image variant to NativeContentOut enum
- Implement capabilities() returning vision: true
- Update convert_messages() to parse [IMAGE:...] markers and convert
them to Anthropic's native image content blocks
- Support both data URIs and local file paths
- Add comprehensive tests for vision functionality

Fixes #3163

Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:27:58 -04:00
Darren.Zeng
ab6846cb9f
feat(channel): make email subject configurable (#3190)
Add default_subject field to EmailConfig to allow users to customize
the default subject line for outgoing emails. Previously hardcoded as
"ZeroClaw Message".

- Add default_subject field with serde default
- Update send() method to use configured default
- Add tests for new functionality

Fixes #2878

Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:27:52 -04:00
Darren.Zeng
ca683816a7
fix(config): fix web_fetch allowed_domains serde default (#3192)
When [web_fetch] section was specified in config without explicit
allowed_domains, serde used Vec::default() (empty vector) instead of
the wildcard ["*"] default. This caused all web fetch requests to be
rejected unexpectedly.

Fix by adding explicit serde default function that returns vec!["*"].

Fixes #2941

Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:27:49 -04:00
Darren.Zeng
8d7abb73e7
fix(config): accept openai-* aliases for wire_api config (#3191)
Add support for openai-responses, open-ai-responses, openai-chat-completions,
and open-ai-chat-completions as aliases for wire_api configuration values.
This aligns the parser with documented values that users expect to work.

Fixes #2735
2026-03-11 22:09:50 -04:00
Darren.Zeng
7ddf10f86d
feat(onboard): add --reinit flag to prevent accidental config overwrite (#3102)
* feat(onboard): add --reinit flag to prevent accidental config overwrite

Add --reinit flag to onboard command that:
- Backs up existing ~/.zeroclaw directory with timestamp
- Starts fresh initialization after backup
- Requires --interactive mode to work
- Prevents accidental configuration loss

This addresses issue #3013 where onboard could accidentally
overwrite all configuration without warning.

Closes #3013

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* fix(ci): SHA-pin all third-party GitHub Actions

Replace mutable version tags with immutable commit SHAs to prevent
tag-hijacking supply chain attacks (P1 finding).

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

* chore: retrigger CI after startup_failure

* fix(onboard): address PR #3102 review issues for --reinit flag

- Use resolve_runtime_dirs_for_onboarding() instead of hardcoded ~/.zeroclaw
- Remove unsafe relative path fallback, bail instead
- Add user confirmation prompt before reinitializing config
- Update docs/reference/cli/commands-reference.md with --reinit docs

* style: fix cargo fmt and clippy violations

- Fix import ordering in src/config/mod.rs (rustfmt)
- Collapse single-arg encrypt/decrypt calls in src/config/schema.rs (rustfmt)
- Box::pin large onboard futures to fix clippy::large_futures in src/main.rs

These violations were blocking CI lint checks.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Simian Astronaut 7 <simianastronaut7@gmail.com>
2026-03-11 22:09:39 -04:00
Darren.Zeng
ef2f8e9808
fix(daemon): handle SIGTERM for graceful shutdown (#3193)
The daemon previously only handled SIGINT (Ctrl+C), ignoring SIGTERM
which is the standard termination signal used by Docker, Kubernetes,
and systemd. This caused containers to wait for the grace period
then be force-killed with SIGKILL.

Now the daemon handles both SIGINT and SIGTERM for graceful shutdown.

Fixes #2529
2026-03-11 22:09:34 -04:00
Argenis
5cf1c77531
style: fix cargo fmt violations blocking CI lint (#3244)
* style: fix cargo fmt in ollama.rs test

* style: cargo fmt dispatcher.rs

* style: cargo fmt loop_.rs

* style: cargo fmt schema.rs

* style: cargo fmt mod.rs

* style: cargo fmt ws.rs

* style: cargo fmt ollama.rs
2026-03-11 21:53:25 -04:00
Argenis
483d3c0853
fix(ollama): strip <think> tags from Qwen responses and validate tool calls (#3079) (#3241)
- Strip `<think>...</think>` blocks in parse_tool_calls(), XmlToolDispatcher,
  and OllamaProvider before processing tool-call XML
- Add effective_content() fallback: when content is empty after stripping
  think tags, check the thinking field for tool-call XML
- Add strip_think_tags() to ollama.rs, loop_.rs, and dispatcher.rs
- Add comprehensive tests for think-tag stripping and tool-call parsing

Fixes #3079

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:35:33 -04:00
Argenis
f5cd6baec3
fix(gateway): add /api/integrations/settings, echo WS protocol, persist session ID (#3242)
- #3009: Add handle_api_integrations_settings endpoint returning JSON with
  per-integration enabled/category/status so /api/integrations/settings no
  longer falls through to the SPA static handler.

- #3010: Extract Sec-WebSocket-Protocol header in handle_ws_chat and echo
  back "zeroclaw.v1" via ws.protocols() when the client requests it.

- #3038: Generate a persistent session_id (crypto.randomUUID stored in
  sessionStorage) in the web WS client and pass it as a query parameter.
  Add session_id: Option<String> to WsQuery on the server side so the
  backend can key conversations by session across reconnects.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:35:27 -04:00
Argenis
12cfe48047
fix(config): add channel secrets roundtrip test and gitignore entries (#3126) (#3240)
Add a test verifying Telegram bot_token is encrypted on save and
decrypted on load, and add .gitignore entries for local state backups.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:35:11 -04:00
Jaime Linares
0479bfca36
fix(channel): reconnect WhatsApp Web session and show QR on logout (#3045)
Wraps the WhatsApp Web listen() in a reconnect loop. When Event::LoggedOut
fires, the bot is torn down, stale session DB files are deleted, and after
exponential backoff (3s base, 300s cap, max 10 retries) the loop restarts
triggering fresh QR pairing.

- Broadcast channel for logout signaling from event handler to listen loop
- Session file cleanup (primary + WAL + SHM) only on explicit LoggedOut
- Proper resource ordering: client lock, abort handle, drop bot/device
- Tests for retry delay, counter, session purge, and file paths helpers
2026-03-11 20:30:28 -04:00
Argenis
195c7ba919
fix(agent): resolve display text for tool-only turns (#3054) 2026-03-11 20:08:16 -04:00
James Cowan
bb66df5276
fix(config): encrypt and decrypt all channel secrets on save/load (#3217)
Adds symmetric encrypt/decrypt calls for all channel secret fields in
Config::save() and Config::load_or_init(). Previously only nostr.private_key
was handled, leaving all other channel secrets (bot_token, app_token,
access_token, api_token, password, etc.) and gateway.paired_tokens stored
as plaintext when secrets.encrypt = true.

Closes #3175, closes #3173.

Co-authored-by: jameslcowan
2026-03-11 20:02:20 -04:00
Alan P John
74fe29d772
feat: Add Opencode-go provider (#3113)
Adds opencode-go as a first-class provider with dedicated API endpoint,
env var, onboarding wizard wiring, and test coverage.

CI failures are pre-existing on master (Rust 1.94 formatting/lint changes per #3207).
2026-03-11 19:35:43 -04:00
Argenis
86ca34ac1f
fix(tests): update assertions for live tool call notifications (#3232)
The live tool call notifications feature sends extra messages to the
channel when tools are invoked. Update 5 tests that assumed exactly
1 sent message to instead check the last message in the list.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:26:45 -04:00
Argenis
f0f0f80895
feat(matrix): add multi-room support (#3224)
Enable a single Matrix bot instance to respond in multiple rooms:
- Disable the room_id filter so messages from all joined rooms are processed
- Embed room_id in reply_target as "user||room_id" for routing replies
- Include room_id in channel field for per-room conversation isolation
- Extract room_id from recipient in send() for correct message routing

The configured room_id still serves as a fallback for direct sends
without a "||" separator in the recipient.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:13:18 -04:00
Argenis
01bcba83ad
feat(matrix): add file upload handling and voice message support (#3222) 2026-03-11 19:12:44 -04:00
Argenis
bdc0f325bf
feat(matrix): add pin and unpin message support (#3220)
Implement pin_message and unpin_message for the Matrix channel using
the m.room.pinned_events state event. Adds default no-op trait methods
to the Channel trait so other channel implementations are unaffected.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:10:08 -04:00
Abdullah Imad
248348bd80
feat(matrix): reaction and threading support (#3219)
Implement add_reaction/remove_reaction for Matrix channel using
ReactionEventContent and redaction. Add threading support via
Relation::Thread in send() and thread_ts extraction from incoming
messages, enabling threaded conversations.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 19:07:49 -04:00
Abdullah Imad
bd70c0f45b
feat(observer): live tool call notifications (#3221)
Add ChannelNotifyObserver that wraps the observer to forward tool-call
events as real-time threaded messages on messaging channels. Include
tool arguments (truncated) in ToolCallStart events for better
visibility into what tools are doing. Auto-thread final replies when
tools were used.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 19:07:34 -04:00
Abdullah Imad
d0edcec1f9
feat(prompt): refresh stale datetime (#3223)
The system prompt is built once at daemon startup and cached. The
"Current Date & Time" section becomes stale immediately. This patch
replaces it with a fresh timestamp every time build_channel_system_prompt
is called (i.e. per incoming message).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:04:23 -04:00
Aleksandr Prilipko
39353748fa
fix(memory): resolve embedding api_key from embedding_provider env var, not default_provider key (#3184)
When embedding_provider differs from default_provider (e.g. default=gemini,
embedding=openai), the caller-supplied api_key belongs to the chat provider.
Passing it to the embedding endpoint causes 401 Unauthorized (gemini key
sent to api.openai.com/v1/embeddings).

Add embedding_provider_env_key() which looks up OPENAI_API_KEY,
OPENROUTER_API_KEY, or COHERE_API_KEY before falling back to the
caller-supplied key. This matches the provider-specific env var resolution
in providers/mod.rs without introducing cross-module coupling.

Also add config_secrets_survive_save_load_roundtrip test: full save→load
cycle with channel credentials (telegram, discord, slack bot_token,
slack app_token) and gateway paired_tokens, verifying that enc2: values
are correctly decrypted by Config::load_or_init(). Regression guard for
issues #3173 and #3175.

Closes #3083

Co-authored-by: ZeroClaw Bot <zeroclaw_bot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 15:39:54 -04:00
Argenis
50a65ea0e5
Merge branch 'master' into fix/channel-model-switch-resolve-routes 2026-03-11 13:32:15 -04:00
Argenis
9cfc88c38c
Merge pull request #3201 from whtiehack/pr/fix-channel-embedding-routes
fix(channels): pass embedding routes to channel memory init
2026-03-11 12:07:53 -04:00
smallwhite
7cacdef2d1 fix(channels): pass embedding routes to channel memory init 2026-03-11 23:57:46 +08:00
smallwhite
1c2a49459e fix(agent): strip prompt-guided tool artifacts from visible replies 2026-03-11 23:50:39 +08:00
panviktor
0ee3b6d617 fix(channels): resolve provider from model_routes on /model, preserve context
- `/model <name>` now auto-resolves provider from configured model_routes
  by matching model name or hint, fixing 404 when switching to models on
  different providers (e.g. `/model kimi-k2.5` with anthropic default)
- Conversation history is no longer cleared on `/model` or `/models` —
  users can explicitly reset via `/new`
- Matrix channel now supports `/model`, `/models`, and `/new` commands
- `/model` (no args) lists configured model routes with hints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:10:42 +01:00
Simian Astronaut 7
5901f70dc0 fix(clippy): box-pin large onboard wizard futures
The onboard wizard futures exceed clippy's large_futures threshold
(16KB+). Wrap in Box::pin to heap-allocate and fix the lint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:21:46 -04:00
Simian Astronaut 7
026158557c chore: fix rustfmt violations from TTS provider merge
Import ordering in config/mod.rs and line-wrapping in config/schema.rs
were left unformatted by PR #2994. Run cargo fmt to fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:09:06 -04:00
Simian Astronaut 7
162a2b65a5 fix(multi): harden Edge TTS path validation, add subprocess timeout, restore Slack symlink protection
Edge TTS: reject binary_path containing path separators to prevent
arbitrary executable paths bypassing the basename allowlist. Wrap
subprocess execution in tokio::time::timeout (60s) matching HTTP
providers.

Slack: restore symlink_metadata check before rename to prevent
symlink-following attacks on attachment output paths.

Docs: add TTS module misplacement note to refactor-candidates.md —
tts.rs belongs in src/tools/, not src/channels/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 10:05:52 -04:00
Simian Astronaut 7
e6bfb1ebee fix(slack): add HTTP timeouts, proper jitter, and cache bounds
HTTP clients had no timeouts and could hang forever; add 30s total and
10s connect timeouts. Replace clock-nanos-based jitter with rand::random
for proper randomness. Add a 1000-entry cap to the user display name
cache with expired-entry pruning. Fix truncate_text to avoid scanning
the full string twice when checking for truncation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 08:58:20 -04:00
Simian Astronaut 7
9a6de3b204 fix(tts): move Google API key to header and sanitize provider inputs
Google TTS was passing the API key as a URL query parameter, which can
appear in logs and proxy access records. Move it to the x-goog-api-key
header instead. Add input validation for ElevenLabs voice IDs (reject
non-alphanumeric/dash/underscore characters) and restrict Edge TTS
binary_path to allowed basenames (edge-tts, edge-playback).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 08:58:13 -04:00
Simian Astronaut 7
f894bc4140 fix(slack): only send bearer token on first redirect hop
Slack private file fetching was sending the bot token on every redirect
hop. Since Slack CDN redirects use pre-signed URLs, sending the bearer
token to CDN hosts is unnecessary credential exposure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 08:58:05 -04:00
Simian Astronaut 7
a1c65558d8 fix(gateway): restrict admin endpoints to localhost and replace process::exit with graceful shutdown
Admin endpoints (/admin/shutdown, /admin/paircode, /admin/paircode/new) were
completely unauthenticated, allowing any network client to shut down the gateway
or read/generate pairing codes. Add require_localhost() guard that returns 403
for non-loopback IPs.

Replace std::process::exit(0) in shutdown handler with a tokio watch channel
for graceful shutdown, allowing proper destructor cleanup and connection
draining. Replace the 500ms sleep race in the restart command with a poll loop
that waits for the port to actually become free.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 08:57:34 -04:00
Argenis
f2035819c2
Merge pull request #2994 from rareba/feature/tts-providers
feat(tts): add multi-provider TTS system
2026-03-11 05:23:50 -04:00
Kunal Karmakar
06926a189d Merge branch 'master' of https://github.com/kunalk16/zeroclaw into fix-honor-default-temperature-agent-command 2026-03-11 08:36:35 +00:00
Sid Jain
6016491985 fix(slack): harden redirect chain and auth health checks 2026-03-11 04:32:56 -04:00
Sid Jain
bf11b7b1a0 fix(slack): resolve clippy warnings in URL and tests 2026-03-11 04:32:56 -04:00
Sid Jain
436619b015 chore(slack): satisfy rustfmt wrap in MIME warning 2026-03-11 04:32:56 -04:00
Sid Jain
b33af6894e fix(slack): redact private URLs and harden attachment writes 2026-03-11 04:32:56 -04:00
Sid Jain
14de5e527e fix(slack): preserve auth and validate image bytes 2026-03-11 04:32:56 -04:00
Sid Jain
7b7e08dc21 fix(slack): align cron workspace dir and socket retry backoff 2026-03-11 04:32:56 -04:00
Sid Jain
526d63fd75 feat: add slack file reading capability to zeroclaw 2026-03-11 04:32:56 -04:00
曾文锋0668000834
e3cc40c64c feat(gateway): add --new flag to get-paircode for non-disruptive pairing code generation
- Add --new flag to GetPaircode command in src/lib.rs
- Update main.rs to handle GetPaircode { new } parameter
- Add /admin/paircode/new POST endpoint in gateway/mod.rs
- Enhance documentation for constant_time_eq security function

Refs: #3015
2026-03-11 04:30:58 -04:00