* fix(pico): preserve image media across pico attachments and client
* * fix ci
* fix(pico): preserve text when client media parsing fails
- Skip non-inline Pico attachment URLs instead of treating them as invalid inline media
- Preserve pico_client text messages when malformed media payloads are received
- Add regression coverage for media.create, download attachments, and invalid media payloads
* fix lint
* add gemini web search provider
* fix(web): prefer free providers before Gemini in auto mode
* fix(web): expose gemini api key and model settings
* fix(web): prefer configured providers before Gemini in auto mode
* fix(web): satisfy gemini lint checks
* fix(web): address gemini provider review feedback
* test(web): align auto-provider expectations
* fix(web): let gemini ignore search range
* feat: improve model configuration workflows
Add model catalog browsing, provider registry with form validation,
model fetch/test dialogs, and enhanced model management UI.
- Add model catalog API and catalog-dialog component for browsing saved models
- Add provider-registry with auto-populated form fields per provider
- Add provider-combobox, fetch-models-dialog, test-model-dialog components
- Add model-validation for provider-aware model ID validation
- Add command and popover UI components
- Enhance edit-model-sheet with tool schema transform support
- Add anthropic to protocolMetaByName for correct default API base
- Apply NormalizeBaseURL to anthropic provider for consistent URL handling
- Add i18n keys for new model management features (en/zh)
* fix(web): prevent auto-fetch when API key is missing in fetch models dialog
When a provider requires an API key but none is set, the dialog now shows
the warning without triggering a doomed fetch attempt. Fetch is deferred
until the user provides a key.
* fix(web): add credential warning for catalog imports from remote providers
When importing models from a catalog entry whose provider requires an API
key, a yellow warning banner now informs users that credentials will need
to be configured after import.
* feat(web,api): test connection with real connectivity verification and unsaved form values
Add POST /api/models/test-inline endpoint that performs actual network
probes (GET /models) instead of just checking config. Frontend Test
Connection now uses current form values (not saved state) and is
available in both Add and Edit model flows.
* style(web): apply linter formatting across model config components
Normalize quote style, import ordering, and class name ordering as
reported by the project linter.
* fix(web,api): fix edit test connection false negative and gate fetch for unsupported providers
- handleTestInlineModel now accepts optional model_index to fall back to stored credentials when api_key is empty, fixing false negatives when testing edited models
- Add supportsFetch to provider registry and FETCHABLE_PROVIDER_KEYS derived set
- Gate Fetch Models button to only show for OpenAI-compatible and Ollama providers
- Add backend guard in handleFetchModels to reject unsupported providers with clear error
* fix: address review feedback on model config workflow
- Send explicit {} for empty extra_body/custom_headers fields so the
backend clears stored values instead of preserving them
- Merge backend provider_options with frontend PROVIDERS registry so
the provider picker reflects backend-supported providers and policy
fields (create_allowed, default_auth_method, auth_method_locked)
- Render provider combobox popover inside the sheet scroll container
to fix wheel events scrolling the sheet instead of the provider list
* feat(web,api): add provider selection, model form foundation, and validation
Split from PR #2752 (part 1 of 3).
Backend:
- CRUD model endpoints (list/add/update/delete/set-default)
- Provider metadata with default API bases and model provider options
- Model ID validation and normalization
- Anthropic default API base normalization
Frontend:
- Provider registry with metadata, labels, icons, and aliases
- Provider combobox with backend option merging
- Model field validation with provider-aware checks
- Redesigned add/edit model sheets with provider selection
- Dynamic imports for fetch/catalog/test dialogs (coming in PR2/PR3)
- i18n support for model configuration UI
Addresses security concerns raised in PR review:
1. Dynamic headers now require explicit allowlist per server:
- New `dynamic_headers.allowed` config field lists permitted header names
- Without allowlist, no dynamic headers are forwarded (secure by default)
- Header names matched case-insensitively
2. Add limits to prevent abuse:
- `max_count`: max headers per request (default: 10)
- `max_value_len`: max value length (default: 4096)
3. Protect internal metadata in pico channel:
- Reserved keys (platform, session_id, conn_id, etc.) cannot be
overwritten by client-provided metadata
Example config:
```json
"dynamic_headers": {
"allowed": ["X-Grafana-Service-Account-Token"],
"max_count": 5,
"max_value_len": 2048
}
```
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allows Pico clients to include a metadata object in message payloads.
String values are merged into the channel metadata, enabling clients
to pass headers (e.g., mcp:Authorization) that flow through to MCP
tool calls via the dynamic headers mechanism.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Clone header maps in WithMCPHeaders/MCPHeaders to prevent concurrent
mutation (maps are shared across goroutines via context).
- Trim whitespace from header names extracted from InboundContext.Raw
to prevent invalid HTTP header names.
- Add unit tests for headerTransport dynamic header injection:
dynamic-only, dynamic-overrides-static, and no-dynamic passthrough.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Channels can now pass HTTP headers to MCP servers on a per-request basis
by storing keys with a "mcp:" prefix in InboundContext.Raw. This enables
forwarding bearer tokens from channel authentication to MCP tool calls.
The context flows: Channel → InboundContext.Raw["mcp:Authorization"]
→ toolshared.MCPHeaders(ctx) → headerTransport.RoundTrip → HTTP header.
SSE/HTTP transports now always use headerTransport (previously only when
static headers were configured) so dynamic headers work out of the box.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Always route through classifySDKError to ensure resp.Body is
closed even when the API call succeeds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Store QuoteToken for image, video, and sticker messages (not just text)
- Add webhook.LocationMessageContent case to forward as [location] placeholder
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>