Use correct ISO 639-1 language code (vi) instead of country code (vn),
consistent with existing translations (zh-CN, ja, ru).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add full Vietnamese (Tiếng Việt) translation of README.md and update
language selector links across existing README files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When autonomy is set to "supervised", the approval gate only prompted
interactively on CLI. On Telegram and other channels, all tool calls
were silently auto-approved with ApprovalResponse::Yes, including
high-risk tools like shell — completely bypassing supervised mode.
On non-CLI channels where interactive prompting is not possible, deny
tool calls that require approval instead of auto-approving. Users can
expand the auto_approve list in config to explicitly allow specific
tools on non-interactive channels.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Restrict 19 internal-only modules from pub to pub(crate) in lib.rs,
reducing the public API surface of the library crate.
Modules kept pub (used by integration tests, benchmarks, or are
documented extension points per AGENTS.md):
agent, channels, config, gateway, memory, observability,
peripherals, providers, rag, runtime, tools
Modules restricted to pub(crate) (not imported via zeroclaw:: by any
external consumer):
approval, auth, cost, cron, daemon, doctor, hardware, health,
heartbeat, identity, integrations, migration, multimodal, onboard,
security, service, skills, tunnel, util
Also restrict 6 command enums (ServiceCommands, ChannelCommands,
SkillCommands, MigrateCommands, CronCommands, IntegrationCommands)
to pub(crate) — main.rs defines its own copies and does not import
these from the library crate. HardwareCommands and PeripheralCommands
remain pub as main.rs imports them via zeroclaw::.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When parallel_tools is enabled, both code branches in execute_tools()
ran the same sequential for loop. The parallel path was a no-op.
Use futures::future::join_all to execute tool calls concurrently when
parallel_tools is true. The futures crate is already a dependency.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace the single shared typing_handle with a HashMap keyed by
recipient channel ID. Previously, concurrent messages would fight
over one handle — starting typing for message B would cancel message
A's indicator, and stopping one would kill the other's.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
rotate_key() selects the next key in the round-robin but never applies
it to the underlying provider (Provider trait has no set_api_key
method). The previous info-level log implied rotation was working.
Change to warn-level and explicitly state the key is not applied,
making the limitation visible to operators instead of silently
pretending rotation works.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Network access (web search via DuckDuckGo) should require explicit user
consent rather than being enabled by default. This aligns with the
least-surprise principle and the project's secure-by-default policy:
users must opt in to external network requests.
Changes:
- WebSearchConfig::default() now sets enabled: false
- Serde default for enabled field changed from default_true to default
(bool defaults to false)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(installer): add guided zeroclaw installer entrypoint
- add top-level POSIX wrapper (zeroclaw_install.sh) that ensures bash is present
- route bootstrap/install compatibility scripts through the new installer entrypoint
- improve Linux dependency handling for Alpine/Fedora/Arch, including pacman container fallback
* fix(ci): resolve dependabot config conflict and run daily
- remove duplicate docker ecosystem entry with overlapping directory/target-branch
- switch cargo, github-actions, and docker schedules from monthly to daily
AnthropicProvider declared supports_native_tools() = true but did not
override chat_with_tools(). The default trait implementation drops all
conversation history (sends only system + last user message), breaking
multi-turn conversations on Telegram and other channels.
Changes:
- Override chat_with_tools() in AnthropicProvider: converts OpenAI-format
tool JSON to ToolSpec and delegates to chat() which preserves full
message history
- Skip build_tool_instructions() XML protocol when provider supports
native tools (saves ~12k chars in system prompt)
- Remove duplicate Tool Use Protocol section from build_system_prompt()
for native-tool providers
- Update Your Task section to encourage conversational follow-ups
instead of XML tool_call tags when using native tools
- Add tracing::warn for malformed tool definitions in chat_with_tools
Two fixes for conversation history quality:
1. Store raw msg.content in ConversationHistoryMap instead of
enriched_message — memory context is ephemeral per-request and
pollutes future turns when persisted.
2. Skip memory recall when conversation history exists — prior turns
already provide context. Memory recall adds noise and can mislead
the model (e.g. old 'seen' entries overshadowing a code variable
named seen in the current conversation).
After run_tool_call_loop, only the final text response was saved to
per-sender conversation history. All intermediate tool calls and results
were discarded, so on the next turn the LLM had no awareness of what
tools it used or what it discovered — causing poor follow-up ability.
Record the history length before the tool loop, then scan new messages
for tool names after it completes. Prepend a compact [Used tools: ...]
annotation to the assistant message saved in history, giving the LLM
context about its own actions on subsequent turns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, the memory-enriched message (with [Memory context] block
prepended) was saved to per-sender conversation history. On subsequent
turns the LLM saw stale memory fragments with raw keys baked into
prior "user" messages, creating compounding noise.
Save the original msg.content instead. Memory context is still injected
for the current LLM call but no longer persists across turns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every user message was auto-saved to memory regardless of length,
flooding the store with trivial entries like "ok", "thanks", "hi".
These noise entries competed with real memories during recall, degrading
relevance — especially with keyword-only search.
Skip auto-saving messages shorter than 20 characters. Applied to both
the channel path (channels/mod.rs) and CLI agent path (agent/loop_.rs).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
build_system_prompt() included a "## Tool Use Protocol" section with
the tag format and usage instructions. build_tool_instructions() then
appended another identical "## Tool Use Protocol" section with full
JSON schemas. This wasted ~1-2K tokens on every API call.
Remove the duplicate protocol block from build_system_prompt(), keeping
only the compact tool name/description list. The complete protocol with
schemas is provided by build_tool_instructions().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Channel Capabilities section in build_system_prompt() was hardcoded
to say "You are running as a Discord bot" for ALL channels, including
Telegram. This caused the LLM to misidentify itself and reference
Discord-specific features regardless of the actual channel.
Replace with generic "messaging bot" text. Per-channel delivery
instructions already exist via channel_delivery_instructions().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract hard-coded test vector keys into named constants in bedrock.rs
and linq.rs to resolve rust/hard-coded-cryptographic-value alerts
- Replace derived Debug impls with manual impls that redact sensitive
fields (access_token, refresh_token, credential, api_key) on
QwenOauthCredentials, QwenOauthProviderContext, and
ResolvedEmbeddingConfig to resolve rust/cleartext-logging alerts
- Redact Matrix user_id and device_id hints in tracing::warn! diagnostic
messages via crate::security::redact() to resolve cleartext-logging
alert in matrix.rs
Addresses CodeQL alerts: #77, #95-106
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>