Add CachedCredentials with 50-minute TTL that transparently refreshes
from the ECS container credential endpoint, env vars, or EC2 IMDS.
- Add from_ecs() to credential resolve chain for ECS/Fargate support
- Move streaming credential fetch into async context for TTL validation
- Remove sync credential fallback (all paths now use TTL-aware cache)
- Double-checked locking prevents thundering herd on refresh
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Copilot API proxy for Claude models (Opus 4.6, Opus 4.6-1m) splits
text content and tool_calls into separate choices. Previously only
choices[0] was read, causing all tool calls to be silently dropped
when they appeared in choices[1].
Merge text and tool_calls from all choices so tool calling works
regardless of how the proxy splits the response.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wire QuotaMetadata into ChatResponse for all provider implementations,
enabling quota tracking data to flow from API responses through the
agent loop to quota monitoring tools.
Depends on: circuit breaker (#1842) + quota monitoring (#1904)
Made-with: Cursor
Add SiliconFlow provider factory support and alias/env handling.
Normalize onboarding UX to volcengine while preserving doubao/ark runtime aliases.
Add integration registry entries and provider resolution coverage tests.
Expand provider and command docs with setup and validation examples.
- report api_key_configured via provider credential resolution (env + overrides)\n- set agent.compact_context default to true for new configs\n- align docs and tests with the new default\n\nRefs: #1983\nRefs: #1984\nContext: #1358\n\nCo-authored-by: Argenis <144828210+theonlyhennygod@users.noreply.github.com>
Compute api_key_configured through provider credential resolution so env-variable credentials are reported correctly for scenarios and delegate agents.
Closes#1983
* feat(providers): implement Qwen OAuth quota tracking
Add static quota display for Qwen OAuth provider (portal.qwen.ai).
Qwen OAuth API does not return rate-limit headers, so this provides
a static quota indicator based on known OAuth free-tier limits.
Changes:
- Add QwenQuotaExtractor in quota_adapter.rs
- Parses rate-limit errors for retry backoff
- Registered for all Qwen aliases (qwen, qwen-code, dashscope, etc.)
- Add Qwen OAuth detection in quota_cli.rs
- Auto-detects ~/.qwen/oauth_creds.json
- Displays static quota: ?/1000 (unknown remaining, 1000/day total)
- Improve quota display formatting
- Shows "?/total" when only total limit is known
- Add comprehensive test report and testing scripts
- Full integration test report: docs/qwen-provider-test-report.md
- Model availability, context window, and latency tests
- Reusable test scripts in scripts/ directory
Test results:
- Available model: qwen3-coder-plus (verified)
- Context window: ~32K tokens
- Average latency: ~2.8s
- All 15 quota tests passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit fa91b6a170)
* docs: satisfy markdownlint spacing in qwen docs
---------
Co-authored-by: ZeroClaw Bot <zeroclaw_bot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
`supports_vision` is currently hardcoded per-provider. The same Ollama instance can run `llava` (vision) or
`codellama` (no vision), but the code fixes vision support at the provider level with no user override.
This adds a top-level `model_support_vision: Option<bool>` config key — tri-state:
- **Unset (default):** provider's built-in value, zero behavior change
- **`true`:** force vision on (e.g. Ollama + llava)
- **`false`:** force vision off
Follows the exact same pattern as `reasoning_enabled`. Override is applied at the wrapper layer (`ReliableProvider` /
`RouterProvider`) — no concrete provider code is touched.
## Changes
**Config surface:**
- Top-level `model_support_vision` field in `Config` struct with `#[serde(default)]`
- Env override: `ZEROCLAW_MODEL_SUPPORT_VISION` / `MODEL_SUPPORT_VISION`
**Provider wrappers (core logic):**
- `ReliableProvider`: `vision_override` field + `with_vision_override()` builder + `supports_vision()` override
- `RouterProvider`: same pattern
**Wiring (1-line each):**
- `ProviderRuntimeOptions` struct + factory functions
- 5 construction sites: `loop_.rs`, `channels/mod.rs`, `gateway/mod.rs`, `tools/mod.rs`, `onboard/wizard.rs`
**Docs (i18n parity):**
- `config-reference.md` — Core Keys table
- `providers-reference.md` — new "Ollama Vision Override" section
- Vietnamese sync: `docs/i18n/vi/` + `docs/vi/` (4 files)
## Non-goals
- Does not change any concrete provider implementation
- Does not auto-detect model vision capability
## Test plan
- [x] `cargo fmt --all -- --check`
- [x] `cargo clippy --all-targets -- -D warnings` (no new errors)
- [x] 5 new tests passing:
- `model_support_vision_deserializes` — TOML parse + default None
- `env_override_model_support_vision` — env var override + invalid value ignored
- `vision_override_forces_true` — ReliableProvider override
- `vision_override_forces_false` — ReliableProvider override
- `vision_override_none_defers_to_provider` — passthrough behavior
## Risk and Rollback
- **Risk:** Low. `None` default = zero behavior change for existing users.
- **Rollback:** Revert commit. Field is `#[serde(default)]` so old configs without it will deserialize fine.
(cherry picked from commit a1b8dee785)
The default trait implementation returned a single error chunk that the
SSE mapper silently converted to `data: [DONE]`, producing empty
streaming responses from the OpenAI-compatible endpoint. Mirror the
non-streaming chat_with_history pattern: extract system + last user
message and delegate to stream_chat_with_system, which all providers
already implement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add underscores to long numeric literals (1234567890 → 1_234_567_890)
- Allow cast_possible_truncation for rough token estimates
- Replace loop/match with while-let for event stream parsing
- Merge identical match arms for event types
- Add #[allow(clippy::cast_possible_truncation)] on test helper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>