- Add field to ProviderSpec (default True)
- Add and methods in LiteLLMProvider
- Filter image_url content blocks in before sending to non-vision models
- Reverts session-layer filtering from original PR (wrong layer)
This fixes the issue where switching from Claude (vision-capable) to
non-vision models (e.g., Baidu Qianfan) causes API errors due to
unsupported image_url content blocks.
The provider layer is the correct place for this filtering because:
1. It has access to model/provider capabilities
2. It only affects non-vision models
3. It preserves session layer purity (storage should not know about model capabilities)
Feishu downloads images with incorrect extensions (e.g. .jpg for PNG files).
mimetypes.guess_type() relies on the file extension, causing a MIME mismatch
that Anthropic rejects with 'image was specified using image/jpeg but appears
to be image/png'.
Fix: read the first bytes of the image data and detect the real MIME type via
magic bytes (PNG: 0x89PNG, JPEG: 0xFFD8FF, GIF: GIF87a/GIF89a, WEBP: RIFF+WEBP).
Fall back to mimetypes.guess_type() only when magic bytes are inconclusive.
Commit 0209ad5 moved `import lark_oapi as lark` inside the start()
method (lazy import) to suppress DeprecationWarnings. This had an
unintended side effect: the import now happens after the main asyncio
loop is already running, so lark_oapi's module-level
loop = asyncio.get_event_loop()
captures the running main loop. When the WebSocket thread then calls
loop.run_until_complete() inside Client.start(), Python raises:
RuntimeError: This event loop is already running
and the _connect/_disconnect coroutines are never awaited.
Fix: in run_ws(), create a fresh event loop with asyncio.new_event_loop(),
set it as the thread's current loop, and patch lark_oapi.ws.client.loop
to point to this dedicated loop before calling Client.start(). The loop
is closed on thread exit.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Part 1: Make system prompt static
- Move Current Time from system prompt to user message prefix
- System prompt now only changes when config/skills change, not every minute
- Timestamp injected as [YYYY-MM-DD HH:MM (Day) (TZ)] prefix on each user message
Part 2: Add second cache_control breakpoint
- Existing: system message breakpoint (caches static system prompt)
- New: second-to-last message breakpoint (caches conversation history prefix)
- Refactored _apply_cache_control with shared _mark() helper
Before: 0% cache hit rate (system prompt changed every minute)
After: ~90% savings on cached input tokens for multi-turn conversations
Closes#981
- cancel_by_session: use asyncio.gather for parallel cancellation
instead of sequential await per task
- _dispatch: register in _active_tasks before acquiring lock so /stop
can find queued tasks (synced from #1179)
- SubagentManager tracks _session_tasks: session_key -> {task_id, ...}
- cancel_by_session() cancels all subagents for a session
- SpawnTool passes session_key through to SubagentManager
- /stop response reports subagent cancellation count
- Cleanup callback removes from both _running_tasks and _session_tasks
Builds on #1179
- Add commands.py with CommandDef registry, parse_command(), get_help_text()
- Refactor run() to dispatch messages as asyncio tasks (non-blocking)
- /stop is an 'immediate' command: handled inline, cancels active task
- Global processing lock serializes message handling (safe for shared state)
- _pending_tasks set prevents GC of dispatched tasks before lock acquisition
- _dispatch() registers/clears active tasks, catches CancelledError gracefully
- /help now auto-generated from COMMANDS registry
Closes#849
- Defer Brave API key resolution to execute() time instead of __init__,
so env var or config changes take effect without gateway restart
- Improve error message to reference actual config path
(tools.web.search.apiKey) instead of only mentioning env var
Fixes#1069 (issues 1 and 2 of 3)
- Add content extraction for share cards (chat, user, calendar event)
- Add recursive parsing for interactive card elements
- Fix image download API to use GetMessageResourceRequest with message_id
- Handle BytesIO response from message resource API
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add download functionality for multimedia messages in Feishu channel,
enabling agents to process images, audio recordings, and file attachments
sent through Feishu.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>