返回 DeepSeek-Reasonix
schema_error.go
根目录 / internal / provider / schema_error.go
1 package provider
2
3 import (
4 "errors"
5 "fmt"
6 "regexp"
7 "strconv"
8 "strings"
9 )
10
11 var providerToolIndexPattern = regexp.MustCompile(`(?i)\btool\s+(\d+)\s+function\b`)
12
13 // AnnotateToolSchemaError resolves provider messages such as "Tool 197 function
14 // has invalid 'parameters' schema" back to the stable Reasonix tool identity.
15 // MCP tool names carry their source server in mcp__<server>__<tool> form, so the
16 // resulting diagnostic tells users which integration supplied the bad schema.
17 func AnnotateToolSchemaError(err error, tools []ToolSchema) error {
18 var apiErr *APIError
19 if !errors.As(err, &apiErr) || (apiErr.Status != 400 && apiErr.Status != 422) {
20 return err
21 }
22 match := providerToolIndexPattern.FindStringSubmatch(apiErr.Body)
23 if len(match) != 2 {
24 return err
25 }
26 index, parseErr := strconv.Atoi(match[1])
27 if parseErr != nil || index < 0 || index >= len(tools) {
28 return err
29 }
30
31 tool := tools[index]
32 context := fmt.Sprintf("Provider tool %d maps to Reasonix tool %q.", index, tool.Name)
33 if server, rawName, ok := splitMCPToolName(tool.Name); ok {
34 context = fmt.Sprintf("Provider tool %d maps to Reasonix tool %q (MCP server %q, tool %q).", index, tool.Name, server, rawName)
35 }
36 annotated := *apiErr
37 annotated.ToolContext = context
38 return &annotated
39 }
40
41 func splitMCPToolName(name string) (server, tool string, ok bool) {
42 const prefix = "mcp__"
43 if !strings.HasPrefix(name, prefix) {
44 return "", "", false
45 }
46 parts := strings.SplitN(strings.TrimPrefix(name, prefix), "__", 2)
47 if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
48 return "", "", false
49 }
50 return parts[0], parts[1], true
51 }
52
52 lines GO