diff --git a/__tests__/validate.test.mjs b/__tests__/validate.test.mjs index 3469373..282c626 100644 --- a/__tests__/validate.test.mjs +++ b/__tests__/validate.test.mjs @@ -183,8 +183,9 @@ describe('真实数据全量校验', () => { } }) - it('Brave Search API 使用显式密钥声明且默认关闭', () => { + it('WebSearch API providers 使用显式密钥声明且默认关闭', () => { const brave = JSON.parse(readFileSync(join(ROOT, 'api-providers', 'web-search', 'brave.json'), 'utf8')) + const doubao = JSON.parse(readFileSync(join(ROOT, 'api-providers', 'web-search', 'doubao-search-global.json'), 'utf8')) const index = JSON.parse(readFileSync(join(ROOT, 'api-providers', 'web-search', '_index.json'), 'utf8')) assert.equal(brave.enabled, false) @@ -194,11 +195,38 @@ describe('真实数据全量校验', () => { headerName: 'X-Subscription-Token', apiKeyRef: 'brave', }) - assert.deepEqual(index.order, ['tavily', 'brave', 'serper']) + assert.equal(doubao.enabled, false) + assert.equal(doubao.endpoint, 'https://open.feedcoopapi.com/search_api/global_search') + assert.deepEqual(doubao.auth, { + type: 'bearer', + apiKeyRef: 'doubao-search-global', + }) + assert.deepEqual(doubao.request.bodyTemplate, { + Query: '${query}', + SearchType: 'web', + DocCount: '${maxResults}', + MaxSnippetLength: 500, + }) + assert.equal(doubao.response.resultsPath, 'Result.Documents') + assert.deepEqual(doubao.response.item, { + titlePath: 'Title', + urlPath: 'Url', + snippetPath: 'Snippet.0.Text', + pageAgePath: 'DocumentInfo.PublishTime', + }) + assert.deepEqual(doubao.response.successCondition, { + path: 'Result.ErrorCode', + equals: 0, + }) + assert.deepEqual(index.order, ['tavily', 'brave', 'serper', 'doubao-search-global']) assert.equal( validateFile(join(ROOT, 'api-providers', 'web-search', 'brave.json'), validators).ok, true, ) + assert.equal( + validateFile(join(ROOT, 'api-providers', 'web-search', 'doubao-search-global.json'), validators).ok, + true, + ) }) it('DeepSeek V4 Pro/Flash 应与官方的 1M/384K reasoning profile 一致', () => { diff --git a/api-providers/web-search/_index.json b/api-providers/web-search/_index.json index e9d7d89..02cca3d 100644 --- a/api-providers/web-search/_index.json +++ b/api-providers/web-search/_index.json @@ -1,4 +1,4 @@ { "description": "web_search 工具后端加载顺序索引", - "order": ["tavily", "brave", "serper"] + "order": ["tavily", "brave", "serper", "doubao-search-global"] } diff --git a/api-providers/web-search/doubao-search-global.json b/api-providers/web-search/doubao-search-global.json new file mode 100644 index 0000000..b1f0f28 --- /dev/null +++ b/api-providers/web-search/doubao-search-global.json @@ -0,0 +1,36 @@ +{ + "id": "doubao-search-global", + "name": "豆包搜索 Global", + "capability": "web_search", + "enabled": false, + "builtin": true, + "priority": 40, + "endpoint": "https://open.feedcoopapi.com/search_api/global_search", + "method": "POST", + "auth": { + "type": "bearer", + "apiKeyRef": "doubao-search-global" + }, + "request": { + "bodyTemplate": { + "Query": "${query}", + "SearchType": "web", + "DocCount": "${maxResults}", + "MaxSnippetLength": 500 + } + }, + "response": { + "resultsPath": "Result.Documents", + "item": { + "titlePath": "Title", + "urlPath": "Url", + "snippetPath": "Snippet.0.Text", + "pageAgePath": "DocumentInfo.PublishTime" + }, + "successCondition": { + "path": "Result.ErrorCode", + "equals": 0 + } + }, + "timeoutMs": 10000 +} diff --git a/manifest.json b/manifest.json index 1bdd44f..c21e284 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "version": "1.0.0", - "presetDataVersion": 107, - "updatedAt": "2026-08-31", + "presetDataVersion": 108, + "updatedAt": "2026-09-01", "description": "DesireCore 官方配置中心" } diff --git a/schemas/api-provider.schema.json b/schemas/api-provider.schema.json index 922bb8f..9006039 100644 --- a/schemas/api-provider.schema.json +++ b/schemas/api-provider.schema.json @@ -61,7 +61,24 @@ "pageAgePath": { "type": "string" } } }, - "textPath": { "type": "string", "description": "image_understanding 结果文本的点路径" } + "textPath": { "type": "string", "description": "image_understanding 结果文本的点路径" }, + "successCondition": { + "type": "object", + "description": "可选业务成功判定;HTTP 成功后读取 path 并与 equals 严格比较,不匹配时按 Provider 失败继续降级", + "required": ["path", "equals"], + "additionalProperties": false, + "properties": { + "path": { + "type": "string", + "minLength": 1, + "description": "业务成功标志的响应点路径;路径缺失也视为失败" + }, + "equals": { + "type": ["string", "number", "boolean", "null"], + "description": "成功时必须严格等于的 JSON 标量值" + } + } + } } }, "timeoutMs": { "type": "number", "description": "请求超时(毫秒)", "default": 10000 }