* agents: Qwen Code (qwen) as a managed agent (#1279) Qwen Code (QwenLM/qwen-code, a Gemini CLI fork) keeps custom model providers in ~/.qwen/settings.json modelProviders.<protocol> entries ({baseUrl, envKey, id, name}, envKey naming a variable in the same file's env object) and its session model in settings.model {name, baseUrl}. magpie writes one modelProviders.openai entry per catalog model — wire id the gateway takes, name magpie/<provider>/<model>, every one on env.MAGPIE_API_KEY holding the gateway's key, which is how an entry of magpie's is told from the user's own — and points settings.model at a pick. Stash, Check/drift, Sync, port-move Rewire and disconnect work as for the other JSON-config agents; on disconnect the user's entries, model and key are restored, the file byte-identical to before. Verified: go build, GOOS=linux nogui + GOOS=windows builds, go vet ./...; go test -tags nogui ./internal/agent (TestQwen* pass; TestDriftUnwiredEveryAgent/qwen and TestPortMovesEveryAgent pass after binding drift identity to the entry, not the address), go test -race -count=3 -run TestQwen, go test . (TestAgentQwenDefault: set then 'default' restores the settings byte-for-byte). TestQwen fails with 'unknown agent' when the registration is reverted. Real use: a copy of a live 341-line settings.json in a sandbox HOME — wire, then 'qwen default' left it byte-identical. Not run: GUI suite (no gui/assets change); TestReasonixCLI* and TestPluginHTTP2TakesTheProxy fail on main too (fixture/network), unchanged by this. * agents: qwen honors QWEN_HOME, sets auth type, owns a qwen-specific key name, carries context windows (#1279 review) - $QWEN_HOME stands for ~/.qwen, resolved as the other agents' (via place.getenv, appdir.Getenv; a distro's isn't read), and is in agentenv.Vars so the sandbox clears it - wiring sets security.auth.selectedType openai so qwen skips the /auth prompt; the user's own (including a pre-existing "openai", told from magpie's by a stash marker) is restored on disengage - envKey is MAGPIE_QWEN_API_KEY: a shell-exported or ~/.qwen/.env value wins over the settings' env, so the magpie-generic name is not used - entries carry generationConfig.contextWindowSize from the catalog - a settings.json without modelProviders reads as no models of anyone, instead of gjson's 'cannot use null as iterable' Verified: TestQwen* incl. TestQwenAuthOpenAIOfTheUsersOwn and TestQwenHomeOverride, TestAgentQwenDefault (CLI), -race -count=3; unwired-drift and port-move generic tests pass. Real end-to-end: dev gateway on 127.0.0.1:3999 in a sandbox HOME, real qwen binary in a sandbox QWEN_HOME ran a prompt through the gateway (PONG), and wire → default left the settings byte-identical. Reasonix fixture tests fail on main too (environment). * agents: qwen's requests are attributed by their QwenCode/<version> User-Agent
61 lines
1.5 KiB
Go
61 lines
1.5 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// `magpie qwen a/m` writes its provider entries and the gateway's key,
|
|
// `magpie qwen default` takes magpie back out and restores the model the
|
|
// user had, their own provider entry and settings kept.
|
|
func TestAgentQwenDefault(t *testing.T) {
|
|
groupsHome(t)
|
|
path := filepath.Join(os.Getenv("HOME"), ".qwen", "settings.json")
|
|
os.MkdirAll(filepath.Dir(path), 0o755)
|
|
own := `{
|
|
"env": {
|
|
"IDEALAB_API_KEY": "team-key"
|
|
},
|
|
"modelProviders": {
|
|
"openai": [
|
|
{
|
|
"baseUrl": "https://idealab.example.com/v1",
|
|
"envKey": "IDEALAB_API_KEY",
|
|
"id": "glm-5",
|
|
"name": "[IdeaLab] glm-5"
|
|
}
|
|
]
|
|
},
|
|
"model": {
|
|
"baseUrl": "https://idealab.example.com/v1",
|
|
"name": "glm-5"
|
|
},
|
|
"outputLanguage": "zh-CN"
|
|
}
|
|
`
|
|
if err := os.WriteFile(path, []byte(own), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
read := func() string {
|
|
b, _ := os.ReadFile(path)
|
|
return string(b)
|
|
}
|
|
if err := run([]string{"qwen", "a/m"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s := read()
|
|
for _, want := range []string{`"id": "a/m"`, `"name": "magpie/a/m"`, `"MAGPIE_QWEN_API_KEY"`, `"selectedType": "openai"`, `"baseUrl": "https://idealab.example.com/v1"`, `"outputLanguage": "zh-CN"`} {
|
|
if !strings.Contains(s, want) {
|
|
t.Fatalf("not wired (%s missing):\n%s", want, s)
|
|
}
|
|
}
|
|
if err := run([]string{"qwen", "default"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s = read(); s != own {
|
|
t.Fatalf("default didn't put back what was there:\n%s", s)
|
|
}
|
|
}
|