Maintainer edit: keep the Mattermost adapter running under the gateway, fail closed when team filtering cannot verify the team, isolate new thread sessions immediately, and make buffered stream finalization retry-safe.
- Send pairing code response (not empty message) for denied DMs
- Resolve actual channel type in action events before permission check
- Use word-boundary regex in _is_mentioned to avoid partial matches
- Use safe_filename for download path sanitization
- Add tests: denied DM pairing, denied action event, is_mentioned boundary
- Attachments now only attached to first chunk when message is split
- Filename sanitized with Path(name).name to prevent path traversal
- Updated streaming tests to match buffer-and-post-at-end pattern
(iOS compatibility)
maintainer edit: cron is also a trigger source, so keep the new CLI-delivered source explicitly named as local trigger across backend, WebUI, docs, and tests.
After a gateway restart or websocket reconnect, the UI stays stuck in
processing state because reconnecting clients only replay running status
when a turn is active, never push idle when no turn is running.
Fix _hydrate_after_subscribe to always push goal_status (running with
started_at when turn is active, idle when no turn is running) so the
frontend can reset its processing indicator on reconnect.
Also fix cmd_stop reporting 'No active task to stop' when a task is
actually processing by draining the pending injection queue in addition
to cancelling active tasks. This prevents mid-turn injection deadlocks
and gives accurate task counts.
richText messages only kept rich_text_list items whose type was
"text", so bold/italic/inlineCode/pre segments were silently dropped;
a message made entirely of formatted segments produced empty content
and fell through to the "unsupported message type: richText" warning.
Now any item carrying text is kept (matching the SDK's own
get_text_list, which keys off the "text" field) and its type is mapped
to Markdown so the formatting survives into the agent's context.
Text and downloadCode within a rich-text item are handled
independently (the SDK treats them as separate via get_text_list /
get_image_list), so an item carrying both a caption and an attachment
no longer drops the file.
The shared httpx.AsyncClient was created without a timeout, so all
requests (including large file/image downloads) used httpx's 5s
default and hit ConnectTimeout/ReadTimeout on uploads. Set an explicit
httpx.Timeout (connect=10s, read/write=30s).
Adds regression tests for formatted-segment preservation, the
all-formatted no-drop case, the text+downloadCode item, and the client
timeout configuration.
Closes#4497
maintainer edit: Telegram Web cannot render sendRichMessage payloads, so keep the rich path available only for explicit opt-in instead of enabling it by default.
Replace the manual thread-based catalog refresh with an asyncio task and async HTTP catalog fetches so the Settings route stays within the async WebUI model.
WhatsApp can deliver a sender LID instead of a phone number. The channel
already learns the LID->phone mapping at runtime, but only after a message
that carries both values, so the first message from a contact can't be
resolved to a phone number.
Seed the mapping on startup from two sources:
- reverse mapping files the bridge persists in the auth directory
(lid-mapping-<lid>_reverse.json), resolved via get_runtime_subdir so it
respects a custom runtime dir
- a new optional channels.whatsapp.lidMappings config dict for static
mappings (takes precedence over the on-disk files)
Malformed/empty mapping files are ignored rather than failing startup.
Adds tests for both sources, precedence, malformed files and the
no-auth-dir case, plus docs for the new config field.
Maintainer edit: parse Feishu card table columns and rows so forwarded table cards do not fall back to [interactive], and add parser regression coverage.
maintainer edit: remove the Feishu-specific config-file guard from the shared CLI login command. Feishu now follows the Weixin pattern where channel.login owns its setup and persistence.
maintainer edit: fix the lint failure, report the active config path, fail fast when the registration response lacks a login URL, and cover the new Feishu login writeback path.
Bring the Keenable search provider in line with the established
multi-file provider pattern so it surfaces everywhere the others do:
- settings_api.py: register in the web-search provider options so it
appears in the WebUI settings dropdown (credential: api_key, optional).
- WebUI provider-brand: add keenable brand entry + brand test.
- docs/configuration.md: provider table row + config example.
- Harden _search_keenable: honor config.timeout and return explicit
messages on HTTP status errors (429 / other), matching peer providers.
- Add env-key and HTTP-error tests; add the websocket settings whitelist
assertion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feishu CardKit content updates can fail without raising, leaving a blank Generating card while the final streamed response skips normal send. Reopen streaming mode and retry once, close blank cards when the first update fails, and fall back to a regular card when final updates still fail.