- Add MediaCache using xxHash3-128 (with sha256 fallback) content-addressable storage
- Externalize message chain image payloads before recording monitoring and discarded messages
- Strip base64 payloads to null in SQLite monitoring_messages, dropping row size from megabytes to hundreds of bytes
- Add GET /api/v1/files/media/<filename> route with immutable HTTP cache headers to serve cached media
- Integrate age-based retention (default 30 days) and configurable disk quota with MaintenanceService cleanup loop
- Add defensive sanitizer in MonitoringService.record_message against oversized raw base64 payloads
- Add comprehensive unit tests and end-to-end verification covering CAS deduplication, route serving, and LRU pruning
* feat(packaging): add fnOS FPK packaging and CI workflow
Add packaging/fnos/ shell (manifest, lifecycle cmd scripts, install/
upgrade/uninstall wizards, desktop entry, EULA) plus in-repo build
script. A release now auto-builds langbot-<tag>-fnos.fpk via
.github/workflows/build-fnos-fpk.yaml, uploaded to the release assets.
* ci(fnos): skip release upload on manual dispatch
github.event.release.tag_name is empty when triggered via
workflow_dispatch, causing 'gh release upload' to fail with
'requires at least 2 arg(s)'. Restrict the step to release events.
* ci(fnos): normalize release asset name
Strip a trailing -fnos from the tag-derived version before appending
the suffix, avoiding langbot-<v>-fnos-fnos.fpk when the tag itself
already carries -fnos.
* ci(fnos): use release tag version for auto build, manifest for manual
Auto build (release/tag) reads version from tag like other release
workflows; build.sh strips the v prefix when injecting into manifest.
Manual dispatch falls back to the version maintained in manifest.
* feat(fnos): add post-install deployment notice to install wizard
Last wizard step now informs users that first startup takes about
5-10 minutes for dependency setup before the web UI is ready.
* docs(fnos): add packaging directory README
* refactor(fnos): rename app from ai.langbot to langbot
Rename appname, desktop entry, data share, build artifacts, and all
references from ai.langbot to langbot across packaging files.
---------
Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>
* feat(mcp): surface OAuth-required server tests
* fix(mcp): show connection failure details in status cards
---------
Co-authored-by: RockChinQ <rockchinq@gmail.com>
create_bot inserts the Bot row first and only then instantiates the
adapter via platform_mgr.load_bot. When the adapter constructor raises
(e.g. KeyError on a missing credential key), the insert is already
committed and nothing removes the row: the HTTP layer returns 500 but
a permanently disabled orphan bot stays in the DB. Callers never
receive the bot uuid, so they cannot compensate by deleting it, and
load_bots_from_db skips enable=False bots, so the orphan is never
loaded or surfaced anywhere.
Wrap load_bot in try/except and delete the inserted row before
re-raising. Add a regression test asserting the DELETE is issued when
the adapter constructor fails.
Since b55f073e the token field is optional in qqofficial.yaml ("the
current adapter implementation does not use it either, so it can be
safely left blank"), but the adapter constructor still reads it with
config['token']. Creating a bot via QR binding (which only returns
appid/secret) or with the token field left blank raises KeyError and
the API returns 500.
Read it with config.get('token', '') instead. The value is never used
by QQOfficialClient beyond being stored, so an empty string default is
safe.
WecomMessageConverter.yiri2target() always emits {'media_id': ...} for
image/voice/file parts (never 'media'), matching the correct usage
already in reply_message(). send_message(), the entry point plugins
use via PluginToRuntimeAction.SEND_MESSAGE, instead read
content['media'], which is never set, so any image/voice/file part
raises KeyError and aborts the send.
Refs #1687
Signed-off-by: Amir Fathi <amirfathi.me@gmail.com>
* fix(cloud): provision login workspace just in time
* fix(oauth): send callback URI during code exchange
* fix(oauth): preserve callback URI through browser exchange
* fix(oauth): negotiate redirect-bound codes
---------
Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>
* fix(cloud): launch new accounts through Space
* style: format Cloud entry URL
* fix(cloud): wait for launch workspace projection
---------
Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>