- Add the _extract_dify_text_output method to uniformly handle the parsing of Dify output content
- Modify the content extraction method for the answer node in workflow mode
- Add workflow mode detection logic to support the workflow_started event
- Handle error state checks upon completion of the workflow
- Improve the message chunking logic for both basic and workflow modes
- Add a mechanism to capture answer content upon completion of a workflow node
* feat(telegram): enhance message handling with markdown support and draft messages
* fix(telegram): update draft message ID generation to use current timestamp
Fixes#2014
When using default local storage, the s3storage module was imported
at the top level, which triggered boto3/botocore import and caused
ModuleNotFoundError if those packages weren't installed.
Now s3storage is only imported when S3 storage is actually configured.
* perf: reduce memory usage by ~200MB+ at startup
Two key optimizations:
1. Use importlib.util.find_spec() instead of __import__() in dependency
checking. find_spec() only locates modules without executing them,
avoiding loading all 36 dependencies (~222MB) into memory at startup.
2. Introduce shared aiohttp.ClientSession via httpclient module.
Previously, every HTTP request created a new ClientSession, which
creates a new TCPConnector and SSL context, loading system root
certificates each time (~270MB total allocations observed via memray).
Now all HTTP client code reuses shared sessions.
- satori.py and coze_server_api/client.py are left unchanged as they
create one session per adapter lifecycle (not per-request).
Profiling data (memray):
- Peak memory: 403MB
- SSL context creation: 270MB / 6.7M allocations (67% of total)
- Dependency import: 222MB (55% of peak)
- Expected reduction: 150-350MB at startup
* fix: remove unused aiohttp imports (ruff F401)
* style: ruff format
* feat: add in-product survey system
- SurveyManager: event-based trigger, Space API communication
- Trigger on first successful non-WebSocket response
- Backend API: /api/v1/survey/{pending,respond,dismiss}
- Frontend: floating survey widget with progressive questions
- Flat radio/checkbox style (not dropdown Select)
* fix: persist triggered survey events to disk across restarts
Store triggered events in data/survey_triggered_events.json so that
restarting the process doesn't re-query Space for already-triggered events.
* fix: use metadata table for survey event persistence instead of file
Store triggered events in the existing metadata KV table
(key='survey_triggered_events') instead of a standalone JSON file.
* fix: ruff format and prettier fixes
* feat: add session message monitoring tab to bot detail dialog
Add a new "Sessions" tab in the bot detail dialog that displays
sent & received messages grouped by sessions. Users can select
any session to view its messages in a chat-bubble style layout.
Backend changes:
- Add sessionId filter to monitoring messages endpoint
- Add role column to MonitoringMessage (user/assistant)
- Record bot responses in monitoring via record_query_response()
- Add DB migration (dbm019) for the new role column
Frontend changes:
- New BotSessionMonitor component with session list + message viewer
- Add Sessions sidebar tab to BotDetailDialog
- Add getBotSessions/getSessionMessages API methods to BackendClient
- Add i18n translations (en-US, zh-Hans, zh-Hant, ja-JP)
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
* refactor: remove outdated version comment from PipelineManager class
* fix: bump required_database_version to 19 to trigger monitoring_messages.role migration
* fix: prevent session message auto-scroll from pushing dialog content out of view
Replace scrollIntoView (which scrolls all ancestor containers) with
direct scrollTop manipulation on the ScrollArea viewport. This keeps
the scroll contained within the messages panel only.
* ui: redesign BotSessionMonitor with polished chat UI
- Wider session list (w-72) with avatar circles and cleaner layout
- Richer chat header with avatar, platform info, and active indicator
- User messages now use blue-500 (solid) instead of blue-100 for
clear visual distinction
- Metadata (time, runner) shown on hover below bubbles, not inside
- Proper empty state illustrations for both panels
- Better spacing, rounded corners, and shadow treatment
- Consistent dark mode styling
* fix: infinite re-render loop in DynamicFormComponent
The useEffect depended on onSubmit which was a new closure every
parent render. Calling onSubmit inside the effect triggered parent
state update → re-render → new onSubmit ref → effect re-runs → loop.
Fix: use useRef to hold a stable reference to onSubmit, removing it
from the useEffect dependency array.
Also add DialogDescription to BotDetailDialog to suppress Radix
aria-describedby warning.
* fix: remove .html suffix from docs.langbot.app links (Mintlify migration)
* style: fix prettier and ruff formatting
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
* feat(platform): add Forward message support for aiocqhttp adapter
- Add _send_forward_message method to send merged forward cards via OneBot API
- Support NapCat's send_forward_msg API with fallback to send_group_forward_msg
- Fix MessageChain deserialization for Forward messages in handler.py
- Properly deserialize nested ForwardMessageNode.message_chain to preserve data
This enables plugins to send QQ merged forward cards through the standard
LangBot send_message API using the Forward message component.
* style: fix ruff lint and format issues
- Remove f-string prefix from log message without placeholders
- Apply ruff format to aiocqhttp.py and handler.py
* refactor: remove custom deserializer, rely on SDK for Forward deserialization
- Remove _deserialize_message_chain from handler.py; use standard
MessageChain.model_validate() (Forward handling fixed in SDK via
langbot-app/langbot-plugin-sdk#38)
- Fix group_id type: use int instead of str for OneBot compatibility
- Add warning log when Forward message is used with non-group target
* chore: bump langbot-plugin to 0.2.7 (Forward deserialization fix)
---------
Co-authored-by: RockChinQ <rockchinq@gmail.com>
* fix: Add the file upload function and optimize the media message processing
* fix: Optimize the message processing logic, improve the concatenation of text elements and the sending of media messages
* fix: Simplify the file request construction and message processing logic to enhance code readability
- Added checks for maximum allowed extensions, bots, and pipelines in the backend services (PluginsRouterGroup, BotService, MCPService, PipelineService).
- Updated system configuration to include limitation settings for max_bots, max_pipelines, and max_extensions.
- Enhanced frontend components to handle limitations, providing user feedback when limits are reached.
- Added internationalization support for limitation messages in English, Japanese, Simplified Chinese, and Traditional Chinese.
* feat: add card auto layout configuration for DingTalk adapter
* fix: correct card auto layout configuration key and improve related logic
* fix: simplify card auto layout configuration logic in create_and_card method
* fix: correct card auto layout key in DingTalk migration configuration
* fix: correct migration class name for DingTalk card auto layout
* fix: update migration version for DingTalk card auto layout
* fix: correct key name for card auto layout in DingTalk configuration
* fix: improve formatting and consistency in DingTalk card auto layout methods
- Updated create_llm_model method to include auto_set_to_default_pipeline parameter.
- Adjusted ModelManager to set auto_set_to_default_pipeline to False when creating models.
- Improved logic for setting the default pipeline model based on the new parameter.
* feat: add emoji support to knowledge bases and pipelines
* feat: add optional emoji property to ExternalKBCardVO for enhanced knowledge base representation
* feat: add GitHub Actions workflow for linting with Ruff
* refactor: rename lint job and add formatting step to Ruff workflow
* chore: run ruff format
* chore: rename Ruff lint job to 'Lint' and add frontend linting workflow