issue #14: the "422" seen in the group was not from the DingTalk card API but
from the claude subprocess's model provider, echoed back as the reply.
Root cause:
- claudecode's spec pins --model claude-haiku-4-5-20251001 in both argvTail and
streamArgvTail.
- claudeUserSettingsEnv (issue #10) injects the user's ANTHROPIC_BASE_URL /
ANTHROPIC_AUTH_TOKEN into the claude subprocess. With a third-party provider
relay that has no mapping for that exact haiku pin, the provider returns
"API Error: 422 ...".
- execForwarder.forward used cmd.Output() and returned any non-empty stdout as
the answer without checking err, so the raw 422 text was forwarded to the chat
on every message.
Fix (A + B):
A. In forwarderForChannel, when a custom provider base URL is in effect
(injected via Claude settings or already in the process env) and the user did
not pick a model (--agent-model / DWS_AGENT_MODEL), strip the built-in model
pin so the provider's default model applies. Official-login users keep the
pin; an explicit --agent-model still wins.
B. In forward and forwardStream, treat stdout that starts with "API Error:"
(or a process error) as a failure: return a short, actionable Chinese hint
("...请用 --agent-model <model> 指定模型后重连.") instead of echoing the raw
backend error. Normal replies are unaffected.
Adds unit tests for the haiku-drop wiring, the API-Error guard, and the new
helpers.
Bring the official-channel reply experience (hermes/openclaw) to every
stream-bridge channel:
- "🤔Thinking" reaction chip on the user's message while the agent runs,
swapped to "🥳Done" when the reply lands — the hermes text-emotion contract
(POST /v1.0/robot/emotion/reply|recall, emotionId 2659900).
- AI-card reply using the openclaw connector's public template + payload
contract (msgContent + flowStatus state machine). Card templates are
app-scoped: hermes' own template renders "内容加载失败" for any other app —
confirmed by live A/B on the same robot.
- Live streaming into the card where the channel CLI supports it (verified
per CLI): claude/codebuddy stream-json text deltas (thinking deltas
filtered), qodercli stream-json per-turn snapshots; codex/gemini/opencode
stay one-shot. Frames are full-content and throttled at 800ms per card.
- --reply-card flag (default on, env DWS_REPLY_CARD=0) with full fallback
chain: any card failure → plain text/markdown webhook reply; stuck cards
are best-effort marked failed.
- Deliver responses are checked for business-level failures inside HTTP 200
({"result":[{"success":false,...}]} observed live), and every card API
response body is logged for operability.
- workbuddy persona now forbids tool use: headless codebuddy otherwise
stalls on permission gates trying to write memory files.
- Skill docs: reply-card flag, version-publish approver-selection workflow
(check-approval → present approver list to the user → publish --approver).
Known issue under investigation: after a batch of invalid-template test
cards, the reporting device renders all subsequent cards as "内容加载失败"
even though every API call succeeds and identical payloads rendered earlier
the same day — suspected client-side card/template cache poisoning; pending
verification on a second client.