Skip to content

v1.7.2-beta.1

Pre-release
Pre-release

Choose a tag to compare

@inureyes inureyes released this 09 May 06:18

API-driven capability detection for remote provider models — five-level pipeline with SQLite cache and live row-by-row UI updates, plus override dialog, markdown table repair, and Community card translations.

Backend.AI GO v1.7.2-beta.1

12 commits since v1.7.1. (11971 lines added, 343 lines deleted)

New Features

  • API-driven capability detection for remote provider models . Two-tier capability schema (provider-level + per-model) replaces the pure name-string heuristic with a five-level pipeline: ManualOverride > ProviderTable > ExtendedMetadata > EndpointInheritance > NameHeuristic. Backend (src-tauri/src/providers/capabilities/) ships with types, prober, metadata parser, detector, name-heuristic Rust port, hardcoded provider tables for OpenAI / Anthropic / Gemini, and a SQLite-backed cache with 7-day TTL plus manual-override survival. Eight service functions exposed as both Tauri commands AND REST handlers; both transports call the same internal providers::capabilities::* function per .claude/rules/api-parity.md. End-to-end event streaming (provider:capabilities-started, provider:capabilities-progress, provider:capabilities-updated, provider:capabilities-failed) wired through useProviderListeners so per-model rows upgrade row-by-row as detection completes. Concurrency cap 8, per-model timeout 2 s, redirect cap 1, partial-failure tolerated.
  • Capability override UI . New CapabilityOverrideDialog common component with Inputs / Outputs / Features tabs rendered as ToggleSwitch rows seeded from the current ModelCapabilityRecord. "Save" calls providersStore.setCapabilityOverride; "Reset to detected" calls clearCapabilityOverride; both show inline error feedback on rejection. Per-row "Re-detect" and "Override" action buttons in RemoteModelCard surface in an on-hover toolbar. ModelCapabilityChips badge tooltips now show the localized detected_via pipeline chain and confidence level.
  • Auto-download of model-metadata.yaml with continuum-router . The router needs a version-matched metadata file at runtime, but it lives in the lablup/continuum-router repo (not as a release asset) and was previously hand-committed. scripts/download-continuum-router.sh now fetches model-metadata.yaml from the matching tag via gh api -H "Accept: application/vnd.github.v3.raw", once per invocation regardless of how many platforms are requested; empty and JSON-error responses are detected before the file is moved into place. The bundled model-metadata.yaml is synced to v1.6.1, picking up gpt-image-2, the retrieval/embedding capability split, and other entries the bundled copy was missing.
  • Markdown table repair preprocessor . New repairMarkdownTables utility in src/lib/markdownTableRepair.ts and integration into MarkdownContent rendering. Repairs three malformed GFM table patterns produced by local LLMs before they reach react-markdown: delimiter-row pollution (e.g., | :---ed || :--- |), empty delimiter cells filled with ---, and list-marker contamination (e.g., * | body || body |). Idempotent on valid input, code-fence-aware (backtick fences preserved), streaming-safe (incomplete table windows untouched), with a no-pipe early-exit fast path. 34 fixture-anchored unit tests plus four integration tests rendering the real <ReactMarkdown> tree.
  • Additive translations map on RegistryProfileEntry . With a slim RegistryProfileTranslation carrying optional name / description overlays, #[serde(default, skip_serializing_if = "HashMap::is_empty")] so older registry indices and cache files keep parsing unchanged. Documented in docs/en/cowork/profiles.md and docs/ko/cowork/profiles.md.
  • Release statistics tracking script for measuring change scope across releases.

Improvements

  • All capability consumers migrated to prefer ModelCapabilityRecord . Every consumer of isImageGenerationModel, getImageEditCapabilities, getImageModelType, supportsVision, getModelImageParamCapabilities, and supportsImageRefinement now forwards the providers' ModelCapabilityRecord so the API-driven detection wins over the legacy name heuristic when present, and falls back to the heuristic when no record exists yet. New helpers: useCapabilityRecordByModelId (React) and getCapabilityRecordByModelId (snapshot); both walk providers in lexicographic order so the winner for a modelId collision is stable across sessions. makeRecordFinder extracted from providersStore so the five inline findRecord copies share the same deterministic-order logic. Migrated 18 files across components, hooks, stores, lib, and pages.
  • Capability detection i18n parity across ja, zh-CN, zh-TW, and es . 27 missing keys under models.capabilities.* (top-level labels, detection.*, actions.*, dialog.*) mirrored from the canonical en/ko locales. Chinese variants aligned with surrounding term conventions: zh-CN providerTable (提供方表 → 供应商表) and zh-TW providerTable (提供者表 → 供應商表) match the existing models.* keys; zh-TW imageVariation (圖像變化 → 圖像變體) matches the existing image-variation cluster.

