Root cause of #959: resolve_connected_account_ref returned None when the entity had more than one connected account for an app, silently dropping auto-resolve and causing every execute call to fail with 'cannot find connected account'. The LLM then looped re-issuing the OAuth URL even though the account was already connected.
- resolve_connected_account_ref now picks the first usable account (ordered by updated_at DESC from the API) instead of returning None when multiple accounts exist
- Add 'connected_accounts' as a dispatch alias for 'list_accounts' in handler, schema enum, and description
- 8 new regression tests
Closes#959
Add five new idempotency store tests covering: different-key acceptance,
max_keys clamping to minimum of 1, rapid duplicate rejection, TTL-based
key expiry and re-acceptance, and eviction preserving newest entries.
Addresses audit finding on weak gateway idempotency test coverage.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace bare .unwrap() calls with descriptive .expect() messages in
src/agent/agent.rs and src/tools/shell.rs test modules. Adds meaningful
failure context for memory creation, agent builder, and tool execution
assertions. Addresses audit finding on test assertion quality (§5.2).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds section markers and decision-point comments to the three most complex
control-flow modules. Comments explain loop invariants, retry/fallback
strategy, security policy precedence rules, and error handling rationale.
This improves maintainability by making the reasoning behind complex
branches explicit for reviewers and future contributors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Every public field in the Config struct hierarchy now has a /// doc comment
explaining its purpose, default value, and usage context. This ensures
operators and extension developers can understand config options directly
from rustdoc without cross-referencing the config reference documentation.
Comments are consistent with docs/config-reference.md descriptions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The four underdocumented core trait files now include trait-level doc blocks
explaining purpose and architecture role, method-level documentation with
parameter/return/error descriptions, and public struct/enum documentation.
This brings parity with the well-documented provider, channel, tool, and
memory traits, giving extension developers clear guidance for implementing
these core extension points.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The English README contains architecture overview (diagram + trait table),
subscription auth setup (OAuth flow + examples), and memory system design
(vector + FTS5 hybrid search) sections that were missing from the Chinese,
Japanese, and Russian translations.
This closes the content parity gap identified in the documentation audit,
ensuring non-English speakers have access to the same critical architectural
context and setup guidance.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Each major subsystem mod.rs now includes a //! doc block explaining the
subsystem purpose, trait-driven architecture, factory registration pattern,
and extension guidance. This improves the generated rustdoc experience for
developers navigating ZeroClaw's modular architecture.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds onboarding decision tree to getting-started/README.md so users can
quickly identify the right setup command for their situation.
Adds hardware vision overview to hardware/README.md explaining the
Peripheral trait and supported board types.
Expands project/README.md with scope explanation describing the purpose
of project snapshots and how they relate to documentation maintenance.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove merge conflict markers in .github/pull_request_template.md,
keeping the spaced module label format (\<module>: <component>\)
from the chore/labeler-spacing-trusted-tier branch.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The embedding provider factory only recognized "openai" and "custom:*",
causing "openrouter" to silently fall through to NoopEmbedding. This
made vector/semantic search completely non-functional — memory recall
fell back to BM25 keyword-only matching, with 70% of the hybrid score
always returning zero.
Route "openrouter" through OpenAiEmbedding with the OpenRouter API base
URL (https://openrouter.ai/api/v1), which is OpenAI-compatible.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a custom value_parser for the --temperature CLI argument to enforce
the documented 0.0-2.0 range at parse time. Previously, the comment
stated the valid range but clap did not reject out-of-range values,
allowing invalid temperatures to propagate to provider API calls.
- Add parse_temperature() validator that rejects values outside 0.0..=2.0
- Wire it into the Agent subcommand's temperature arg via value_parser
Addresses API surface audit §2.3 (CLI argument range validation).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Improve vague error messages in channel initialization and tool setup
to include specific config key paths and remediation steps, matching
the quality standard set by proxy validation errors.
Changes:
- telegram.rs: Include [channels.telegram] section path and required
fields (bot_token, allowed_users) in missing-config error; add
onboard hint; specify channels.telegram.allowed_users in pairing
message; improve parse error context
- whatsapp.rs: Specify channels.whatsapp.allowed_numbers key path
in unauthorized-number warning
- linq.rs: Specify channels.linq.allowed_senders key path in
unauthorized-sender warning; add onboard hint
- web_search_tool.rs: Include tools.web_search.provider config path
and valid values in unknown-provider error
Addresses API surface audit §8.2 (config context in error messages).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add Config::validate() called from load_or_init() after env overrides
are applied. This catches obviously invalid configuration values at
startup instead of allowing them to silently cause runtime failures.
Validated fields:
- gateway.host: must not be empty
- autonomy.max_actions_per_hour: must be > 0
- scheduler.max_concurrent: must be > 0
- scheduler.max_tasks: must be > 0
- model_routes[*]: hint, provider, model must not be empty
- embedding_routes[*]: hint, provider, model must not be empty
- proxy: delegates to existing ProxyConfig::validate()
Previously, ProxyConfig::validate() was only called during
apply_env_overrides() and only warned/disabled on failure. The new
Config::validate() runs it as a hard error after all overrides are
resolved, ensuring proxy misconfiguration is surfaced early.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use enum-backed channel menu dispatch to prevent duplicated match-arm indices and unreachable-pattern warnings (issue #913).
Also switch OpenAI native tool spec parsing to owned serde structs so tool-schema validation compiles.
Skill prompts and tool definitions from SKILL.toml were parsed and stored
correctly but never included in the agent's system prompt. Both prompt-building
paths (channels/mod.rs and agent/prompt.rs) only emitted skill metadata (name,
description, location), telling the LLM to "read" the SKILL.toml on demand.
This caused the agent to attempt manual file reads that often failed, leaving
skills effectively ignored.
Now both paths inline <instructions> and <tools> blocks inside each <skill>
XML element, so the agent receives full skill context without extra tool calls.
Closes#877
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>