mirror of
https://git.openapi.site/https://github.com/desirecore/config-center.git
synced 2026-07-23 02:53:22 +08:00
feat(api-providers): 新增 web_search / image_understanding 声明式后端默认配置 (#31)
- api-providers/{web-search,image-understanding}/*.json + _index.json
- 新增 schemas/api-provider.schema.json,validate.mjs 纳入校验(CI 自检)
- 不改 compute/ 与 manifest,presetDataVersion 不变:老客户端忽略新目录,线上不受影响
Co-authored-by: yi-ge <jackyoncode@gmail.com>
This commit is contained in:
4
api-providers/image-understanding/_index.json
Normal file
4
api-providers/image-understanding/_index.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"description": "image_understanding 工具后端加载顺序索引",
|
||||||
|
"order": ["configured-vision-openai", "configured-vision-anthropic", "minimax"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"id": "configured-vision-anthropic",
|
||||||
|
"name": "视觉模型(Anthropic 兼容,复用默认映射)",
|
||||||
|
"capability": "image_understanding",
|
||||||
|
"enabled": true,
|
||||||
|
"builtin": true,
|
||||||
|
"priority": 20,
|
||||||
|
"endpoint": "${baseUrl}/messages",
|
||||||
|
"method": "POST",
|
||||||
|
"computeServiceType": "vision",
|
||||||
|
"requiresApiFormat": "anthropic-messages",
|
||||||
|
"auth": { "type": "header", "headerName": "x-api-key" },
|
||||||
|
"request": {
|
||||||
|
"imageMode": "base64",
|
||||||
|
"headers": { "anthropic-version": "2023-06-01" },
|
||||||
|
"bodyTemplate": {
|
||||||
|
"model": "${model}",
|
||||||
|
"max_tokens": 1024,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{ "type": "image", "source": { "type": "base64", "media_type": "${imageMime}", "data": "${imageBase64}" } },
|
||||||
|
{ "type": "text", "text": "${prompt}" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": { "textPath": "content.0.text" },
|
||||||
|
"timeoutMs": 30000
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"id": "configured-vision-openai",
|
||||||
|
"name": "视觉模型(OpenAI 兼容,复用默认映射)",
|
||||||
|
"capability": "image_understanding",
|
||||||
|
"enabled": true,
|
||||||
|
"builtin": true,
|
||||||
|
"priority": 10,
|
||||||
|
"endpoint": "${baseUrl}/chat/completions",
|
||||||
|
"method": "POST",
|
||||||
|
"computeServiceType": "vision",
|
||||||
|
"requiresApiFormat": "openai-completions",
|
||||||
|
"auth": { "type": "bearer" },
|
||||||
|
"request": {
|
||||||
|
"imageMode": "url",
|
||||||
|
"bodyTemplate": {
|
||||||
|
"model": "${model}",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{ "type": "text", "text": "${prompt}" },
|
||||||
|
{ "type": "image_url", "image_url": { "url": "${imageUrl}" } }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": { "textPath": "choices.0.message.content" },
|
||||||
|
"timeoutMs": 30000
|
||||||
|
}
|
||||||
18
api-providers/image-understanding/minimax.json
Normal file
18
api-providers/image-understanding/minimax.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"id": "minimax",
|
||||||
|
"name": "MiniMax 图像理解(内测网关)",
|
||||||
|
"capability": "image_understanding",
|
||||||
|
"enabled": false,
|
||||||
|
"builtin": true,
|
||||||
|
"priority": 30,
|
||||||
|
"endpoint": "${baseUrl}/understand_image",
|
||||||
|
"method": "POST",
|
||||||
|
"baseUrlRef": "internal-testing",
|
||||||
|
"auth": { "type": "bearer" },
|
||||||
|
"request": {
|
||||||
|
"imageMode": "url",
|
||||||
|
"bodyTemplate": { "prompt": "${prompt}", "image_url": "${imageUrl}" }
|
||||||
|
},
|
||||||
|
"response": { "textPath": "text" },
|
||||||
|
"timeoutMs": 30000
|
||||||
|
}
|
||||||
4
api-providers/web-search/_index.json
Normal file
4
api-providers/web-search/_index.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"description": "web_search 工具后端加载顺序索引",
|
||||||
|
"order": ["tavily", "serper", "minimax"]
|
||||||
|
}
|
||||||
20
api-providers/web-search/minimax.json
Normal file
20
api-providers/web-search/minimax.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"id": "minimax",
|
||||||
|
"name": "MiniMax 搜索(内测网关)",
|
||||||
|
"capability": "web_search",
|
||||||
|
"enabled": false,
|
||||||
|
"builtin": true,
|
||||||
|
"priority": 30,
|
||||||
|
"endpoint": "${baseUrl}/web_search",
|
||||||
|
"method": "POST",
|
||||||
|
"baseUrlRef": "internal-testing",
|
||||||
|
"auth": { "type": "bearer" },
|
||||||
|
"request": {
|
||||||
|
"bodyTemplate": { "query": "${query}", "num_results": "${maxResults}" }
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"resultsPath": "results",
|
||||||
|
"item": { "titlePath": "title", "urlPath": "url", "snippetPath": "content" }
|
||||||
|
},
|
||||||
|
"timeoutMs": 10000
|
||||||
|
}
|
||||||
19
api-providers/web-search/serper.json
Normal file
19
api-providers/web-search/serper.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"id": "serper",
|
||||||
|
"name": "Serper",
|
||||||
|
"capability": "web_search",
|
||||||
|
"enabled": false,
|
||||||
|
"builtin": true,
|
||||||
|
"priority": 20,
|
||||||
|
"endpoint": "https://google.serper.dev/search",
|
||||||
|
"method": "POST",
|
||||||
|
"auth": { "type": "header", "headerName": "X-API-KEY", "apiKeyRef": "serper" },
|
||||||
|
"request": {
|
||||||
|
"bodyTemplate": { "q": "${query}", "num": "${maxResults}" }
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"resultsPath": "organic",
|
||||||
|
"item": { "titlePath": "title", "urlPath": "link", "snippetPath": "snippet" }
|
||||||
|
},
|
||||||
|
"timeoutMs": 10000
|
||||||
|
}
|
||||||
23
api-providers/web-search/tavily.json
Normal file
23
api-providers/web-search/tavily.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"id": "tavily",
|
||||||
|
"name": "Tavily",
|
||||||
|
"capability": "web_search",
|
||||||
|
"enabled": false,
|
||||||
|
"builtin": true,
|
||||||
|
"priority": 10,
|
||||||
|
"endpoint": "https://api.tavily.com/search",
|
||||||
|
"method": "POST",
|
||||||
|
"auth": { "type": "bearer", "apiKeyRef": "tavily" },
|
||||||
|
"request": {
|
||||||
|
"bodyTemplate": {
|
||||||
|
"query": "${query}",
|
||||||
|
"max_results": "${maxResults}",
|
||||||
|
"search_depth": "basic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"resultsPath": "results",
|
||||||
|
"item": { "titlePath": "title", "urlPath": "url", "snippetPath": "content" }
|
||||||
|
},
|
||||||
|
"timeoutMs": 10000
|
||||||
|
}
|
||||||
69
schemas/api-provider.schema.json
Normal file
69
schemas/api-provider.schema.json
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "https://desirecore.net/schemas/config-center/api-provider.schema.json",
|
||||||
|
"title": "ApiProvider",
|
||||||
|
"description": "api-providers/<capability>/*.json:声明式外部 API 供应商(web_search / image_understanding 工具后端)。镜像 desirecore 主仓 lib/schemas/agent-service/api-provider.ts。",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["id", "name", "capability", "enabled", "endpoint", "auth", "request", "response"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"id": { "type": "string", "description": "同 capability 下唯一标识" },
|
||||||
|
"name": { "type": "string", "description": "显示名称" },
|
||||||
|
"capability": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["web_search", "image_understanding"],
|
||||||
|
"description": "服务的工具能力"
|
||||||
|
},
|
||||||
|
"enabled": { "type": "boolean", "description": "是否启用" },
|
||||||
|
"builtin": { "type": "boolean", "description": "是否为内置默认", "default": false },
|
||||||
|
"priority": { "type": "number", "description": "优先级,越小越优先", "default": 100 },
|
||||||
|
"endpoint": { "type": "string", "description": "API 端点 URL,支持 ${变量}" },
|
||||||
|
"method": { "type": "string", "enum": ["POST", "GET"], "description": "HTTP 方法", "default": "POST" },
|
||||||
|
"computeServiceType": { "type": "string", "description": "复用算力默认映射的服务类型(如 vision)" },
|
||||||
|
"requiresApiFormat": { "type": "string", "description": "仅当解析出的 provider apiFormat 等于此值时可用" },
|
||||||
|
"baseUrlRef": { "type": "string", "description": "指向某算力 provider 的 provider 标识,取其 baseUrl 与密钥" },
|
||||||
|
"auth": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "鉴权配置",
|
||||||
|
"required": ["type"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"type": { "type": "string", "enum": ["bearer", "header", "query", "none"] },
|
||||||
|
"apiKeyRef": { "type": "string", "description": "secrets.json 中的密钥引用名" },
|
||||||
|
"headerName": { "type": "string", "description": "type=header 时的请求头名称" },
|
||||||
|
"queryParam": { "type": "string", "description": "type=query 时的查询参数名" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "请求构造,字符串值支持 ${变量}",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"headers": { "type": "object", "additionalProperties": { "type": "string" } },
|
||||||
|
"bodyTemplate": { "type": "object", "additionalProperties": true },
|
||||||
|
"queryParams": { "type": "object", "additionalProperties": { "type": "string" } },
|
||||||
|
"imageMode": { "type": "string", "enum": ["url", "base64"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "响应提取",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"resultsPath": { "type": "string", "description": "web_search 结果数组的点路径" },
|
||||||
|
"item": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"titlePath": { "type": "string" },
|
||||||
|
"urlPath": { "type": "string" },
|
||||||
|
"snippetPath": { "type": "string" },
|
||||||
|
"pageAgePath": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"textPath": { "type": "string", "description": "image_understanding 结果文本的点路径" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timeoutMs": { "type": "number", "description": "请求超时(毫秒)", "default": 10000 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,9 @@ function pickSchemaKey(absPath) {
|
|||||||
if (rel.startsWith('compute/providers/') && rel.endsWith('.json')) return 'provider'
|
if (rel.startsWith('compute/providers/') && rel.endsWith('.json')) return 'provider'
|
||||||
if (rel.startsWith('compute/coding-plans/') && rel.endsWith('.json')) return 'provider'
|
if (rel.startsWith('compute/coding-plans/') && rel.endsWith('.json')) return 'provider'
|
||||||
if (rel.startsWith('compute/model-specs/') && rel.endsWith('.json')) return 'model-spec'
|
if (rel.startsWith('compute/model-specs/') && rel.endsWith('.json')) return 'model-spec'
|
||||||
|
// api-providers/<capability>/*.json:声明式外部 API 供应商(_index.json 复用 providers-index)
|
||||||
|
if (rel.startsWith('api-providers/') && rel.endsWith('/_index.json')) return 'providers-index'
|
||||||
|
if (rel.startsWith('api-providers/') && rel.endsWith('.json')) return 'api-provider'
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user