diff --git a/backend/internal/adapters/agent/qwen/qwen.go b/backend/internal/adapters/agent/qwen/qwen.go index 5e17767dcc..76c12450e3 100644 --- a/backend/internal/adapters/agent/qwen/qwen.go +++ b/backend/internal/adapters/agent/qwen/qwen.go @@ -52,6 +52,23 @@ func New() *Plugin { var _ adapters.Adapter = (*Plugin)(nil) var _ ports.Agent = (*Plugin)(nil) +// GetConfigSpec reports the per-project agent config keys Qwen Code +// understands. +func (p *Plugin) GetConfigSpec(ctx context.Context) (ports.ConfigSpec, error) { + if err := ctx.Err(); err != nil { + return ports.ConfigSpec{}, err + } + return ports.ConfigSpec{ + Fields: []ports.ConfigField{ + { + Key: "model", + Type: ports.ConfigFieldString, + Description: "Model override passed to `qwen --model`.", + }, + }, + }, nil +} + // Manifest returns the adapter's static self-description. func (p *Plugin) Manifest() adapters.Manifest { return adapters.Manifest{ @@ -79,6 +96,7 @@ func (p *Plugin) GetLaunchCommand(ctx context.Context, cfg ports.LaunchConfig) ( cmd = []string{binary} appendApprovalFlags(&cmd, cfg.Permissions) + appendModelFlag(&cmd, cfg.Config) systemPrompt, err := launchSystemPromptText(cfg) if err != nil { @@ -132,6 +150,7 @@ func (p *Plugin) GetRestoreCommand(ctx context.Context, cfg ports.RestoreConfig) cmd = make([]string, 0, 3) cmd = append(cmd, binary) appendApprovalFlags(&cmd, cfg.Permissions) + appendModelFlag(&cmd, cfg.Config) systemPrompt, err := restoreSystemPromptText(cfg) if err != nil { return nil, false, err @@ -229,6 +248,13 @@ func appendApprovalFlags(cmd *[]string, permissions ports.PermissionMode) { } } +// appendModelFlag appends --model if a non-empty model is configured. +func appendModelFlag(cmd *[]string, cfg ports.AgentConfig) { + if model := strings.TrimSpace(cfg.Model); model != "" { + *cmd = append(*cmd, "--model", model) + } +} + type qwenSubmitCommand struct { Type string `json:"type"` Text string `json:"text"` diff --git a/backend/internal/adapters/agent/qwen/qwen_test.go b/backend/internal/adapters/agent/qwen/qwen_test.go index 732e147b1c..04b718b64a 100644 --- a/backend/internal/adapters/agent/qwen/qwen_test.go +++ b/backend/internal/adapters/agent/qwen/qwen_test.go @@ -224,6 +224,68 @@ func TestGetLaunchCommandWorkerRequiresDataDirForRemoteInput(t *testing.T) { } } +func TestGetLaunchCommandWorkerAppendsTrimmedConfiguredModel(t *testing.T) { + plugin := &Plugin{resolvedBinary: "qwen"} + + cmd, err := plugin.GetLaunchCommand(context.Background(), ports.LaunchConfig{ + Kind: domain.KindWorker, + DataDir: t.TempDir(), + SessionID: "sess-123", + Config: domain.AgentConfig{Model: " qwen-plus "}, + Permissions: ports.PermissionModeBypassPermissions, + Prompt: "fix it", + }) + if err != nil { + t.Fatal(err) + } + if runtime.GOOS == "windows" { + if !containsSubsequence(cmd, []string{"--model", "qwen-plus"}) { + t.Fatalf("command %#v missing trimmed --model qwen-plus", cmd) + } + return + } + if len(cmd) != 3 || !strings.Contains(cmd[2], "'--model' 'qwen-plus'") { + t.Fatalf("worker command %#v missing trimmed --model qwen-plus", cmd) + } +} + +func TestGetLaunchCommandOmitsBlankConfiguredModel(t *testing.T) { + plugin := &Plugin{resolvedBinary: "qwen"} + + cmd, err := plugin.GetLaunchCommand(context.Background(), ports.LaunchConfig{ + Config: domain.AgentConfig{Model: " "}, + Permissions: ports.PermissionModeBypassPermissions, + Prompt: "fix it", + }) + if err != nil { + t.Fatal(err) + } + if contains(cmd, "--model") { + t.Fatalf("command %#v contains unexpected --model flag", cmd) + } +} + +func TestGetRestoreCommandAppendsConfiguredModel(t *testing.T) { + plugin := &Plugin{resolvedBinary: "qwen"} + + cmd, ok, err := plugin.GetRestoreCommand(context.Background(), ports.RestoreConfig{ + Config: domain.AgentConfig{Model: "qwen-max"}, + Permissions: ports.PermissionModeAuto, + Session: ports.SessionRef{ + Metadata: map[string]string{ports.MetadataKeyAgentSessionID: "sess-123"}, + }, + }) + if err != nil { + t.Fatal(err) + } + if !ok { + t.Fatal("ok = false, want true") + } + if !containsSubsequence(cmd, []string{"--model", "qwen-max"}) { + t.Fatalf("command %#v missing --model qwen-max", cmd) + } +} + func TestGetPromptDeliveryStrategy(t *testing.T) { plugin := &Plugin{} @@ -244,15 +306,22 @@ func TestGetPromptDeliveryStrategy(t *testing.T) { } } -func TestGetConfigSpecHasNoCustomFieldsYet(t *testing.T) { +func TestGetConfigSpecReportsModelField(t *testing.T) { plugin := &Plugin{} spec, err := plugin.GetConfigSpec(context.Background()) if err != nil { t.Fatal(err) } - if len(spec.Fields) != 0 { - t.Fatalf("unexpected config fields: %#v", spec.Fields) + want := []ports.ConfigField{ + { + Key: "model", + Type: ports.ConfigFieldString, + Description: "Model override passed to `qwen --model`.", + }, + } + if !reflect.DeepEqual(spec.Fields, want) { + t.Fatalf("config fields\nwant: %#v\n got: %#v", want, spec.Fields) } }