refactor(search): fold zai-search into the glm provider
The separate zai-search entry showed "No connections" on the web search page because credentials live on the `glm` connection, not on it. Every other provider that does both chat and search (antigravity, kimi, xai, gemini) declares webSearch on the provider itself, so do the same here. - glm gains serviceKinds ["llm", "webSearch"] and the MCP searchConfig - the request builder / normalizer move from "zai-search" to "glm" - drop the zai-search registry entry and its svg logo, which also removes the only need for svg logo support in getProviderIconSrc ollama-search keeps its own entry and credentialFallback: its search endpoint is unrelated to the ollama chat transport.
This commit is contained in:
@@ -394,12 +394,12 @@ function buildOllamaSearchRequest(config, params) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Z.AI Coding plan MCP web_search_prime ─────────────────────────────────
|
// ── GLM Coding plan MCP web_search_prime ──────────────────────────────────
|
||||||
// POST https://api.z.ai/api/mcp/web_search_prime/mcp
|
// POST https://api.z.ai/api/mcp/web_search_prime/mcp
|
||||||
// JSON-RPC envelope: { jsonrpc, id, method: "tools/call",
|
// JSON-RPC envelope: { jsonrpc, id, method: "tools/call",
|
||||||
// params: { name: "web_search_prime", arguments: { search_query, count } } }
|
// params: { name: "web_search_prime", arguments: { search_query, count } } }
|
||||||
// Response: { result: { content: [{ type: "text", text: "<json>" }] } }
|
// Response: { result: { content: [{ type: "text", text: "<json>" }] } }
|
||||||
function buildZaiSearchRequest(config, params) {
|
function buildGlmSearchRequest(config, params) {
|
||||||
const body = {
|
const body = {
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
id: `9r-${Date.now()}`,
|
id: `9r-${Date.now()}`,
|
||||||
@@ -437,7 +437,7 @@ const BUILDERS = {
|
|||||||
"searxng": buildSearxngRequest,
|
"searxng": buildSearxngRequest,
|
||||||
"xquik": buildXquikRequest,
|
"xquik": buildXquikRequest,
|
||||||
"ollama-search": buildOllamaSearchRequest,
|
"ollama-search": buildOllamaSearchRequest,
|
||||||
"zai-search": buildZaiSearchRequest,
|
"glm": buildGlmSearchRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ function normalizeOllamaSearch(data, _query, _searchType) {
|
|||||||
return { results, totalResults: results.length };
|
return { results, totalResults: results.length };
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeZaiSearch(data, _query, _searchType) {
|
function normalizeGlmSearch(data, _query, _searchType) {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
// MCP envelope: { result: { content: [{ type: "text", text: "<json>" }] } }
|
// MCP envelope: { result: { content: [{ type: "text", text: "<json>" }] } }
|
||||||
let payload = data;
|
let payload = data;
|
||||||
@@ -270,7 +270,7 @@ function normalizeZaiSearch(data, _query, _searchType) {
|
|||||||
: Array.isArray(payload) ? payload
|
: Array.isArray(payload) ? payload
|
||||||
: [];
|
: [];
|
||||||
const results = items.map((item, idx) =>
|
const results = items.map((item, idx) =>
|
||||||
makeResult("zai-search", {
|
makeResult("glm", {
|
||||||
title: item.title,
|
title: item.title,
|
||||||
url: item.link || item.url,
|
url: item.link || item.url,
|
||||||
snippet: item.content || "",
|
snippet: item.content || "",
|
||||||
@@ -295,7 +295,7 @@ const NORMALIZERS = {
|
|||||||
"searxng": normalizeSearxng,
|
"searxng": normalizeSearxng,
|
||||||
"xquik": normalizeXquik,
|
"xquik": normalizeXquik,
|
||||||
"ollama-search": normalizeOllamaSearch,
|
"ollama-search": normalizeOllamaSearch,
|
||||||
"zai-search": normalizeZaiSearch,
|
"glm": normalizeGlmSearch,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -53,6 +53,20 @@ export default {
|
|||||||
{ id: "glm-4.7", name: "GLM 4.7" },
|
{ id: "glm-4.7", name: "GLM 4.7" },
|
||||||
{ id: "glm-4.6v", name: "GLM 4.6V (Vision)" },
|
{ id: "glm-4.6v", name: "GLM 4.6V (Vision)" },
|
||||||
],
|
],
|
||||||
|
serviceKinds: ["llm", "webSearch"],
|
||||||
|
// Coding plan bundles web search on the same API key as chat.
|
||||||
|
searchConfig: {
|
||||||
|
baseUrl: "https://api.z.ai/api/mcp/web_search_prime/mcp",
|
||||||
|
method: "POST",
|
||||||
|
authType: "apikey",
|
||||||
|
authHeader: "bearer",
|
||||||
|
costPerQuery: 0,
|
||||||
|
searchTypes: ["web"],
|
||||||
|
defaultMaxResults: 5,
|
||||||
|
maxMaxResults: 50,
|
||||||
|
timeoutMs: 10000,
|
||||||
|
cacheTTLMs: 300000,
|
||||||
|
},
|
||||||
features: {
|
features: {
|
||||||
usage: true,
|
usage: true,
|
||||||
usageApikey: true,
|
usageApikey: true,
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ import p95 from "./xai.js";
|
|||||||
import p96 from "./xiaomi-mimo.js";
|
import p96 from "./xiaomi-mimo.js";
|
||||||
import p97 from "./xiaomi-tokenplan.js";
|
import p97 from "./xiaomi-tokenplan.js";
|
||||||
import p98 from "./youcom.js";
|
import p98 from "./youcom.js";
|
||||||
import p124 from "./zai-search.js";
|
|
||||||
import p99 from "./alims-intl.js";
|
import p99 from "./alims-intl.js";
|
||||||
import p100 from "./codebuddy-intl.js";
|
import p100 from "./codebuddy-intl.js";
|
||||||
// Temporarily hidden — no tool calling support (trae SOLO agent / windsurf gRPC skip ToolCallChunk).
|
// Temporarily hidden — no tool calling support (trae SOLO agent / windsurf gRPC skip ToolCallChunk).
|
||||||
@@ -225,7 +224,6 @@ export default [
|
|||||||
p96,
|
p96,
|
||||||
p97,
|
p97,
|
||||||
p98,
|
p98,
|
||||||
p124,
|
|
||||||
p99,
|
p99,
|
||||||
p100,
|
p100,
|
||||||
// p102, // trae — hidden, no tool calling
|
// p102, // trae — hidden, no tool calling
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
export default {
|
|
||||||
id: "zai-search",
|
|
||||||
alias: "zai-search",
|
|
||||||
display: {
|
|
||||||
name: "GLM Coding Search",
|
|
||||||
icon: "travel_explore",
|
|
||||||
color: "#2563EB",
|
|
||||||
textIcon: "GS",
|
|
||||||
website: "https://z.ai",
|
|
||||||
notice: {
|
|
||||||
text: "Web search via the Z.AI Coding plan MCP endpoint. Reuses the API key from the GLM Coding provider.",
|
|
||||||
apiKeyUrl: "https://open.bigmodel.cn/usercenter/apikeys",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
category: "apikey",
|
|
||||||
authType: "apikey",
|
|
||||||
authModes: ["apikey"],
|
|
||||||
serviceKinds: ["webSearch"],
|
|
||||||
// Credential fallback: reuses the GLM Coding plan API key — one key, chat + search.
|
|
||||||
credentialFallback: "glm",
|
|
||||||
searchConfig: {
|
|
||||||
baseUrl: "https://api.z.ai/api/mcp/web_search_prime/mcp",
|
|
||||||
method: "POST",
|
|
||||||
authType: "apikey",
|
|
||||||
authHeader: "bearer",
|
|
||||||
costPerQuery: 0,
|
|
||||||
freeMonthlyQuota: 0,
|
|
||||||
searchTypes: ["web"],
|
|
||||||
defaultMaxResults: 5,
|
|
||||||
maxMaxResults: 50,
|
|
||||||
timeoutMs: 10000,
|
|
||||||
cacheTTLMs: 300000,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect width="128" height="128" rx="28" fill="#6366f1"/>
|
|
||||||
<text x="64" y="64" text-anchor="middle" dominant-baseline="central" font-family="system-ui,-apple-system,sans-serif" font-size="48" font-weight="700" fill="#ffffff">Z</text>
|
|
||||||
<text x="64" y="98" text-anchor="middle" dominant-baseline="central" font-family="system-ui,-apple-system,sans-serif" font-size="16" font-weight="600" fill="#c7d2fe">.AI</text>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 521 B |
@@ -8,9 +8,6 @@ const ICON_ALIASES = {
|
|||||||
"ollama-search": "ollama",
|
"ollama-search": "ollama",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Providers that ship an .svg logo instead of .png.
|
|
||||||
const SVG_PROVIDER_IDS = new Set(["zai-search"]);
|
|
||||||
|
|
||||||
// Runtime only — first 404 remembers id for the whole session
|
// Runtime only — first 404 remembers id for the whole session
|
||||||
const failedIds = new Set();
|
const failedIds = new Set();
|
||||||
|
|
||||||
@@ -29,13 +26,10 @@ export function resolveProviderIconId(providerId) {
|
|||||||
return aliased;
|
return aliased;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** `/providers/{id}.{png|svg}` or null when previously failed. */
|
/** `/providers/{id}.png` or null when previously failed. */
|
||||||
export function getProviderIconSrc(providerId) {
|
export function getProviderIconSrc(providerId) {
|
||||||
const id = resolveProviderIconId(providerId);
|
const id = resolveProviderIconId(providerId);
|
||||||
if (!id) return null;
|
return id ? `/providers/${id}.png` : null;
|
||||||
// svg for vector logos, png for everything else
|
|
||||||
const ext = SVG_PROVIDER_IDS.has(id) ? "svg" : "png";
|
|
||||||
return `/providers/${id}.${ext}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Call from img onError so later mounts skip the request. */
|
/** Call from img onError so later mounts skip the request. */
|
||||||
|
|||||||
Reference in New Issue
Block a user