diff --git a/skills/9router-web-fetch/SKILL.md b/skills/9router-web-fetch/SKILL.md index 764aa37..69c41ac 100644 --- a/skills/9router-web-fetch/SKILL.md +++ b/skills/9router-web-fetch/SKILL.md @@ -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 diff --git a/skills/9router-web-search/SKILL.md b/skills/9router-web-search/SKILL.md index e88594c..ebd3003 100644 --- a/skills/9router-web-search/SKILL.md +++ b/skills/9router-web-search/SKILL.md @@ -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"`. diff --git a/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js b/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js index e8bf57f..5382f6f 100644 --- a/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js +++ b/src/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js @@ -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 || "";