From 37ad16f6125b14fb70b10073c8e68154e0cde173 Mon Sep 17 00:00:00 2001 From: Yige Date: Fri, 28 Aug 2026 18:55:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(compute):=20=E5=A3=B0=E6=98=8E=20Anthropic?= =?UTF-8?q?=20thinking=20=E5=9B=9E=E6=94=BE=E8=83=BD=E5=8A=9B=20(#87)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: yige --- __tests__/validate.test.mjs | 24 ++++++++++++++++++++++++ compute/providers/anthropic.json | 24 ++++++++++++++++++++++++ manifest.json | 2 +- schemas/provider.schema.json | 28 +++++++++++++++++++++++++++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/__tests__/validate.test.mjs b/__tests__/validate.test.mjs index 0a755b5..28e516f 100644 --- a/__tests__/validate.test.mjs +++ b/__tests__/validate.test.mjs @@ -629,6 +629,30 @@ describe('provider schema 反例(防 PR #1 重演)', () => { assert.equal(validate(data), true, JSON.stringify(validate.errors)) }) + it('严格校验 Provider model 的 native thinking round-trip 能力', () => { + const valid = makeValidProvider() + valid.models[0].extra = { + thinkingRoundTrip: { + enabled: true, + protocol: 'anthropic-messages', + allowEmptySignature: false, + scope: 'active-tool-turn', + }, + } + assert.equal(validate(valid), true, JSON.stringify(validate.errors)) + + for (const brokenCapability of [ + { enabled: true, protocol: 'anthropic-messages', scope: 'active-tool-turn' }, + { enabled: true, protocol: 'openai-completions', allowEmptySignature: false, scope: 'active-tool-turn' }, + { enabled: true, protocol: 'anthropic-messages', allowEmptySignature: false, scope: 'all-history' }, + { enabled: true, protocol: 'anthropic-messages', allowEmptySignature: false, scope: 'active-tool-turn', completed: true }, + ]) { + const invalid = makeValidProvider() + invalid.models[0].extra = { thinkingRoundTrip: brokenCapability } + assert.equal(validate(invalid), false) + } + }) + it('拒绝 Ultra 与重复 reasoning effort', () => { const ultra = makeValidProvider() ultra.models[0].extra = { diff --git a/compute/providers/anthropic.json b/compute/providers/anthropic.json index 9250101..e898f15 100644 --- a/compute/providers/anthropic.json +++ b/compute/providers/anthropic.json @@ -35,6 +35,12 @@ "inputPrice": 10, "outputPrice": 50, "extra": { + "thinkingRoundTrip": { + "enabled": true, + "protocol": "anthropic-messages", + "allowEmptySignature": false, + "scope": "active-tool-turn" + }, "serverSideWebSearch": { "enabled": true, "dialect": "anthropic-messages", @@ -83,6 +89,12 @@ "inputPrice": 5, "outputPrice": 25, "extra": { + "thinkingRoundTrip": { + "enabled": true, + "protocol": "anthropic-messages", + "allowEmptySignature": false, + "scope": "active-tool-turn" + }, "serverSideWebSearch": { "enabled": true, "dialect": "anthropic-messages", @@ -136,6 +148,12 @@ "inputPrice": 2, "outputPrice": 10, "extra": { + "thinkingRoundTrip": { + "enabled": true, + "protocol": "anthropic-messages", + "allowEmptySignature": false, + "scope": "active-tool-turn" + }, "serverSideWebSearch": { "enabled": true, "dialect": "anthropic-messages", @@ -187,6 +205,12 @@ "outputPrice": 5, "defaultTemperature": 1, "extra": { + "thinkingRoundTrip": { + "enabled": true, + "protocol": "anthropic-messages", + "allowEmptySignature": false, + "scope": "active-tool-turn" + }, "modelId": "claude-haiku-4-5-20251001", "cachePricing": { "write5m": 1.25, diff --git a/manifest.json b/manifest.json index 45800a3..d89e162 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "version": "1.0.0", - "presetDataVersion": 102, + "presetDataVersion": 103, "updatedAt": "2026-08-28", "description": "DesireCore 官方配置中心" } diff --git a/schemas/provider.schema.json b/schemas/provider.schema.json index 0a49769..c4c179c 100644 --- a/schemas/provider.schema.json +++ b/schemas/provider.schema.json @@ -252,8 +252,34 @@ }, "extra": { "type": "object", - "description": "接入面特定配置:如 TTS 模型音色列表、ASR 支持格式与本 Provider 实际接受的 reasoning effort。这里是兼容扩展面:旧客户端会安全保留并忽略未知子字段。", + "description": "接入面特定配置:如 TTS 模型音色列表、ASR 支持格式、reasoning effort 与 native thinking 回放能力。这里是兼容扩展面:旧客户端会安全保留并忽略未知子字段。", "properties": { + "thinkingRoundTrip": { + "type": "object", + "description": "当前 Provider/model 接入面是否允许回放 Provider 原样返回的 Anthropic thinking。只授权当前未闭合工具轨迹;UI 展示 thinking、已完成旧轮次、跨模型/凭据数据永远没有回放资格。", + "required": ["enabled", "protocol", "allowEmptySignature", "scope"], + "properties": { + "enabled": { + "type": "boolean", + "description": "显式能力开关;客户端只接受 true,false 或缺失均 fail closed。" + }, + "protocol": { + "type": "string", + "enum": ["anthropic-messages"], + "description": "能力对应的线上协议;不得由 Provider 名称或 URL 猜测。" + }, + "allowEmptySignature": { + "type": "boolean", + "description": "是否允许回放该接入面原样返回的空 signature;只有真机证明网关确实要求时才能设为 true,不得制造空签名。" + }, + "scope": { + "type": "string", + "enum": ["active-tool-turn"], + "description": "固定只作用于当前未闭合工具轨迹,禁止扩张到完成历史。" + } + }, + "additionalProperties": false + }, "reasoning": { "type": "object", "description": "当前 Provider 接入面接受哪些 reasoning effort 值——精确档位矩阵。只能写在 provider model 的 extra 里:同一模型经不同网关支持的集合可能不同,因此 model-spec 的 spec.extra 里写本键会被客户端 applySpec 主动丢弃。想表达「这个模型根本关不掉思考」的用 model-spec 的 spec.extra.thinkingOnly,那只回答 off 能否使用、不声明任何深度档位。",