feat(cursor): update model handling to use agentv1 responses and enhance CLI model details

- Refactored response handling in newProtoMessage to utilize agentv1 for GetUsableModelsResponse and GetDefaultModelForCliResponse.
- Added new tests for buildCLIModelDetails and encodeCLIModels to ensure correct model details and encoding.
- Updated buildUsableModelsPayload and buildDefaultModelForCliPayload to leverage buildCLIModelDetails for improved model data structure.
This commit is contained in:
leookun
2026-08-03 22:56:17 +08:00
parent 424235f11d
commit 5df3e8f512
3 changed files with 78 additions and 12 deletions
+3 -2
View File
@@ -14,6 +14,7 @@ import (
"strings"
"time"
"cursor/gen/agentv1"
"cursor/gen/aiserverv1"
"cursor/internal/logger"
"cursor/internal/netproxy"
@@ -433,9 +434,9 @@ func newProtoMessage(typeName string) (proto.Message, error) {
case "aiserver.v1.ListMarketplacesResponse":
return &aiserverv1.ListMarketplacesResponse{}, nil
case "aiserver.v1.GetUsableModelsResponse":
return &aiserverv1.GetUsableModelsResponse{}, nil
return &agentv1.GetUsableModelsResponse{}, nil
case "aiserver.v1.GetDefaultModelForCliResponse":
return &aiserverv1.GetDefaultModelForCliResponse{}, nil
return &agentv1.GetDefaultModelForCliResponse{}, nil
case "aiserver.v1.GetDefaultModelResponse":
return &aiserverv1.GetDefaultModelResponse{}, nil
case "aiserver.v1.GetGlobalCommandsResponse":
+29 -10
View File
@@ -431,8 +431,8 @@ func buildServerTimePayload(*RequestContext) (map[string]any, error) {
func buildServerConfigPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"configVersion": "local_cli_sandbox_defaults_disabled_v2",
// "http2Config": "HTTP2_CONFIG_FORCE_ALL_DISABLED",
"configVersion": "local_cli_sandbox_defaults_disabled_v2",
"http2Config": "HTTP2_CONFIG_FORCE_ALL_DISABLED",
"cliSandboxDefaultEnabled": true,
"indexingConfig": map[string]any{
"defaultUserPathEncryptionKey": localPathEncryptionKey,
@@ -451,6 +451,7 @@ func buildAvailableModelsPayload(reqCtx *RequestContext) (map[string]any, error)
if len(modelRefs) > 0 {
defaultModel = modelRefs[0]
}
modelEntries := buildAvailableModelEntries(adapters)
return map[string]any{
"backgroundComposerModelConfig": map[string]any{
"bestOfNDefaultModels": append([]string(nil), modelRefs...),
@@ -470,7 +471,7 @@ func buildAvailableModelsPayload(reqCtx *RequestContext) (map[string]any, error)
"defaultModel": defaultModel,
},
"disableUnusedModelsAfterNHours": availableModelsDisableUnusedHours,
"models": buildAvailableModelEntries(adapters),
"models": modelEntries,
"planExecutionModelConfig": map[string]any{
"defaultModel": defaultModel,
"fallbackModels": append([]string(nil), modelRefs...),
@@ -502,12 +503,7 @@ func buildUsableModelsPayload(reqCtx *RequestContext) (map[string]any, error) {
if err != nil {
return nil, err
}
refs := collectModelAdapterRefs(adapters)
models := make([]map[string]any, 0, len(refs))
for _, ref := range refs {
models = append(models, map[string]any{"modelName": ref})
}
return map[string]any{"models": models}, nil
return map[string]any{"models": buildCLIModelDetails(adapters)}, nil
}
func buildDefaultModelForCliPayload(reqCtx *RequestContext) (map[string]any, error) {
@@ -515,7 +511,11 @@ func buildDefaultModelForCliPayload(reqCtx *RequestContext) (map[string]any, err
if err != nil {
return nil, err
}
return map[string]any{"model": map[string]any{"modelName": firstModelAdapterRef(adapters)}}, nil
models := buildCLIModelDetails(adapters)
if len(models) == 0 {
return map[string]any{"model": map[string]any{}}, nil
}
return map[string]any{"model": models[0]}, nil
}
func buildDefaultModelPayload(reqCtx *RequestContext) (map[string]any, error) {
@@ -720,6 +720,25 @@ func buildAvailableModelEntries(adapters []legacyruntime.ModelAdapterConfig) []m
return output
}
func buildCLIModelDetails(adapters []legacyruntime.ModelAdapterConfig) []map[string]any {
models := make([]map[string]any, 0, len(adapters))
for _, adapter := range adapters {
channelID := strings.TrimSpace(adapter.ID)
if channelID == "" {
continue
}
models = append(models, map[string]any{
"modelId": channelID,
"displayModelId": channelID,
"apiKeyCredentials": map[string]any{
"apiKey": strings.TrimSpace(adapter.APIKey),
"baseUrl": strings.TrimSpace(adapter.BaseURL),
},
})
}
return models
}
func buildThinkingEffortParameterDefinitions(adapterType string) []map[string]any {
values := thinkingEffortValuesForAdapter(adapterType)
options := make([]map[string]any, 0, len(values))
@@ -2,9 +2,55 @@ package upstream
import (
"encoding/json"
"reflect"
"testing"
"cursor/gen/agentv1"
legacyruntime "cursor/internal/runtime"
"google.golang.org/protobuf/proto"
)
func TestBuildCLIModelDetailsPreservesChannelCredentials(t *testing.T) {
adapters := []legacyruntime.ModelAdapterConfig{
{ID: " channel-a ", ModelID: "model-a", APIKey: "provider-secret-a", BaseURL: "https://provider-a.example/v1"},
{ID: "channel-b", ModelID: "model-a"},
{ID: "", ModelID: "model-c"},
}
got := buildCLIModelDetails(adapters)
want := []map[string]any{
{"modelId": "channel-a", "displayModelId": "channel-a", "apiKeyCredentials": map[string]any{"apiKey": "provider-secret-a", "baseUrl": "https://provider-a.example/v1"}},
{"modelId": "channel-b", "displayModelId": "channel-b", "apiKeyCredentials": map[string]any{"apiKey": "", "baseUrl": ""}},
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("build CLI model details: got %v, want %v", got, want)
}
}
func TestEncodeCLIModelsUsesAgentModelDetailsWireFormat(t *testing.T) {
payload := map[string]any{"models": buildCLIModelDetails([]legacyruntime.ModelAdapterConfig{{ID: "channel-a", APIKey: "provider-secret", BaseURL: "https://provider.example/v1"}})}
encoded, err := encodeMockProto("aiserver.v1.GetUsableModelsResponse", payload)
if err != nil {
t.Fatalf("encode CLI models: %v", err)
}
response := &agentv1.GetUsableModelsResponse{}
if err := proto.Unmarshal(encoded, response); err != nil {
t.Fatalf("decode CLI models with agent proto: %v", err)
}
if len(response.Models) != 1 {
t.Fatalf("decoded model count: got %d, want 1", len(response.Models))
}
model := response.Models[0]
if model.GetModelId() != "channel-a" || model.GetDisplayModelId() != "channel-a" {
t.Fatalf("decoded channel IDs: model=%q display=%q", model.GetModelId(), model.GetDisplayModelId())
}
if credentials := model.GetApiKeyCredentials(); credentials == nil || credentials.GetApiKey() != "provider-secret" || credentials.GetBaseUrl() != "https://provider.example/v1" {
t.Fatalf("decoded relay credentials: %#v", credentials)
}
}
func TestBuildBootstrapStatsigConfigJSONDisablesAlwaysLocalDecompositionGate(t *testing.T) {
payload, err := buildBootstrapStatsigConfigJSON(12345, "test-auth-id")
if err != nil {