| 1 | package config |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "strconv" |
| 6 | "strings" |
| 7 | ) |
| 8 | |
| 9 | func rewriteDeepSeekProviderBlockAs(lines []string, block providerTOMLBlock, kind, baseURL string) error { |
| 10 | kindLine, baseURLLine := -1, -1 |
| 11 | state := tomlOutside |
| 12 | for i := block.start + 1; i < block.end; i++ { |
| 13 | if state != tomlOutside { |
| 14 | state = advanceTOMLStringState(state, lines[i]) |
| 15 | continue |
| 16 | } |
| 17 | nextState := advanceTOMLStringState(tomlOutside, lines[i]) |
| 18 | if nextState != tomlOutside { |
| 19 | state = nextState |
| 20 | continue |
| 21 | } |
| 22 | switch { |
| 23 | case kind == "openai" && (isTOMLKeyAssignment(lines[i], "request_url") || isTOMLKeyAssignment(lines[i], "chat_url")): |
| 24 | // Only reached for an eligible official endpoint. Clear the standard |
| 25 | // override so the derived endpoint applies and independent search |
| 26 | // stays enabled. |
| 27 | _, value, _ := tomlKeyValue(lines[i]) |
| 28 | if value != `""` && value != `''` { |
| 29 | lines[i] = replaceTOMLStringAssignment(lines[i], "") |
| 30 | } |
| 31 | case isTOMLKeyAssignment(lines[i], "kind"): |
| 32 | kindLine = i |
| 33 | case isTOMLKeyAssignment(lines[i], "base_url"): |
| 34 | baseURLLine = i |
| 35 | } |
| 36 | state = nextState |
| 37 | } |
| 38 | if kindLine < 0 || baseURLLine < 0 { |
| 39 | return fmt.Errorf("upgrade DeepSeek protocol: provider table is missing kind or base_url") |
| 40 | } |
| 41 | lines[kindLine] = replaceTOMLStringAssignment(lines[kindLine], kind) |
| 42 | lines[baseURLLine] = replaceTOMLStringAssignment(lines[baseURLLine], baseURL) |
| 43 | return nil |
| 44 | } |
| 45 | |
| 46 | func replaceTOMLStringAssignment(line, value string) string { |
| 47 | return replaceTOMLScalarAssignment(line, strconv.Quote(value)) |
| 48 | } |
| 49 | |
| 50 | func replaceTOMLScalarAssignment(line, encoded string) string { |
| 51 | carriageReturn := strings.HasSuffix(line, "\r") |
| 52 | line = strings.TrimSuffix(line, "\r") |
| 53 | equals, err := findTOMLAssignmentEquals(line, 0, len(line)) |
| 54 | if err != nil { |
| 55 | equals = strings.IndexByte(line, '=') |
| 56 | } |
| 57 | if equals < 0 { |
| 58 | return line |
| 59 | } |
| 60 | rhs := line[equals+1:] |
| 61 | leadingLen := len(rhs) - len(strings.TrimLeft(rhs, " \t")) |
| 62 | leading := rhs[:leadingLen] |
| 63 | suffix := "" |
| 64 | if comment := tomlInlineCommentIndex(rhs); comment >= 0 { |
| 65 | spaceStart := comment |
| 66 | for spaceStart > 0 && (rhs[spaceStart-1] == ' ' || rhs[spaceStart-1] == '\t') { |
| 67 | spaceStart-- |
| 68 | } |
| 69 | suffix = rhs[spaceStart:] |
| 70 | } |
| 71 | next := line[:equals+1] + leading + encoded + suffix |
| 72 | if carriageReturn { |
| 73 | next += "\r" |
| 74 | } |
| 75 | return next |
| 76 | } |
| 77 | |
| 78 | func tomlInlineCommentIndex(value string) int { |
| 79 | inBasic, inLiteral, escaped := false, false, false |
| 80 | for i := range len(value) { |
| 81 | ch := value[i] |
| 82 | if inBasic { |
| 83 | if escaped { |
| 84 | escaped = false |
| 85 | continue |
| 86 | } |
| 87 | switch ch { |
| 88 | case '\\': |
| 89 | escaped = true |
| 90 | case '"': |
| 91 | inBasic = false |
| 92 | } |
| 93 | continue |
| 94 | } |
| 95 | if inLiteral { |
| 96 | if ch == '\'' { |
| 97 | inLiteral = false |
| 98 | } |
| 99 | continue |
| 100 | } |
| 101 | switch ch { |
| 102 | case '"': |
| 103 | inBasic = true |
| 104 | case '\'': |
| 105 | inLiteral = true |
| 106 | case '#': |
| 107 | return i |
| 108 | } |
| 109 | } |
| 110 | return -1 |
| 111 | } |
| 112 |