Files
tutti/services/tuttid/service/agent/composer_runtime_model_options.go
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

220 lines
6.4 KiB
Go

package agent
import (
"strings"
"github.com/tutti-os/tutti/packages/agent/daemon/modelcatalog"
"github.com/tutti-os/tutti/packages/agent/daemon/providerregistry"
)
func composerConfigOptions(
provider string,
settings ComposerSettings,
modelOptions []ComposerConfigOptionValue,
reasoningOptions []ComposerConfigOptionValue,
speedOptions []ComposerConfigOptionValue,
) []map[string]any {
profile := composerProfileFor(provider)
if !profile.ModelSelection && !profile.ReasoningEffort && !profile.Speed {
return []map[string]any{}
}
if modelOptions == nil {
modelOptions = composerSelectedModelOptions(settings.Model)
}
options := make([]map[string]any, 0, 3)
if profile.ModelSelection && len(modelOptions) > 0 {
configOptionID := strings.TrimSpace(profile.ModelConfigOptionID)
if configOptionID == "" {
configOptionID = "model"
}
options = append(options, map[string]any{
"currentValue": nullableString(settings.Model),
"id": configOptionID,
"options": composerConfigOptionValuesToRuntimeModelOptions(modelOptions),
})
}
if profile.ReasoningEffort && profile.ReasoningEffortOptions != providerregistry.ReasoningEffortOptionsStrictModelCatalog {
if len(reasoningOptions) > 0 {
options = append(options, map[string]any{
"currentValue": nullableString(settings.ReasoningEffort),
"id": reasoningConfigOptionID(provider),
"options": composerConfigOptionValuesToRuntimeOptions(reasoningOptions),
})
}
}
if profile.Speed {
options = append(options, map[string]any{
"currentValue": nullableString(settings.Speed),
"id": speedConfigOptionID(provider),
"options": composerConfigOptionValuesToRuntimeOptions(speedOptions),
})
}
return options
}
func extractModelOptionsFromRuntimeContext(runtimeContext map[string]any, optionIDs ...string) []ComposerConfigOptionValue {
if len(runtimeContext) == 0 {
return nil
}
modelOptionID := "model"
if len(optionIDs) > 0 && strings.TrimSpace(optionIDs[0]) != "" {
modelOptionID = strings.TrimSpace(optionIDs[0])
}
models, advertised, err := modelcatalog.ParseRuntimeConfigOptionModels(
runtimeContext["configOptions"],
modelOptionID,
)
if err != nil || !advertised {
return nil
}
return composerModelOptionsFromCanonicalCatalog(models)
}
func extractEffectiveModelFromRuntimeContext(
runtimeContext map[string]any,
optionIDs ...string,
) string {
if len(runtimeContext) == 0 {
return ""
}
modelOptionID := "model"
if len(optionIDs) > 0 && strings.TrimSpace(optionIDs[0]) != "" {
modelOptionID = strings.TrimSpace(optionIDs[0])
}
for _, option := range runtimeConfigOptionsAsMapSlice(runtimeContext["configOptions"]) {
if strings.TrimSpace(stringFromAny(option["id"])) != modelOptionID {
continue
}
return strings.TrimSpace(stringFromAny(option["effectiveValue"]))
}
return ""
}
func extractCurrentModelFromRuntimeContext(
runtimeContext map[string]any,
optionIDs ...string,
) string {
if len(runtimeContext) == 0 {
return ""
}
modelOptionID := "model"
if len(optionIDs) > 0 && strings.TrimSpace(optionIDs[0]) != "" {
modelOptionID = strings.TrimSpace(optionIDs[0])
}
for _, option := range runtimeConfigOptionsAsMapSlice(runtimeContext["configOptions"]) {
if strings.TrimSpace(stringFromAny(option["id"])) == modelOptionID {
return strings.TrimSpace(stringFromAny(option["currentValue"]))
}
}
return ""
}
func composerModelOptionsFromCanonicalCatalog(models []modelcatalog.ModelOption) []ComposerConfigOptionValue {
options := make([]ComposerConfigOptionValue, 0, len(models))
for _, model := range models {
value := strings.TrimSpace(model.ID)
if value == "" {
continue
}
if containsModelOption(options, value) {
continue
}
label := strings.TrimSpace(model.DisplayName)
if label == "" {
label = value
}
supportsReasoningEffort := (*bool)(nil)
if model.ReasoningEffortsAdvertised {
supported := len(model.SupportedReasoningEfforts) > 0
supportsReasoningEffort = &supported
}
options = append(options, ComposerConfigOptionValue{
ID: value,
Label: label,
Value: value,
Description: strings.TrimSpace(model.Description),
ConsumptionMultiplier: strings.TrimSpace(model.ConsumptionMultiplier),
SupportsImageInput: model.SupportsImageInput,
SupportsReasoningEffort: supportsReasoningEffort,
ReasoningEffort: strings.TrimSpace(model.DefaultReasoningEffort),
ReasoningEfforts: append([]AgentModelReasoningEffortOption(nil), model.SupportedReasoningEfforts...),
ReasoningEffortsAdvertised: model.ReasoningEffortsAdvertised,
})
}
return options
}
func composerConfigOptionValuesFromAny(input any) []ComposerConfigOptionValue {
rawOptions := anySlice(input)
if len(rawOptions) == 0 {
return nil
}
options := make([]ComposerConfigOptionValue, 0, len(rawOptions))
for _, raw := range rawOptions {
optionMap := anyMap(raw)
value := strings.TrimSpace(stringFromAny(optionMap["value"]))
if value == "" {
continue
}
label := strings.TrimSpace(stringFromAny(optionMap["label"]))
if label == "" {
label = strings.TrimSpace(stringFromAny(optionMap["name"]))
}
if label == "" {
label = value
}
id := strings.TrimSpace(stringFromAny(optionMap["id"]))
if id == "" {
id = value
}
options = append(options, ComposerConfigOptionValue{
ID: id,
Label: label,
Value: value,
Description: strings.TrimSpace(stringFromAny(optionMap["description"])),
ConsumptionMultiplier: strings.TrimSpace(stringFromAny(optionMap["consumptionMultiplier"])),
})
}
return options
}
func anySlice(input any) []any {
switch typed := input.(type) {
case []any:
return typed
case []map[string]any:
result := make([]any, len(typed))
for index := range typed {
result[index] = typed[index]
}
return result
case []map[string]string:
result := make([]any, len(typed))
for index := range typed {
record := make(map[string]any, len(typed[index]))
for key, value := range typed[index] {
record[key] = value
}
result[index] = record
}
return result
default:
return nil
}
}
func anyMap(input any) map[string]any {
switch typed := input.(type) {
case map[string]any:
return typed
case map[string]string:
result := make(map[string]any, len(typed))
for key, value := range typed {
result[key] = value
}
return result
default:
return nil
}
}