feat(models): add provider model scanning (#2106)

* feat(models): add provider model scanning

* fix: double close button

* feat: update plugin module

* fix(monitoring): WeChat Work feedback recording bugs (#2108)

* fix(monitoring): fix WeChat Work feedback recording bugs

- Fix feedback events silently dropped when stream session expires:
  dispatch feedback handlers regardless of session availability
- Fix IntegrityError on repeated feedback (like→dislike) for same
  message: implement UPSERT logic in record_feedback()
- Fix cancel feedback (type=3) not removing records: add delete logic
- Fix inaccurate_reasons validation error: convert int reason codes
  to strings before creating FeedbackEvent (Pydantic expects List[str])
- Fix feedback timestamps 8 hours off in frontend: use parseUTCTimestamp
  instead of new Date() for UTC timestamp parsing
- Fix StreamSessionManager.cleanup missing _feedback_index cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(monitoring): apply ruff format to wecom feedback files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: 6mvp6 <13727783693@163.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add feat for receive files in wecombot

* fix: ruff error

* fix: always show sidebar plus buttons on touch/mobile devices (#2115)

Agent-Logs-Url: https://github.com/langbot-app/LangBot/sessions/e27a4886-fbad-4a7a-8558-67a387852753

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* fix: SPA fallback for all frontend routes, not just /home/*

After migrating from Next.js to Vite SPA, routes like /auth/space/callback
returned 404 because the static file server only had SPA fallback for /home/*.
Now all non-API routes fall back to index.html for React Router to handle.

* style: ruff format main.py

* feat: add marketplace link when no parser available for file upload

Links to /home/market?category=Parser, same pattern as knowledge engine selector.

* fix: lint error

* fix(user): allow password login and password change for Space accounts with local password set

Previously, Space accounts were unconditionally blocked from password login
and password change based on account_type. Now the check verifies whether
the user actually has a local password set, allowing Space users who have
set a local password to authenticate and change it normally.

* feat: add edition field to telemetry payload

Sends constants.edition (community/saas) with each telemetry event
so Space can distinguish between community and SaaS instances.

* style: ruff format telemetry.py

* fix(dingtalk): use voice recognition text instead of raw audio binary

When DingTalk sends a voice message to the bot, the callback JSON contains
a 'recognition' field with the speech-to-text result (powered by Qwen).

Previously, LangBot only extracted the 'downloadCode' to download the raw
audio binary and passed it as 'file_base64' to LLM APIs, which caused
400 errors since most models don't support this content type.

This patch:
- Extracts the 'recognition' field from DingTalk audio message content
- Uses it as plain text input to the LLM instead of raw audio
- Falls back to audio binary only when no recognition text is available
- Fixes duplicate text issue for audio messages with recognition

Fixes voice messages returning 'Request failed' on all LLM models.

* feat: integrate Alembic for database migrations

Replace manual if-sqlite/if-postgres branching with Alembic:
- Add alembic dependency
- Create programmatic alembic env (no CLI/alembic.ini needed)
- Support async engines via run_sync passthrough
- render_as_batch=True for SQLite ALTER TABLE compatibility
- Auto-stamp baseline on first run (existing DB at version 25)
- Run alembic upgrade head after legacy migrations
- Include sample migration showing schema + data migration patterns
- Add alembic dir to package-data for distribution

* ci: add migration test workflow for SQLite and PostgreSQL

Tests alembic upgrade on both databases:
- Stamp baseline on existing schema
- Upgrade to head
- Idempotent re-upgrade
- Fresh DB upgrade from scratch

* feat: add autogenerate support and CLI entrypoint for alembic

- autogenerate: compare ORM models vs DB schema to generate migrations
- CLI: python -m langbot.pkg.persistence.alembic_runner <command>
  - autogenerate, upgrade, stamp, current
- Reads data/config.yaml for DB connection

* fix: add filereader for dingtalk,lark (#2122)

* fix: add filereader for dingtalk

* feat: add lark

* feat: update uv.lock

* chore: update version to 4.9.6 in pyproject.toml, __init__.py, and uv.lock

* fix: update langbot-plugin version to 0.3.8

* fix: update langbot-plugin version to 0.3.8

* docs: update database migration instructions in AGENTS.md

* fix(dashscopeapi): fix null value check in reasoning content processing logic (#2128)

* fix(n8n-runner): fix output_key not applied when n8n returns plain JSON (#2119)

* fix: bump dependencies to resolve Dependabot security alerts (#2130)

* fix: bump dependencies to resolve Dependabot security alerts

Python:
- aiohttp: >=3.11.18 → >=3.13.4 (duplicate Host headers, header injection, redirect leak, multipart DoS)
- cryptography: >=44.0.3 → >=46.0.7 (buffer overflow with non-contiguous buffers)
- pillow: >=11.2.1 → >=12.2.0 (FITS GZIP decompression bomb, HIGH)
- langchain-text-splitters: >=0.0.1 → >=1.1.2 (SSRF redirect bypass)
- langchain-core: add >=1.2.28 (incomplete f-string validation)
- langsmith: add >=0.7.31 (streaming token redaction bypass)
- python-multipart: add >=0.0.26 (multipart DoS)
- Mako: add >=1.3.11 (path traversal)
- pytest: >=8.4.1 → >=9.0.3 (tmpdir handling)
- uv: >=0.7.11 → >=0.11.6 (arbitrary file deletion)

JavaScript (web/):
- vite: ^8.0.3 → ^8.0.5 (fs.deny bypass, WebSocket file read, path traversal, HIGH)
- axios: ^1.13.5 → ^1.15.0 (cloud metadata exfiltration)
- lodash: ^4.17.23 → ^4.18.0 (code injection via _.template, prototype pollution, HIGH)

* fix: update pnpm-lock.yaml for bumped dependencies

* feat(ci): add i18n key consistency check for frontend locales (#2133)

* feat(ci): add i18n key consistency check workflow

Agent-Logs-Url: https://github.com/langbot-app/LangBot/sessions/c7bf50da-189b-49a5-9671-dbe8e70ff9d0

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* feat(ci): replace eval with line-by-line parser, add permissions block

Agent-Logs-Url: https://github.com/langbot-app/LangBot/sessions/c7bf50da-189b-49a5-9671-dbe8e70ff9d0

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* feat(models): add provider model scanning

* feat(models): add 'select all' functionality and enrich model abilities

* fix:ruff

* fix:ruff

---------

Co-authored-by: WangCham <651122857@qq.com>
Co-authored-by: 6mvp6 <119733319+6mvp6@users.noreply.github.com>
Co-authored-by: 6mvp6 <13727783693@163.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Guanchao Wang <wangcham233@gmail.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
Co-authored-by: RockChinQ <rockchinq@gmail.com>
Co-authored-by: haiyangbg <zhouhaiyangaa@gmail.com>
Co-authored-by: Rock Chin <1010553892@qq.com>
Co-authored-by: Amadeus <115918672+AmadeusKurisu1@users.noreply.github.com>
Co-authored-by: hzhhong <hung.z.h916@gmail.com>
Co-authored-by: fdc310 <2213070223@qq.com>
This commit is contained in:
sheetung
2026-04-19 17:47:07 +08:00
committed by GitHub
parent 05c684d757
commit 4e5a6ee79a
23 changed files with 1213 additions and 115 deletions

View File

@@ -181,6 +181,10 @@ const enUS = {
mustBeValidNumber: 'Must be a valid number',
mustBeTrueOrFalse: 'Must be true or false',
requestURL: 'Request URL',
scanURL: 'Scan Models URL',
scanURLPlaceholder: 'Leave empty to use Request URL + /models',
scanURLDescription:
'Fill in the actual model-list endpoint when model scanning does not use the same address as model invocation.',
apiKey: 'API Key',
abilities: 'Abilities',
selectModelAbilities: 'Select model abilities',
@@ -218,6 +222,20 @@ const enUS = {
providerCount: '{{count}} providers',
// New keys for provider-based structure
addModel: 'Add Model',
manualAdd: 'Manual',
scanAdd: 'Scan',
scanModels: 'Scan Models',
scanModelsHint:
'Read available models from the current provider, then select which ones to add.',
scannedModels: 'Scanned Models',
scanDebug: 'Debug Info',
searchScannedModels: 'Search scanned models',
noScannedModels: 'No scan results yet. Click the button above to scan.',
noScannedModelsMatch: 'No matching models',
addSelectedModels: 'Add Selected',
addSelectedModelsSuccess: '{{count}} model(s) added',
selectAll: 'Select All',
alreadyAdded: 'Already added',
addLLMModel: 'Add LLM Model',
addEmbeddingModel: 'Add Embedding Model',
provider: 'Provider',

View File

@@ -227,6 +227,20 @@ const esES = {
providerCount: '{{count}} proveedores',
// New keys for provider-based structure
addModel: 'Añadir modelo',
manualAdd: 'Manual',
scanAdd: 'Escanear',
scanModels: 'Escanear modelos',
scanModelsHint:
'Lee los modelos disponibles del proveedor actual y luego elige cuáles agregar.',
scannedModels: 'Modelos detectados',
searchScannedModels: 'Buscar modelos detectados',
noScannedModels:
'Todavía no hay resultados. Pulsa el botón superior para escanear.',
noScannedModelsMatch: 'No hay modelos coincidentes',
addSelectedModels: 'Agregar seleccionados',
addSelectedModelsSuccess: 'Se agregaron {{count}} modelo(s)',
selectAll: 'Seleccionar todo',
alreadyAdded: 'Ya agregado',
addLLMModel: 'Añadir modelo LLM',
addEmbeddingModel: 'Añadir modelo Embedding',
provider: 'Proveedor',

View File

@@ -221,6 +221,20 @@
'ローカルモデルがありません。作成ボタンをクリックしてモデルを追加してください。',
providerCount: '{{count}} 件のプロバイダー',
addModel: 'モデルを追加',
manualAdd: '手動追加',
scanAdd: 'スキャン追加',
scanModels: 'モデルをスキャン',
scanModelsHint:
'現在のプロバイダーから利用可能なモデルを取得し、追加するモデルを選択します。',
scannedModels: 'スキャン結果',
searchScannedModels: 'スキャン結果を検索',
noScannedModels:
'まだスキャン結果がありません。上のボタンからスキャンしてください。',
noScannedModelsMatch: '一致するモデルがありません',
addSelectedModels: '選択したモデルを追加',
addSelectedModelsSuccess: '{{count}} 件のモデルを追加しました',
selectAll: 'すべて選択',
alreadyAdded: '追加済み',
addLLMModel: 'LLMモデルを追加',
addEmbeddingModel: '埋め込みモデルを追加',
provider: 'プロバイダー',

View File

@@ -215,6 +215,19 @@ const thTH = {
noLocalModels: 'ไม่มีโมเดลท้องถิ่น คลิกสร้างเพื่อเพิ่มโมเดล',
providerCount: '{{count}} ผู้ให้บริการ',
addModel: 'เพิ่มโมเดล',
manualAdd: 'เพิ่มเอง',
scanAdd: 'สแกน',
scanModels: 'สแกนโมเดล',
scanModelsHint:
'ดึงรายการโมเดลที่ใช้ได้จากผู้ให้บริการปัจจุบัน แล้วเลือกโมเดลที่ต้องการเพิ่ม',
scannedModels: 'ผลการสแกน',
searchScannedModels: 'ค้นหาผลการสแกน',
noScannedModels: 'ยังไม่มีผลการสแกน กดปุ่มด้านบนเพื่อเริ่มสแกน',
noScannedModelsMatch: 'ไม่พบโมเดลที่ตรงกัน',
addSelectedModels: 'เพิ่มที่เลือก',
addSelectedModelsSuccess: 'เพิ่มแล้ว {{count}} โมเดล',
selectAll: 'เลือกทั้งหมด',
alreadyAdded: 'เพิ่มแล้ว',
addLLMModel: 'เพิ่มโมเดล LLM',
addEmbeddingModel: 'เพิ่มโมเดล Embedding',
provider: 'ผู้ให้บริการ',

View File

@@ -222,6 +222,19 @@ const viVN = {
noLocalModels: 'Không có mô hình cục bộ. Nhấn Tạo để thêm mô hình.',
providerCount: '{{count}} nhà cung cấp',
addModel: 'Thêm mô hình',
manualAdd: 'Thủ công',
scanAdd: 'Quét',
scanModels: 'Quét mô hình',
scanModelsHint:
'Đọc danh sách mô hình khả dụng từ nhà cung cấp hiện tại rồi chọn mô hình cần thêm.',
scannedModels: 'Kết quả quét',
searchScannedModels: 'Tìm trong kết quả quét',
noScannedModels: 'Chưa có kết quả quét. Nhấn nút phía trên để bắt đầu.',
noScannedModelsMatch: 'Không có mô hình phù hợp',
addSelectedModels: 'Thêm mục đã chọn',
addSelectedModelsSuccess: 'Đã thêm {{count}} mô hình',
selectAll: 'Chọn tất cả',
alreadyAdded: 'Đã thêm',
addLLMModel: 'Thêm mô hình LLM',
addEmbeddingModel: 'Thêm mô hình Embedding',
provider: 'Nhà cung cấp',

View File

@@ -173,6 +173,10 @@ const zhHans = {
mustBeValidNumber: '必须是有效的数字',
mustBeTrueOrFalse: '必须是 true 或 false',
requestURL: '请求URL',
scanURL: '扫描模型地址',
scanURLPlaceholder: '留空则默认使用请求URL + /models',
scanURLDescription:
'当模型扫描接口与模型调用接口不是同一个地址时,在这里填写实际的模型列表接口。',
apiKey: 'API Key',
abilities: '能力',
selectModelAbilities: '选择模型能力',
@@ -209,6 +213,19 @@ const zhHans = {
providerCount: '共 {{count}} 个自定义供应商',
// 供应商结构新增键
addModel: '添加模型',
manualAdd: '手动添加',
scanAdd: '扫描添加',
scanModels: '扫描模型',
scanModelsHint: '从当前供应商接口读取可用模型,然后勾选要添加的模型。',
scannedModels: '扫描结果',
scanDebug: '调试信息',
searchScannedModels: '搜索扫描结果',
noScannedModels: '还没有扫描结果,点击上方按钮开始扫描。',
noScannedModelsMatch: '没有匹配的模型',
addSelectedModels: '添加所选模型',
addSelectedModelsSuccess: '已添加 {{count}} 个模型',
selectAll: '全选模型',
alreadyAdded: '已添加',
addLLMModel: '添加对话模型',
addEmbeddingModel: '添加嵌入模型',
provider: '供应商',

View File

@@ -208,6 +208,18 @@ const zhHant = {
noLocalModels: '暫無本地模型。點擊建立按鈕新增模型。',
providerCount: '共 {{count}} 個供應商',
addModel: '新增模型',
manualAdd: '手動添加',
scanAdd: '掃描添加',
scanModels: '掃描模型',
scanModelsHint: '從目前供應商介面讀取可用模型,然後勾選要添加的模型。',
scannedModels: '掃描結果',
searchScannedModels: '搜尋掃描結果',
noScannedModels: '尚無掃描結果,點擊上方按鈕開始掃描。',
noScannedModelsMatch: '沒有符合的模型',
addSelectedModels: '添加所選模型',
addSelectedModelsSuccess: '已添加 {{count}} 個模型',
selectAll: '全選模型',
alreadyAdded: '已添加',
addLLMModel: '新增對話模型',
addEmbeddingModel: '新增嵌入模型',
provider: '供應商',