fix: preserve runtime tool schemas in Claude tool output

This commit is contained in:
shern-point
2026-04-29 01:59:24 +08:00
parent a550de30af
commit 48c4f0df9f
5 changed files with 11 additions and 25 deletions

View File

@@ -1,6 +1,7 @@
package claude
import (
"ds2api/internal/toolcall"
"fmt"
"strings"
)
@@ -31,30 +32,9 @@ func extractClaudeToolNames(tools []any) []string {
}
func extractClaudeToolMeta(m map[string]any) (string, string, any) {
name, _ := m["name"].(string)
desc, _ := m["description"].(string)
schemaObj := m["input_schema"]
if schemaObj == nil {
schemaObj = m["parameters"]
}
if fn, ok := m["function"].(map[string]any); ok {
if strings.TrimSpace(name) == "" {
name, _ = fn["name"].(string)
}
if strings.TrimSpace(desc) == "" {
desc, _ = fn["description"].(string)
}
if schemaObj == nil {
if v, ok := fn["input_schema"]; ok {
schemaObj = v
}
}
if schemaObj == nil {
if v, ok := fn["parameters"]; ok {
schemaObj = v
}
}
name, desc, schemaObj := toolcall.ExtractToolMeta(m)
if strings.TrimSpace(desc) == "" {
desc = "No description available"
}
return strings.TrimSpace(name), strings.TrimSpace(desc), schemaObj
}

View File

@@ -177,7 +177,7 @@ func stripClaudeThinkingBlocks(raw []byte) []byte {
return out
}
func (h *Handler) handleClaudeStreamRealtime(w http.ResponseWriter, r *http.Request, resp *http.Response, model string, messages []any, thinkingEnabled, searchEnabled bool, toolNames []string) {
func (h *Handler) handleClaudeStreamRealtime(w http.ResponseWriter, r *http.Request, resp *http.Response, model string, messages []any, thinkingEnabled, searchEnabled bool, toolNames []string, toolsRaw any) {
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
@@ -205,6 +205,7 @@ func (h *Handler) handleClaudeStreamRealtime(w http.ResponseWriter, r *http.Requ
searchEnabled,
h.compatStripReferenceMarkers(),
toolNames,
toolsRaw,
)
streamRuntime.sendMessageStart()

View File

@@ -53,6 +53,7 @@ func normalizeClaudeRequest(store ConfigReader, req map[string]any) (claudeNorma
ResolvedModel: dsModel,
ResponseModel: strings.TrimSpace(model),
Messages: payload["messages"].([]any),
ToolsRaw: toolsRequested,
FinalPrompt: finalPrompt,
ToolNames: toolNames,
Stream: util.ToBool(req["stream"]),

View File

@@ -18,6 +18,7 @@ type claudeStreamRuntime struct {
model string
toolNames []string
messages []any
toolsRaw any
thinkingEnabled bool
searchEnabled bool
@@ -47,6 +48,7 @@ func newClaudeStreamRuntime(
searchEnabled bool,
stripReferenceMarkers bool,
toolNames []string,
toolsRaw any,
) *claudeStreamRuntime {
return &claudeStreamRuntime{
w: w,
@@ -59,6 +61,7 @@ func newClaudeStreamRuntime(
bufferToolContent: len(toolNames) > 0,
stripReferenceMarkers: stripReferenceMarkers,
toolNames: toolNames,
toolsRaw: toolsRaw,
messageID: fmt.Sprintf("msg_%d", time.Now().UnixNano()),
thinkingBlockIndex: -1,
textBlockIndex: -1,

View File

@@ -52,6 +52,7 @@ func (s *claudeStreamRuntime) finalize(stopReason string) {
detected = toolcall.ParseStandaloneToolCalls(finalThinking, s.toolNames)
}
if len(detected) > 0 {
detected = toolcall.NormalizeParsedToolCallsForSchemas(detected, s.toolsRaw)
stopReason = "tool_use"
for i, tc := range detected {
idx := s.nextBlockIndex + i