mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-23 10:57:44 +08:00
feat: Update Claude model names and IDs across configuration, documentation, and tests, including the default model and thinking delta logic.
This commit is contained in:
18
API.en.md
18
API.en.md
@@ -246,9 +246,9 @@ No auth required.
|
|||||||
{
|
{
|
||||||
"object": "list",
|
"object": "list",
|
||||||
"data": [
|
"data": [
|
||||||
{"id": "claude-sonnet-4-20250514", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
{"id": "claude-sonnet-4-5", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
||||||
{"id": "claude-sonnet-4-20250514-fast", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
{"id": "claude-3-5-haiku-latest", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
||||||
{"id": "claude-sonnet-4-20250514-slow", "object": "model", "created": 1715635200, "owned_by": "anthropic"}
|
{"id": "claude-opus-4-6", "object": "model", "created": 1715635200, "owned_by": "anthropic"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -267,7 +267,7 @@ anthropic-version: 2023-06-01
|
|||||||
|
|
||||||
| Field | Type | Required | Notes |
|
| Field | Type | Required | Notes |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `model` | string | ✅ | `claude-sonnet-4-20250514` / `-fast` / `-slow` |
|
| `model` | string | ✅ | `claude-sonnet-4-5` / `claude-opus-4-6` / `claude-3-5-haiku-latest` |
|
||||||
| `messages` | array | ✅ | Claude-style messages |
|
| `messages` | array | ✅ | Claude-style messages |
|
||||||
| `max_tokens` | number | ❌ | Not strictly enforced by upstream bridge |
|
| `max_tokens` | number | ❌ | Not strictly enforced by upstream bridge |
|
||||||
| `stream` | boolean | ❌ | Default `false` |
|
| `stream` | boolean | ❌ | Default `false` |
|
||||||
@@ -281,7 +281,7 @@ anthropic-version: 2023-06-01
|
|||||||
"id": "msg_1738400000000000000",
|
"id": "msg_1738400000000000000",
|
||||||
"type": "message",
|
"type": "message",
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"content": [
|
"content": [
|
||||||
{"type": "text", "text": "response"}
|
{"type": "text", "text": "response"}
|
||||||
],
|
],
|
||||||
@@ -325,7 +325,7 @@ data: {"type":"message_stop"}
|
|||||||
|
|
||||||
**Notes**:
|
**Notes**:
|
||||||
|
|
||||||
- Thinking-enabled models (`-slow`) stream `thinking_delta`
|
- Models whose names contain `opus` / `reasoner` / `slow` stream `thinking_delta`
|
||||||
- `signature_delta` is not emitted (DeepSeek does not provide verifiable thinking signatures)
|
- `signature_delta` is not emitted (DeepSeek does not provide verifiable thinking signatures)
|
||||||
- In `tools` mode, the stream avoids leaking raw tool JSON and does not force `input_json_delta`
|
- In `tools` mode, the stream avoids leaking raw tool JSON and does not force `input_json_delta`
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ data: {"type":"message_stop"}
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "Hello"}
|
{"role": "user", "content": "Hello"}
|
||||||
]
|
]
|
||||||
@@ -754,7 +754,7 @@ curl http://localhost:5001/anthropic/v1/messages \
|
|||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "anthropic-version: 2023-06-01" \
|
-H "anthropic-version: 2023-06-01" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"max_tokens": 1024,
|
"max_tokens": 1024,
|
||||||
"messages": [{"role": "user", "content": "Hello"}]
|
"messages": [{"role": "user", "content": "Hello"}]
|
||||||
}'
|
}'
|
||||||
@@ -768,7 +768,7 @@ curl http://localhost:5001/anthropic/v1/messages \
|
|||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "anthropic-version: 2023-06-01" \
|
-H "anthropic-version: 2023-06-01" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "claude-sonnet-4-20250514-slow",
|
"model": "claude-opus-4-6",
|
||||||
"max_tokens": 1024,
|
"max_tokens": 1024,
|
||||||
"messages": [{"role": "user", "content": "Explain relativity"}],
|
"messages": [{"role": "user", "content": "Explain relativity"}],
|
||||||
"stream": true
|
"stream": true
|
||||||
|
|||||||
18
API.md
18
API.md
@@ -246,9 +246,9 @@ data: [DONE]
|
|||||||
{
|
{
|
||||||
"object": "list",
|
"object": "list",
|
||||||
"data": [
|
"data": [
|
||||||
{"id": "claude-sonnet-4-20250514", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
{"id": "claude-sonnet-4-5", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
||||||
{"id": "claude-sonnet-4-20250514-fast", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
{"id": "claude-3-5-haiku-latest", "object": "model", "created": 1715635200, "owned_by": "anthropic"},
|
||||||
{"id": "claude-sonnet-4-20250514-slow", "object": "model", "created": 1715635200, "owned_by": "anthropic"}
|
{"id": "claude-opus-4-6", "object": "model", "created": 1715635200, "owned_by": "anthropic"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -267,7 +267,7 @@ anthropic-version: 2023-06-01
|
|||||||
|
|
||||||
| 字段 | 类型 | 必填 | 说明 |
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `model` | string | ✅ | `claude-sonnet-4-20250514` / `-fast` / `-slow` |
|
| `model` | string | ✅ | `claude-sonnet-4-5` / `claude-opus-4-6` / `claude-3-5-haiku-latest` |
|
||||||
| `messages` | array | ✅ | Claude 风格消息数组 |
|
| `messages` | array | ✅ | Claude 风格消息数组 |
|
||||||
| `max_tokens` | number | ❌ | 当前实现不会硬性截断上游输出 |
|
| `max_tokens` | number | ❌ | 当前实现不会硬性截断上游输出 |
|
||||||
| `stream` | boolean | ❌ | 默认 `false` |
|
| `stream` | boolean | ❌ | 默认 `false` |
|
||||||
@@ -281,7 +281,7 @@ anthropic-version: 2023-06-01
|
|||||||
"id": "msg_1738400000000000000",
|
"id": "msg_1738400000000000000",
|
||||||
"type": "message",
|
"type": "message",
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"content": [
|
"content": [
|
||||||
{"type": "text", "text": "回复内容"}
|
{"type": "text", "text": "回复内容"}
|
||||||
],
|
],
|
||||||
@@ -325,7 +325,7 @@ data: {"type":"message_stop"}
|
|||||||
|
|
||||||
**说明**:
|
**说明**:
|
||||||
|
|
||||||
- 思维模型(`-slow`)会输出 `thinking_delta`
|
- 名称中包含 `opus` / `reasoner` / `slow` 的模型会输出 `thinking_delta`
|
||||||
- 不会输出 `signature_delta`(上游 DeepSeek 未提供可验证签名)
|
- 不会输出 `signature_delta`(上游 DeepSeek 未提供可验证签名)
|
||||||
- `tools` 场景优先避免泄露原始工具 JSON,不强制发送 `input_json_delta`
|
- `tools` 场景优先避免泄露原始工具 JSON,不强制发送 `input_json_delta`
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ data: {"type":"message_stop"}
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "你好"}
|
{"role": "user", "content": "你好"}
|
||||||
]
|
]
|
||||||
@@ -754,7 +754,7 @@ curl http://localhost:5001/anthropic/v1/messages \
|
|||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "anthropic-version: 2023-06-01" \
|
-H "anthropic-version: 2023-06-01" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"max_tokens": 1024,
|
"max_tokens": 1024,
|
||||||
"messages": [{"role": "user", "content": "你好"}]
|
"messages": [{"role": "user", "content": "你好"}]
|
||||||
}'
|
}'
|
||||||
@@ -768,7 +768,7 @@ curl http://localhost:5001/anthropic/v1/messages \
|
|||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "anthropic-version: 2023-06-01" \
|
-H "anthropic-version: 2023-06-01" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "claude-sonnet-4-20250514-slow",
|
"model": "claude-opus-4-6",
|
||||||
"max_tokens": 1024,
|
"max_tokens": 1024,
|
||||||
"messages": [{"role": "user", "content": "解释相对论"}],
|
"messages": [{"role": "user", "content": "解释相对论"}],
|
||||||
"stream": true
|
"stream": true
|
||||||
|
|||||||
@@ -79,9 +79,9 @@ flowchart LR
|
|||||||
|
|
||||||
| 模型 | 默认映射 |
|
| 模型 | 默认映射 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `claude-sonnet-4-20250514` | `deepseek-chat` |
|
| `claude-sonnet-4-5` | `deepseek-chat` |
|
||||||
| `claude-sonnet-4-20250514-fast` | `deepseek-chat` |
|
| `claude-3-5-haiku-latest` | `deepseek-chat` |
|
||||||
| `claude-sonnet-4-20250514-slow` | `deepseek-reasoner` |
|
| `claude-opus-4-6` | `deepseek-reasoner` |
|
||||||
|
|
||||||
可通过配置中的 `claude_mapping` 或 `claude_model_mapping` 覆盖映射关系。
|
可通过配置中的 `claude_mapping` 或 `claude_model_mapping` 覆盖映射关系。
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,9 @@ flowchart LR
|
|||||||
|
|
||||||
| Model | Default Mapping |
|
| Model | Default Mapping |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `claude-sonnet-4-20250514` | `deepseek-chat` |
|
| `claude-sonnet-4-5` | `deepseek-chat` |
|
||||||
| `claude-sonnet-4-20250514-fast` | `deepseek-chat` |
|
| `claude-3-5-haiku-latest` | `deepseek-chat` |
|
||||||
| `claude-sonnet-4-20250514-slow` | `deepseek-reasoner` |
|
| `claude-opus-4-6` | `deepseek-reasoner` |
|
||||||
|
|
||||||
Override mapping via `claude_mapping` or `claude_model_mapping` in config.
|
Override mapping via `claude_mapping` or `claude_model_mapping` in config.
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func TestHandleClaudeStreamRealtimeTextIncrementsWithEventHeaders(t *testing.T)
|
|||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
||||||
|
|
||||||
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-20250514", []any{map[string]any{"role": "user", "content": "hi"}}, false, false, nil)
|
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-5", []any{map[string]any{"role": "user", "content": "hi"}}, false, false, nil)
|
||||||
|
|
||||||
body := rec.Body.String()
|
body := rec.Body.String()
|
||||||
if !strings.Contains(body, "event: message_start") {
|
if !strings.Contains(body, "event: message_start") {
|
||||||
@@ -122,7 +122,7 @@ func TestHandleClaudeStreamRealtimeThinkingDelta(t *testing.T) {
|
|||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
||||||
|
|
||||||
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-20250514", []any{map[string]any{"role": "user", "content": "hi"}}, true, false, nil)
|
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-5", []any{map[string]any{"role": "user", "content": "hi"}}, true, false, nil)
|
||||||
|
|
||||||
frames := parseClaudeFrames(t, rec.Body.String())
|
frames := parseClaudeFrames(t, rec.Body.String())
|
||||||
foundThinkingDelta := false
|
foundThinkingDelta := false
|
||||||
@@ -148,7 +148,7 @@ func TestHandleClaudeStreamRealtimeToolSafety(t *testing.T) {
|
|||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
||||||
|
|
||||||
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-20250514", []any{map[string]any{"role": "user", "content": "use tool"}}, false, false, []string{"search"})
|
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-5", []any{map[string]any{"role": "user", "content": "use tool"}}, false, false, []string{"search"})
|
||||||
|
|
||||||
frames := parseClaudeFrames(t, rec.Body.String())
|
frames := parseClaudeFrames(t, rec.Body.String())
|
||||||
for _, f := range findClaudeFrames(frames, "content_block_delta") {
|
for _, f := range findClaudeFrames(frames, "content_block_delta") {
|
||||||
@@ -191,7 +191,7 @@ func TestHandleClaudeStreamRealtimeUpstreamErrorEvent(t *testing.T) {
|
|||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
||||||
|
|
||||||
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-20250514", []any{map[string]any{"role": "user", "content": "hi"}}, false, false, nil)
|
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-5", []any{map[string]any{"role": "user", "content": "hi"}}, false, false, nil)
|
||||||
|
|
||||||
frames := parseClaudeFrames(t, rec.Body.String())
|
frames := parseClaudeFrames(t, rec.Body.String())
|
||||||
errFrames := findClaudeFrames(frames, "error")
|
errFrames := findClaudeFrames(frames, "error")
|
||||||
@@ -228,7 +228,7 @@ func TestHandleClaudeStreamRealtimePingEvent(t *testing.T) {
|
|||||||
|
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
req := httptest.NewRequest(http.MethodPost, "/anthropic/v1/messages", nil)
|
||||||
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-20250514", []any{map[string]any{"role": "user", "content": "hi"}}, false, false, nil)
|
h.handleClaudeStreamRealtime(rec, req, resp, "claude-sonnet-4-5", []any{map[string]any{"role": "user", "content": "hi"}}, false, false, nil)
|
||||||
|
|
||||||
frames := parseClaudeFrames(t, rec.Body.String())
|
frames := parseClaudeFrames(t, rec.Body.String())
|
||||||
if len(findClaudeFrames(frames, "ping")) == 0 {
|
if len(findClaudeFrames(frames, "ping")) == 0 {
|
||||||
|
|||||||
@@ -16,9 +16,13 @@ var DeepSeekModels = []ModelInfo{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ClaudeModels = []ModelInfo{
|
var ClaudeModels = []ModelInfo{
|
||||||
{ID: "claude-sonnet-4-20250514", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
{ID: "claude-sonnet-4-5", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
||||||
{ID: "claude-sonnet-4-20250514-fast", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
{ID: "claude-sonnet-4-5-20250929", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
||||||
{ID: "claude-sonnet-4-20250514-slow", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
{ID: "claude-opus-4-6", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
||||||
|
{ID: "claude-opus-4-1", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
||||||
|
{ID: "claude-opus-4-1-20250805", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
||||||
|
{ID: "claude-3-7-sonnet-latest", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
||||||
|
{ID: "claude-3-5-haiku-latest", Object: "model", Created: 1715635200, OwnedBy: "anthropic"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetModelConfig(model string) (thinking bool, search bool, ok bool) {
|
func GetModelConfig(model string) (thinking bool, search bool, ok bool) {
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ func (r *Runner) caseSSEJSONIntegrity(ctx context.Context, cc *caseContext) erro
|
|||||||
"anthropic-version": "2023-06-01",
|
"anthropic-version": "2023-06-01",
|
||||||
},
|
},
|
||||||
Body: map[string]any{
|
Body: map[string]any{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"messages": []map[string]any{
|
"messages": []map[string]any{
|
||||||
{"role": "user", "content": "stream json integrity"},
|
{"role": "user", "content": "stream json integrity"},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1056,7 +1056,7 @@ func (r *Runner) caseAnthropicNonstream(ctx context.Context, cc *caseContext) er
|
|||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
},
|
},
|
||||||
Body: map[string]any{
|
Body: map[string]any{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"messages": []map[string]any{
|
"messages": []map[string]any{
|
||||||
{"role": "user", "content": "hello"},
|
{"role": "user", "content": "hello"},
|
||||||
},
|
},
|
||||||
@@ -1084,7 +1084,7 @@ func (r *Runner) caseAnthropicStream(ctx context.Context, cc *caseContext) error
|
|||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
},
|
},
|
||||||
Body: map[string]any{
|
Body: map[string]any{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"messages": []map[string]any{
|
"messages": []map[string]any{
|
||||||
{"role": "user", "content": "stream hello"},
|
{"role": "user", "content": "stream hello"},
|
||||||
},
|
},
|
||||||
@@ -1113,7 +1113,7 @@ func (r *Runner) caseAnthropicCountTokens(ctx context.Context, cc *caseContext)
|
|||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
},
|
},
|
||||||
Body: map[string]any{
|
Body: map[string]any{
|
||||||
"model": "claude-sonnet-4-20250514",
|
"model": "claude-sonnet-4-5",
|
||||||
"messages": []map[string]any{
|
"messages": []map[string]any{
|
||||||
{"role": "user", "content": "count me"},
|
{"role": "user", "content": "count me"},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
var markdownImagePattern = regexp.MustCompile(`!\[(.*?)\]\((.*?)\)`)
|
var markdownImagePattern = regexp.MustCompile(`!\[(.*?)\]\((.*?)\)`)
|
||||||
|
|
||||||
const ClaudeDefaultModel = "claude-sonnet-4-20250514"
|
const ClaudeDefaultModel = "claude-sonnet-4-5"
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func TestMessagesPrepareRoles(t *testing.T) {
|
|||||||
func TestConvertClaudeToDeepSeek(t *testing.T) {
|
func TestConvertClaudeToDeepSeek(t *testing.T) {
|
||||||
store := config.LoadStore()
|
store := config.LoadStore()
|
||||||
req := map[string]any{
|
req := map[string]any{
|
||||||
"model": "claude-sonnet-4-20250514-slow",
|
"model": "claude-opus-4-6",
|
||||||
"messages": []any{map[string]any{"role": "user", "content": "Hi"}},
|
"messages": []any{map[string]any{"role": "user", "content": "Hi"}},
|
||||||
"system": "You are helpful",
|
"system": "You are helpful",
|
||||||
"stream": true,
|
"stream": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user