diff --git a/README.md b/README.md
index 8ee1e7c4..a2582761 100644
--- a/README.md
+++ b/README.md
@@ -222,7 +222,7 @@ Write your instructions, MCP servers and skills once. magpie writes them into ea
|
-Claude Code · Claude Desktop · Codex · Gemini CLI · OpenCode · OpenChamber · MiMo Code · Pi · Aside · OmO · Goose · Cursor CLI · Zed · VS Code Chat · VS Code Insiders · JetBrains Air · Copilot CLI · Crush · DeepSeek Harness · Command Code · fx · oh-my-pi · Devin · Hermes Agent · Mister Morph · Kimi Code · Muse Code · Empryo · MiniMax Code · Droid · Cline · Qoder · Qoder CN · Grok Build · ZCode · WorkBuddy · T3 Code · OpenHanako · AtomCode · Alma
+Claude Code · Claude Desktop · Codex · Gemini CLI · OpenCode · OpenChamber · MiMo Code · Pi · Aside · OmO · Goose · Cursor CLI · Zed · VS Code Chat · VS Code Insiders · VSCodium Chat · JetBrains Air · Copilot CLI · Crush · DeepSeek Harness · Command Code · fx · oh-my-pi · Devin · Hermes Agent · Mister Morph · Kimi Code · Muse Code · Empryo · MiniMax Code · Droid · Cline · Qoder · Qoder CN · Grok Build · ZCode · WorkBuddy · T3 Code · OpenHanako · AtomCode · Alma
|
@@ -235,6 +235,18 @@ export ANTHROPIC_BASE_URL=http://127.0.0.1:3425 ANTHROPIC_API_KEY=magpie
export GOOGLE_GEMINI_BASE_URL=http://127.0.0.1:3425 GEMINI_API_KEY=magpie
```
+### VSCodium Chat
+
+VSCodium's Chat features are disabled by default. To use the Chat model
+picker with magpie, set `"chat.disableAIFeatures": false` in VSCodium's
+settings and add the `defaultChatAgent` and `trustedExtensionAuthAccess`
+entries required by [VSCodium's Copilot guide](https://github.com/VSCodium/vscodium/blob/master/docs/ext-github-copilot.md)
+to VSCodium's `product.json`. The guide also explains how to install a
+compatible GitHub Copilot Chat extension, since the Open VSX registry does
+not normally provide Microsoft's extension. Restart VSCodium, or run
+**Developer: Reload Window**, after changing these files. Magpie's models
+then appear under the `magpie` custom endpoint group.
+
### Zed-compatible Agent paths
Magpie can use a Zed-compatible fork or installation whose executable or
diff --git a/internal/agent/agents.go b/internal/agent/agents.go
index 5c84332c..3808e119 100644
--- a/internal/agent/agents.go
+++ b/internal/agent/agents.go
@@ -81,6 +81,7 @@ func All() []*Agent {
zed(home, cfg),
vscode(home, cfg),
vscodeInsidersAgent(home, cfg),
+ vscodium(home, cfg),
air(home, cfg),
copilot(home),
crush(home, cfg),
diff --git a/internal/agent/vscode.go b/internal/agent/vscode.go
index c73ef24b..4cb8137e 100644
--- a/internal/agent/vscode.go
+++ b/internal/agent/vscode.go
@@ -58,6 +58,7 @@ type vscodeKind struct {
var (
vscodeStable = vscodeKind{id: "vscode", name: "VS Code", folder: "Code", bin: "code", aliases: []string{"vs-code", "copilot-chat", "vscode-chat"}, ua: []string{vscodeUA}}
vscodeInsiders = vscodeKind{id: "vscode-insiders", name: "VS Code Insiders", folder: "Code - Insiders", bin: "code-insiders", aliases: []string{"vs-code-insiders", "code-insiders"}}
+ vscodiumKind = vscodeKind{id: "vscodium", name: "VSCodium", folder: "VSCodium", bin: "codium", aliases: []string{"codium", "vscodium-chat"}}
)
// token is the bearer token its models send: Stable's the gateway's own,
@@ -75,6 +76,8 @@ func vscode(home, cfg string) *Agent { return vscodeOf(vscodeStable, home, cfg)
func vscodeInsidersAgent(home, cfg string) *Agent { return vscodeOf(vscodeInsiders, home, cfg) }
+func vscodium(home, cfg string) *Agent { return vscodeOf(vscodiumKind, home, cfg) }
+
func vscodeOf(k vscodeKind, home, cfg string) *Agent {
switch runtime.GOOS {
case "darwin":
@@ -161,6 +164,9 @@ func vscodeKindAt(k vscodeKind, dir string) *Agent {
},
Notice: func() string {
if joined() {
+ if k.id == "vscodium" {
+ return "VSCodium's Chat features must be enabled (chat.disableAIFeatures=false) and its product.json must include defaultChatAgent and trustedExtensionAuthAccess for GitHub.copilot-chat. Then run Developer: Reload Window in VSCodium."
+ }
return "magpie's models are in " + k.name + "'s Chat model picker, under magpie, in each of its profiles (VS Code 1.122 or later). If they don't show, run Developer: Reload Window in " + k.name + "."
}
return ""
diff --git a/internal/agent/vscode_test.go b/internal/agent/vscode_test.go
index ccc319d6..01af1510 100644
--- a/internal/agent/vscode_test.go
+++ b/internal/agent/vscode_test.go
@@ -289,3 +289,74 @@ func TestVSCodeInsiders(t *testing.T) {
t.Fatal("disconnected, magpie's group kept")
}
}
+
+func TestVSCodium(t *testing.T) {
+ syncHome(t)
+ c, err := Find("vscodium")
+ if err != nil {
+ t.Fatal(err)
+ }
+ vs, err := Find("vscode")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if c.Name != "VSCodium" || c.Bin != "codium" || c.UA != nil || !strings.Contains(c.Dir, filepath.Join("VSCodium", "User")) {
+ t.Fatalf("vscodium: %+v", c)
+ }
+ for _, alias := range []string{"codium", "vscodium-chat"} {
+ a, err := Find(alias)
+ if err != nil || a.ID != "vscodium" {
+ t.Fatalf("Find(%q): %v %v", alias, a, err)
+ }
+ }
+ writeFile(t, c.Path, "{}\n")
+ writeFile(t, vs.Path, `{"chat.defaultModel":"gpt-5"}`+"\n")
+ if !c.Detected() {
+ t.Fatal("VSCodium not detected")
+ }
+ if err := c.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ g, ok := edit.GetJSONItem(filepath.Join(c.Dir, "chatLanguageModels.json"), vscodeGroup)
+ if !ok || gjson.Get(g, "models.0.requestHeaders.Authorization").String() != "Bearer magpie-vscodium" || !c.Wired() || c.Check() != "" {
+ t.Fatalf("connected: %s %v %q", g, c.Wired(), c.Check())
+ }
+ if isFile(filepath.Join(vs.Dir, "chatLanguageModels.json")) || readFile(vs.Path) != `{"chat.defaultModel":"gpt-5"}`+"\n" || vs.Wired() {
+ t.Fatalf("VS Code touched:\n%s", readFile(vs.Path))
+ }
+ if got := usage.AgentOf("vscodium"); got != "vscodium" {
+ t.Fatalf("token: %q", got)
+ }
+ if err := c.Disconnect(); err != nil {
+ t.Fatal(err)
+ }
+ if _, ok := edit.GetJSONItem(filepath.Join(c.Dir, "chatLanguageModels.json"), vscodeGroup); ok || c.Wired() {
+ t.Fatal("disconnected, magpie's group kept")
+ }
+}
+
+func TestVSCodiumModelsUseTheirOwnVisibility(t *testing.T) {
+ syncHome(t)
+ if err := provider.Save(provider.Provider{ID: "relay", Name: "Relay", Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"visible", "hidden"}}); err != nil {
+ t.Fatal(err)
+ }
+ if err := provider.SetHiddenModels("vscodium", []string{"relay/hidden"}); err != nil {
+ t.Fatal(err)
+ }
+ if err := provider.SetHiddenModels("vscode", []string{"relay/visible"}); err != nil {
+ t.Fatal(err)
+ }
+ has := func(k vscodeKind, id string) bool {
+ b, err := json.Marshal(vscodeGroupJSON(k))
+ if err != nil {
+ t.Fatal(err)
+ }
+ return gjson.GetBytes(b, "models.#(id==\""+id+"\")").Exists()
+ }
+ if has(vscodiumKind, "relay/hidden") || !has(vscodiumKind, "relay/visible") {
+ t.Fatal("VSCodium did not use its own hidden-model list")
+ }
+ if !has(vscodeStable, "relay/hidden") || has(vscodeStable, "relay/visible") {
+ t.Fatal("VS Code did not retain its own hidden-model list")
+ }
+}