When a Qwen/DashScope API key is rejected with a 401 InvalidApiKey error,
the user previously saw a raw SDK exception with no actionable guidance.
The most common cause is an endpoint/region mismatch: keys issued on the
China mainland portal (qwencloud.com) only work against the China endpoint
(dashscope.aliyuncs.com), while international keys require the international
endpoint (dashscope-intl.aliyuncs.com). A valid key paired with the wrong
endpoint produces a 401 that looks like the key itself is broken.
This adds authentication-failure detection to friendly_model_error() with
provider-specific messaging — Qwen models get guidance about the two
DashScope endpoints, other compat vendors get a generic key-check message.
The Qwen provider's endpoint_help text is also expanded to explicitly warn
about the region-key pairing before the user ever hits the error.
Fixes#231
The live skill menu is rebuilt every turn (agent.py calls rescan() while assembling
per-turn context), so every filesystem call in SkillLoader._discover sat on the hot
path unguarded. pathlib ignores ENOENT/ENOTDIR/EBADF/ELOOP but propagates EACCES,
so an unreadable <workspace>/.coworker/skills — an OPTIONAL dir, usually absent —
raised straight out of the turn and terminated the run.
Found while evaluating against benchmark datasets, where the agent runs headless as
an unprivileged user: a root-owned .coworker/ appeared in the workspace mid-session
and long runs died outright, several around 100 turns deep, after the work was
already done. At startup the dir does not exist, ENOENT is ignored and the session
begins normally, which is why it struck at arbitrary points rather than immediately.
_discover now degrades to "no skills here" on OSError, and guards each skill's parse
separately so one unreadable or malformed folder costs only that skill.
Also drop "permission denied" from the provider no-access markers. Every OS
PermissionError stringifies as "[Errno 13] Permission denied: <path>", so that
substring turned any unreadable file into "Your account doesn't have access to
<model>" — a billing failure that did not exist, and hours spent chasing a provider
outage that never happened. Anthropic's genuine marker is the underscored error type
permission_error, which was already listed and still matches.
Three regression tests; all three fail without these changes.
Imported from andrewyng/aisuite@1b4bbf303e
(contents of its platform/ directory, hoisted to the repo root).
Development history prior to this commit lives in that repository.
Co-authored-by: Devika <devikaverma11@gmail.com>