Bug Fixes

  • Community tab agent cards now use translations and preserve raw categories . CommunityProfileCard resolves displayName / displayDescription through getTranslatedName / getTranslatedDescription, matching AgentProfileCard. The category badge no longer collapses every unknown category to "Custom" — known enum values still translate via the locale catalog, free-form community categories ("general", "writing-tools", ...) are humanised to Title Case, and empty categories render no badge. 18 unit tests cover humanizeCategory behavior.
  • Summarization prompt no longer injects the Qwen3-specific /no_think control token . The literal /no_think\n prefix in SUMMARIZE_INSTRUCTIONS is a Qwen3-only control token; other model families (Llama, Mistral, Gemma, Phi, GPT, Claude, Gemini) interpret it as literal user input, corrupting the summarization prompt and occasionally leaking the token into generated summaries. Sibling fix to which patched the same issue in title generation. Regression test asserts no message in the LLM payload contains /no_think for any model id.
  • Stable provider winner for modelId collisions (, HIGH from review of). useCapabilityRecordByModelId and getCapabilityRecordByModelId walk providers in lexicographic order so the winner for a modelId collision is stable across sessions. Without sorting, the winner depended on Map insertion order driven by network completion order, and a different provider could win each time.
  • Cross-firing button events fixed in RemoteModelCard . <article> keyDown handler is now restricted to its own target so Enter/Space on the row's Re-detect / Override buttons no longer cross-fires onToggle. Redetect spinner timer tracked with useRef + useEffect cleanup so it is cancelled when the card unmounts. Destructured useProvidersStore in CapabilityOverrideDialog replaced with stable per-action selectors so background capability-detection events do not re-render the dialog on every store mutation.
  • Capability detection routes added to ROUTE_MANIFEST (, HIGH security). route_scope_middleware now enforces the same scope gate as PUT /providers/{id} and friends — without the manifest entries, the fallback "pass-through" let any authenticated identity call them regardless of scope.
  • Name-heuristic regexes cached in OnceLock (, HIGH perf). name_heuristic::detect previously rebuilt the dall-?e[-_]?3 and nano[-_]?banana[-_]?pro regexes on every call; with ~50 models per provider per refresh, the per-call compile became a measurable hot path. Both are now cached alongside the rest of the heuristics.
  • Capability probe HTTP redirect cap reduced from 10 to 1 . For endpoint reachability discovery we never need to follow more than one redirect; treating the redirect target as the answer prevents a malicious provider URL from chaining redirects to amplify probe latency up to the per-request 2 s timeout.
  • Provider capability cache hardening (post-merge follow-up to /). Preserves seeded provider endpoint flags on indeterminate probe outcomes so transient timeout/5xx responses do not erase known-good cache state. Uses HashSet membership when pruning orphan capability rows to avoid quadratic scans on large provider model lists. The eight provider capability Tauri/REST mappings added to the API parity manifest; cli.rs added to the security handler-scope baseline with a route-scope-middleware note.

CI/CD Improvements

  • None

Technical Details

  • Hot path optimization: deterministic provider ordering for capability lookups, cached regex compilation, per-call HashSet membership for orphan-row pruning.
  • Event lifecycle: service::detect_provider_with_models_emitting extends to take an optional runtime-agnostic Arc<dyn EventEmitter> and emits events at four points: started at the very beginning, capabilities-updated for the provider record after server-endpoint detection, capabilities-updated again for each model as its JoinSet task completes (replacing the prior monolithic for handle in handles join loop), and progress after every model.
  • Lifecycle parity: providers/lifecycle.rs extracts trigger_initial_capability_detection (background spawn), invalidate_capabilities_for_change (manual overrides preserved), and cascade_capability_delete so both Tauri and REST paths share the same code rather than duplicating cache lifecycle handling.
  • Test coverage: 42 unit tests + DTO validation tests for capabilities, 19 component tests for CapabilityOverrideDialog, 13 store tests for providersStore event handlers, 7 tests for useProviderListeners lifecycle, 16 contract tests for providerCapabilityService, 34 fixture-anchored markdown table repair tests + 4 integration tests, 18 tests for CommunityProfileCard.humanizeCategory.

Dependencies

  • continuum-router updated to v1.6.1 (, picks up gpt-image-2, retrieval/embedding capability split).

Breaking Changes

  • None

Known Issues

  • None

Full Changelog