fix(ui): resolve alias conflict for jina-reader in curl example (#1241)

* fix(ui): resolve alias conflict for jina-reader in curl example

* docs(skills): correct web-fetch and web-search model examples
This commit is contained in:
Blue Hoang 2026-05-18 11:59:43 +07:00 committed by GitHub
parent 0e4e58930f
commit 462d1c5ca3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 37 additions and 9 deletions

View file

@ -23,20 +23,46 @@ IDs end in `/fetch` (e.g. `firecrawl/fetch`, `jina/fetch`). `fetch-combo` chains
| Field | Required | Notes |
|---|---|---|
| `model` (or `provider`) | yes | from `/v1/models/web` (`firecrawl/fetch` or `firecrawl`) |
| `model` (or `provider`) | yes | from `/v1/models/web` (e.g. `firecrawl` or `jina-reader`) |
| `url` | yes | URL to extract |
| `format` | no | `markdown` (default) / `text` / `html` |
| `max_characters` | no | truncate output |
## Examples
### Jina Reader
```bash
curl -X POST $NINEROUTER_URL/v1/web/fetch \
-H "Authorization: Bearer $NINEROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"jina/fetch","url":"https://9router.com","format":"markdown"}'
-d '{"model":"jina-reader","url":"https://9router.com","format":"markdown"}'
```
### Exa
```bash
curl -X POST $NINEROUTER_URL/v1/web/fetch \
-H "Authorization: Bearer $NINEROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"exa","url":"https://example.com","format":"markdown","max_characters":0}'
```
### Firecrawl
```bash
curl -X POST $NINEROUTER_URL/v1/web/fetch \
-H "Authorization: Bearer $NINEROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"firecrawl","url":"https://example.com","format":"markdown","max_characters":0}'
```
### Tavily
```bash
curl -X POST $NINEROUTER_URL/v1/web/fetch \
-H "Authorization: Bearer $NINEROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"tavily","url":"https://example.com","format":"markdown","max_characters":0}'
```
JS:
```js

View file

@ -23,7 +23,7 @@ IDs end in `/search` (e.g. `tavily/search`). Combos (`owned_by:"combo"`) chain p
| Field | Required | Notes |
|---|---|---|
| `model` (or `provider`) | yes | from `/v1/models/web` (e.g. `tavily/search` or just `tavily`) |
| `model` (or `provider`) | yes | from `/v1/models/web` (e.g. `tavily` or `brave`) |
| `query` | yes | search query |
| `max_results` | no | default 5 |
| `search_type` | no | `web` (default) / `news` |
@ -35,7 +35,7 @@ IDs end in `/search` (e.g. `tavily/search`). Combos (`owned_by:"combo"`) chain p
curl -X POST $NINEROUTER_URL/v1/search \
-H "Authorization: Bearer $NINEROUTER_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"tavily/search","query":"9Router open source","max_results":5}'
-d '{"model":"tavily","query":"9Router open source","max_results":5}'
```
JS:
@ -88,4 +88,4 @@ All accept `query` + `max_results`. Optional fields vary:
| `youcom` | country, language, time_range, domain_filter, full_page | — |
| `searxng` | language, time_range | Self-hosted, **noAuth** |
Provider IS the model — `"provider":"tavily"``"model":"tavily/search"`.
Provider IS the model — `"provider":"tavily" ≡ "model":"tavily"`.

View file

@ -5,7 +5,7 @@ import Link from "next/link";
import { useState, useEffect } from "react";
import { Card, Badge, Button, AddCustomEmbeddingModal, NoAuthProxyCard, ProviderInfoCard } from "@/shared/components";
import ProviderIcon from "@/shared/components/ProviderIcon";
import { MEDIA_PROVIDER_KINDS, AI_PROVIDERS, getProviderAlias, isCustomEmbeddingProvider } from "@/shared/constants/providers";
import { MEDIA_PROVIDER_KINDS, AI_PROVIDERS, getProviderAlias, isCustomEmbeddingProvider, resolveProviderId } from "@/shared/constants/providers";
import { getModelsByProviderId } from "@/shared/constants/models";
import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard";
import ConnectionsCard from "@/app/(dashboard)/dashboard/providers/components/ConnectionsCard";
@ -917,6 +917,8 @@ function TtsExampleCard({ providerId }) {
// Generic Example Card — config-driven for webSearch, webFetch, image, imageToText, stt, video, music
function GenericExampleCard({ providerId, kind }) {
const providerAlias = getProviderAlias(providerId);
const resolvedId = resolveProviderId(providerAlias);
const safeProviderAlias = resolvedId === providerId ? providerAlias : providerId;
const kindConfig = MEDIA_PROVIDER_KINDS.find((k) => k.id === kind);
const exConfig = KIND_EXAMPLE_CONFIG[kind];
const safeExConfig = exConfig || {};
@ -979,10 +981,10 @@ function GenericExampleCard({ providerId, kind }) {
const endpoint = useTunnel ? tunnelEndpoint : localEndpoint;
const apiPath = kindConfig.endpoint.path;
// webSearch/webFetch: use providerAlias only. Other kinds: append model when present.
// webSearch/webFetch: use safeProviderAlias only. Other kinds: append model when present.
const modelFull = !needsModel
? providerAlias
: (selectedModel ? `${providerAlias}/${selectedModel}` : (allowManualModel ? "" : providerAlias));
? safeProviderAlias
: (selectedModel ? `${safeProviderAlias}/${selectedModel}` : (allowManualModel ? "" : safeProviderAlias));
const imageEditDefaults = getImageEditDefaults(providerId, selectedModel);
const effectiveRefImage = refImage.trim() || imageEditDefaults.image || "";
const effectiveMaskImage = maskImage.trim() || imageEditDefaults.mask_image || "";