Feat : Skills

This commit is contained in:
decolua
2026-05-04 11:29:02 +07:00
parent f08fa5f78d
commit 9c6be62a54
52 changed files with 2666 additions and 1581 deletions
+14 -12
View File
@@ -40,38 +40,40 @@ async function probeWebProvider(provider, apiKey) {
return res.status !== 401 && res.status !== 403;
}
// Probe a tts/embedding provider using ttsConfig/embeddingConfig.
// Returns true if API key is accepted (status !== 401 && !== 403); null to skip.
// Probe a media provider (tts/embedding/stt/image/video) using *Config.
// Returns true if API key is accepted; null to skip (let default handler decide).
async function probeMediaProvider(provider, apiKey) {
const p = AI_PROVIDERS[provider];
if (!p) return null;
// Only probe providers that are media-only (not LLM dual-purpose, let LLM validate handle those)
const MEDIA_KINDS = new Set(["tts", "embedding", "stt", "image", "video", "music", "imageToText"]);
const kinds = p.serviceKinds || ["llm"];
const isMediaOnly = kinds.every((k) => k === "tts" || k === "embedding" || k === "stt");
const isMediaOnly = kinds.every((k) => MEDIA_KINDS.has(k));
if (!isMediaOnly) return null;
const cfg = p.ttsConfig || p.embeddingConfig;
if (!cfg) return null;
const cfg = p.ttsConfig || p.embeddingConfig || p.imageConfig || p.videoConfig || p.musicConfig;
// No probe config → best-effort accept (validate at usage time)
if (!cfg) return true;
if (p.noAuth || cfg.authType === "none") return true;
// Skip auth schemes that need provider-specific data
if (cfg.authHeader === "playht" || cfg.authHeader === "aws-sigv4") return null;
if (cfg.authHeader === "playht" || cfg.authHeader === "aws-sigv4") return true;
const headers = { "Content-Type": "application/json" };
const headers = { "Content-Type": "application/json", ...(cfg.extraHeaders || {}) };
// Apply auth based on authHeader
switch (cfg.authHeader) {
case "bearer": headers["Authorization"] = `Bearer ${apiKey}`; break;
case "key": headers["Authorization"] = `Key ${apiKey}`; break;
case "x-api-key": headers["x-api-key"] = apiKey; break;
case "x-key": headers["x-key"] = apiKey; break;
case "xi-api-key": headers["xi-api-key"] = apiKey; break;
case "token": headers["Authorization"] = `Token ${apiKey}`; break;
case "basic": headers["Authorization"] = `Basic ${apiKey}`; break;
default: return null;
}
// Minimal POST body — server will reject auth before validating body
const method = cfg.method || "POST";
const res = await fetch(cfg.baseUrl, {
method: "POST",
method,
headers,
body: JSON.stringify({ input: "ping", text: "ping", model: cfg.models?.[0]?.id || "test" }),
body: method === "GET" ? undefined : JSON.stringify({ input: "ping", text: "ping", prompt: "ping", model: cfg.models?.[0]?.id || "test" }),
signal: AbortSignal.timeout(8000),
});
return res.status !== 401 && res.status !== 403;