Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
178
backend/internal/thinking/provider/interactions/apply.go
Normal file
178
backend/internal/thinking/provider/interactions/apply.go
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
// Package interactions applies native Interactions thinking configuration.
|
||||
package interactions
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/registry"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/thinking"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
// Applier implements thinking.ProviderApplier for the native Interactions API.
|
||||
type Applier struct{}
|
||||
|
||||
// NewApplier creates a new Interactions thinking applier.
|
||||
func NewApplier() *Applier {
|
||||
return &Applier{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
thinking.RegisterProvider("interactions", NewApplier())
|
||||
}
|
||||
|
||||
// Apply writes thinking configuration using native Interactions generation_config fields.
|
||||
func (a *Applier) Apply(body []byte, config thinking.ThinkingConfig, modelInfo *registry.ModelInfo) ([]byte, error) {
|
||||
if config.Mode != thinking.ModeBudget && config.Mode != thinking.ModeLevel && config.Mode != thinking.ModeNone && config.Mode != thinking.ModeAuto {
|
||||
return body, nil
|
||||
}
|
||||
if len(body) == 0 || !gjson.ValidBytes(body) {
|
||||
body = []byte(`{}`)
|
||||
}
|
||||
|
||||
result := stripInteractionsThinkingFields(body)
|
||||
switch config.Mode {
|
||||
case thinking.ModeLevel:
|
||||
return applyInteractionsLevel(result, body, string(config.Level), modelInfo), nil
|
||||
case thinking.ModeBudget:
|
||||
return applyInteractionsBudget(result, body, config.Budget, modelInfo), nil
|
||||
case thinking.ModeAuto:
|
||||
return setInteractionsThinkingSummaries(result, body), nil
|
||||
case thinking.ModeNone:
|
||||
return applyInteractionsNone(result, body, config, modelInfo), nil
|
||||
default:
|
||||
return body, nil
|
||||
}
|
||||
}
|
||||
|
||||
func applyInteractionsBudget(result, original []byte, budget int, modelInfo *registry.ModelInfo) []byte {
|
||||
level, ok := thinking.ConvertBudgetToLevel(budget)
|
||||
if !ok {
|
||||
return setInteractionsThinkingSummaries(result, original)
|
||||
}
|
||||
switch level {
|
||||
case string(thinking.LevelNone), string(thinking.LevelAuto):
|
||||
// Thinking amount and summary visibility are independent. Interactions has
|
||||
// no wire-level "none" thinking level, so preserve only explicit summary
|
||||
// intent and otherwise let the target model use its documented default.
|
||||
return setInteractionsThinkingSummaries(result, original)
|
||||
default:
|
||||
return applyInteractionsLevel(result, original, level, modelInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func applyInteractionsLevel(result, original []byte, level string, modelInfo *registry.ModelInfo) []byte {
|
||||
level = normalizeInteractionsLevel(level, modelInfo)
|
||||
if level != "" {
|
||||
result, _ = sjson.SetBytes(result, "generation_config.thinking_level", level)
|
||||
}
|
||||
return setInteractionsThinkingSummaries(result, original)
|
||||
}
|
||||
|
||||
func applyInteractionsNone(result, original []byte, config thinking.ThinkingConfig, modelInfo *registry.ModelInfo) []byte {
|
||||
if config.Level != "" {
|
||||
return applyInteractionsLevel(result, original, string(config.Level), modelInfo)
|
||||
}
|
||||
if config.Budget > 0 {
|
||||
return applyInteractionsBudget(result, original, config.Budget, modelInfo)
|
||||
}
|
||||
// With the amount fully disabled, visibility is irrelevant. Restoring
|
||||
// thinking_summaries alone could make a default-on model reason and return a
|
||||
// summary despite the explicit none override.
|
||||
return result
|
||||
}
|
||||
|
||||
func stripInteractionsThinkingFields(body []byte) []byte {
|
||||
result := body
|
||||
for _, path := range []string{
|
||||
"generation_config.thinking_level",
|
||||
"generation_config.thinkingLevel",
|
||||
"generation_config.thinking_budget",
|
||||
"generation_config.thinkingBudget",
|
||||
"generation_config.thinking_summaries",
|
||||
"generation_config.thinkingSummaries",
|
||||
"generation_config.thinking_config",
|
||||
"generation_config.thinkingConfig",
|
||||
"generationConfig.thinkingLevel",
|
||||
"generationConfig.thinking_level",
|
||||
"generationConfig.thinkingBudget",
|
||||
"generationConfig.thinking_budget",
|
||||
"generationConfig.thinkingSummaries",
|
||||
"generationConfig.thinking_summaries",
|
||||
"generationConfig.thinkingConfig",
|
||||
} {
|
||||
result, _ = sjson.DeleteBytes(result, path)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func setInteractionsThinkingSummaries(result, original []byte) []byte {
|
||||
if value, okValue := originalInteractionsThinkingSummaries(original); okValue {
|
||||
result, _ = sjson.SetBytes(result, "generation_config.thinking_summaries", value)
|
||||
return result
|
||||
}
|
||||
if includeThoughts, okValue := originalInteractionsIncludeThoughts(original); okValue {
|
||||
value := "none"
|
||||
if includeThoughts {
|
||||
value = "auto"
|
||||
}
|
||||
result, _ = sjson.SetBytes(result, "generation_config.thinking_summaries", value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func originalInteractionsThinkingSummaries(body []byte) (string, bool) {
|
||||
for _, path := range []string{
|
||||
"generation_config.thinking_summaries",
|
||||
"generation_config.thinkingSummaries",
|
||||
} {
|
||||
value := gjson.GetBytes(body, path)
|
||||
if value.Type != gjson.String {
|
||||
continue
|
||||
}
|
||||
switch normalized := strings.ToLower(strings.TrimSpace(value.String())); normalized {
|
||||
case "auto", "none":
|
||||
return normalized, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func originalInteractionsIncludeThoughts(body []byte) (bool, bool) {
|
||||
for _, path := range []string{
|
||||
"generation_config.thinking_config.include_thoughts",
|
||||
"generation_config.thinking_config.includeThoughts",
|
||||
"generation_config.thinkingConfig.include_thoughts",
|
||||
"generation_config.thinkingConfig.includeThoughts",
|
||||
} {
|
||||
switch value := gjson.GetBytes(body, path); value.Type {
|
||||
case gjson.True:
|
||||
return true, true
|
||||
case gjson.False:
|
||||
return false, true
|
||||
}
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func normalizeInteractionsLevel(level string, modelInfo *registry.ModelInfo) string {
|
||||
level = strings.ToLower(strings.TrimSpace(level))
|
||||
if level == "" || level == string(thinking.LevelNone) || level == string(thinking.LevelAuto) {
|
||||
return ""
|
||||
}
|
||||
if modelInfo != nil && modelInfo.Thinking != nil && len(modelInfo.Thinking.Levels) > 0 {
|
||||
for _, candidate := range modelInfo.Thinking.Levels {
|
||||
if strings.EqualFold(candidate, level) {
|
||||
return strings.ToLower(candidate)
|
||||
}
|
||||
}
|
||||
return strings.ToLower(modelInfo.Thinking.Levels[len(modelInfo.Thinking.Levels)-1])
|
||||
}
|
||||
switch level {
|
||||
case string(thinking.LevelMax), string(thinking.LevelXHigh):
|
||||
return string(thinking.LevelHigh)
|
||||
default:
|
||||
return level
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue