* ♻️ refactor(mecha): decide the model parameters of an LLM call in the shared core
Move the model-parameter rules out of the server's per-attempt hints into
`@lobechat/mecha` as `resolveModelParams(request, providers)`: which extend
params the model consumes (user row → provider card → canonical card),
where the reasoning effort comes from (topic pin, only for the pinned
model and, in a group topic, the answering agent → model-instance config →
sub-agent override), when assistant reasoning must be replayed (Kimi,
DeepSeek thinking, Meta, card support, provider fallback), the capability
defaults the context may assume, the history window, and the stream flag.
The server adapter now only supplies lookups (`createServerModelParamsProviders`)
and the run's frozen snapshots. `stream` falls back to the agent's
`chatConfig.enableStreaming` when the operation did not pin one; the
DeepSeek model-id predicates move to a dependency-free module so the shared
package can import them without the model bank.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* 🐛 fix(server): trace the streaming mode the request really uses
The chat span recorded `ctx.stream ?? true` while the payload now honours
the agent's chat config, so a newly non-streaming request was labelled as
streaming in telemetry. The built context rides along on the LLM trace
input and both the payload and the span read the same resolved value.
Also point the add-model-provider integration map at the shared
resolver as the policy owner.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* ⚡️ perf(model-bank): keep the aiModels catalog off the boot path
The model-bank root barrel re-exports the whole aiModels catalog (1.4 MB
raw), and a handful of value imports on the boot path (search config,
reasoning params, image/video defaults, provider enum) dragged it into the
first screen. Boot-path and route code now import the subpaths, the package
declares sideEffects: false and exposes ./utils and ./knowledgeCutoff, and an
eslint rule forbids value imports of the root barrel across src.
Also reach @lobechat/model-runtime/errors/specs and
@lobechat/utils/client/apiKeyManager directly so services/chat stops pulling
the error pattern tables and dompurify.
Web production build: first-screen gzip 2299 KB -> 2154 KB.
Claude-Session: https://claude.ai/code/session_01QKr8CsFLYmrgqbRTSipTNH
* 🐛 fix(lint): carry the model-bank ban through every scoped override
Flat config replaces no-restricted-imports per file instead of merging, so a
separate src/** block was dropped by the boot-path and feature overrides.
The ban now lives in performanceRestrictedImportPaths, which every
createRestrictedImportRule call includes; tests keep the base restrictions
only.
Claude-Session: https://claude.ai/code/session_01QKr8CsFLYmrgqbRTSipTNH
* ✅ test(upload): assert rejected store actions without act()
Wrapping a rejecting store action in act() and asserting with rejects let
the callback run again after the spies were restored, which sent a real
checkFileHash request and surfaced as an unhandled rejection in the shard.
Store actions do not render, so the assertion awaits them directly.
Claude-Session: https://claude.ai/code/session_01QKr8CsFLYmrgqbRTSipTNH
OpenAI SDK v4 bundles node-fetch@2, whose gzip response-stream handling
breaks under the Node.js June 2026 security release and throws
ERR_STREAM_PREMATURE_CLOSE (surfaced as "LLM stream error: Premature
close" across all providers). SDK v6 uses native fetch, removing the
node-fetch@2 dependency from the LLM call path.
Migration touch-ups for v6's type changes:
- narrow `apiKey` back to `string` (v6 widened it to `string | ApiKeySetter`)
- access `.function` via the function-tool variant (`ChatCompletionTool` /
`ChatCompletionMessageToolCall` are now function|custom unions)
- pass real `Headers` instead of plain objects to `APIError` in tests
(v6 calls `headers.get()`)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* ♻️ refactor: load models through model bank slot
* ♻️ refactor: remove static LobeHub model cards
* ♻️ refactor: share OpenAI image parameters
* 🐛 fix: load async LobeHub model config in server paths
* 🐛 fix: repair model bank CI follow-ups
* 🐛 fix: avoid repeated model bank fallback loads
* 🐛 fix: resolve business model config import in browser
* 🐛 fix: align Nano Banana 2 resolution default
* ♻️ refactor: move model loader slot under client
* ✅ test: move model bank aiModels spec out of build entries
* 🐛 fix: use business model config for mixed provider parsing
* ♻️ refactor: consolidate model bank provider utilities
* 🐛 fix: preserve Nano Banana 2 raw resolution
* 🐛 fix: avoid generated locale sync for raw resolution
* 🌐 style: add Nano Banana 2 resolution locales
* 🌐 style: add online LobeHub model locales
* 🐛 fix: guard optional model provider loaders
* 🐛 fix: prevent sitemap build from hanging
* 🐛 fix: clear sitemap timeout after model load
* 🐛 fix(minimax): derive max_tokens from context window to avoid ExceededContextWindow
MiniMax API enforces `input_tokens + max_tokens <= context_window`. The
provider was passing the model's full `maxOutput` as `max_tokens`, which
overflowed the context window as soon as a few large tool definitions or
system prompts were attached and made the very first user message fail
with "context window exceeds limit".
Add `resolveSafeMaxTokens` utility that estimates input tokens from the
payload (messages + tools), caps `max_tokens` at
`min(maxOutput, contextWindow - estimatedInput - buffer)`, and throws a
typed `MaxTokensExceededError` when no headroom remains. The MiniMax
provider now wires this into `handlePayload` and surfaces the error as
`ExceededContextWindow` via a `handleError` callback so it short-circuits
before the doomed upstream call.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 🐛 fix(minimax): estimate max_tokens against sanitized messages
handlePayload strips signed reasoning (and reasoning-without-content)
from assistant messages before sending to MiniMax, but the previous
resolveSafeMaxTokens call was still measuring the original payload.
For chats with long historical reasoning traces this overcounted the
input — capping max_tokens unnecessarily, or even raising
MaxTokensExceededError when the request would actually fit.
Pass the same processedMessages we send so the estimate matches the
wire payload.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Update sync.yml
* ✨ feat: update aspect ratio defaults to 'auto' for image generation models
* ✨ feat: enhance grounding metadata handling with image search results support
* ✨ feat: filter empty strings from searchQueries in groundingMetadata and update favicon handling in SearchGrounding component
* ✨ feat: add inputToolTokens tracking and update related components for tool usage
* ✨ feat: enhance search grounding with image results and update related components
* ✨ feat: add ImageSearchRef component and related tests for image reference handling
* fix test: rename VertexAIStream to GoogleGenerativeAIStream for consistency in test cases
* Update sync.yml
* feat: add adaptive thinking and effort configuration for Claude Opus 4.6
* fix: update @anthropic-ai/sdk dependency and refine thinking type handling in payload
* fix: enhance payload handling for Claude Opus 4.6
* i18n
* ♻️ refactor: unify retry logic to async-retry
- Refactor MCPService.listTools() to use async-retry with exponential backoff
- Refactor asyncifyPolling() to use async-retry internally while maintaining the same API
- Add async-retry as dependency to root package and model-runtime package
🔗 Related: LOBE-1370
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* ✅ test: update MCPService.listTools tests for async-retry
- Update test expectation: throw original error when retries exceeded
- Remove skipCache parameter test (now handled internally by async-retry)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* move
* refactor with model banks
* refactor with model banks
* refactor @/config/aiModels to model-bank
* refactor @/config/aiModels to model-bank
* fix model bank exports
* clean
* add test workflow
* try again
* fix
* add exports tests
* fix model bank alias
* Update tsconfig.json
* fix import issue
* clean unused code
* fix tests
* test workflow
* test workflow
* add test workflow
* add test workflow
* add test config
* add test config
* add test config
* add test config
* add test config
* update
* refactor tests
* fix tests
* fix tests
* exclude packages
* improve test
* fix test
* add a new package