diff --git a/docs/integrating.md b/docs/integrating.md new file mode 100644 index 00000000..24b4275f --- /dev/null +++ b/docs/integrating.md @@ -0,0 +1,145 @@ +# Integrating your app or agent with magpie + +For developers of an AI app, agent or client who want it to work well with +magpie. There are three levels, from no work on magpie's side to a row of +your own on the Agents page. The web version is +. + +| You want | Route | Change to magpie | +| ----------------------------------------------------- | ------------------------------ | ---------------- | +| Your app's requests served by magpie, counted under its own name in Usage | [Talk to the gateway](#1-talk-to-the-gateway) | none | +| A row on the Agents page: detected, its model picked there, put back on disconnect | [An agent adapter](#2-a-row-on-the-agents-page) | a pull request | +| A new model source (a subscription, a vendor), or rewriting requests | [A plugin](#3-plugins) | none | + +## 1. Talk to the gateway + +magpie runs a local LLM gateway. Every model the user has in magpie +(subscriptions, API keys, local models, routing groups) is served there +under one id each, so your app needs one provider entry, not one per +vendor. + +**Find it.** The gateway listens on `127.0.0.1:3425`, or on the port in +`port` of magpie's `settings.json` (`~/.config/magpie/settings.json`, the +same path under the user's folder on Windows; `$XDG_CONFIG_HOME/magpie` +when that is set). `GET /api/hello` answers +`{"name":"magpie","version":"…"}` when it is magpie. Read that file, never +write it. magpie must be running (the app or `magpie serve`). An app that +finds nothing there should offer its own providers as usual. + +**Endpoints.** Requests go straight through when the vendor speaks your +API, and are translated otherwise, streaming, tool calls, images and +reasoning included: + +| Path | API | +| ---- | --- | +| `/v1/chat/completions` | OpenAI Chat Completions | +| `/v1/responses` | OpenAI Responses | +| `/v1/messages`, `/v1/messages/count_tokens` | Anthropic Messages | +| `/v1beta/models/{model}:generateContent` (and `:streamGenerateContent`) | Google Gemini | +| `/v1/models` | the catalog | + +So the base URL is `http://127.0.0.1:/v1` for an OpenAI client and +`http://127.0.0.1:` for an Anthropic or Gemini one. + +**The key names your app.** On this machine the gateway takes any key. +Send `magpie-` (`Authorization: Bearer magpie-acme`, or +`x-api-key`) and every call is counted as `acme` in Usage, the Requests +log and the routing rules that match on agents. Without it, magpie counts +the call by the first word of your `User-Agent` (`Acme/1.4 (darwin)` is +`Acme`); an SDK's own User-Agent (`OpenAI/JS …`, `ai-sdk/…`) would count it +as that SDK. From another computer (Settings → Share on local network) the +key must be one of the user's gateway keys, and the User-Agent names your +app. + +**Models.** `GET /v1/models` lists what the user has turned on: `id` +(`provider/model`, or a routing group's name, which you send as it is), +`display_name`, `owned_by` (the provider), `reasoning` and +`supported_reasoning_levels` (`[{"effort":"low"},…]`), `context_window` +and `max_output_tokens` when known, `modalities` when magpie knows whether +it takes images. List them from there rather than shipping a list: the +user adds and removes providers in magpie. Reasoning is asked in your +API's own field (`reasoning_effort`, `reasoning.effort`, Anthropic's +`thinking` or `output_config.effort`). `?format=text` gives the ids one a +line. + +**Optional.** Send `X-Magpie-Session: ` with a conversation's requests +and `GET /v1/magpie/route?session=` says which model a routing group +picked for the turn and the fallbacks it tried, before the first token +(long-poll with `after=&wait=`). `GET /v1/magpie/quotas` lists the +user's subscription allowances. Both answer only this machine, or another +with a gateway key. [Connecting anything else](reference.md#connecting-anything-else) +has the details. + +**Keep the user's providers.** Add magpie as one more provider (named +Magpie) beside the ones the user set up in your app, rather than replacing +them, so turning magpie off is picking another provider. + +## 2. A row on the Agents page + +The agents magpie lists (Claude Code, Codex, OpenCode, dsh, Alma, Cindy…) +are adapters in [`internal/agent`](../internal/agent), one file each, +listed in [`agents.go`](../internal/agent/agents.go). A row gets your +app's name and icon, shows when your app is installed, lets the user pick +its model (and reasoning) from magpie's catalog, follows the catalog as +providers change, and on disconnect puts back what your app had before. +There is no runtime registration: a row is added by a pull request to +this repository, and ships in the next release. + +An adapter is an [`Agent`](../internal/agent/agent.go) value. What your +app offers decides its shape: + +- **magpie edits your config file** (most adapters; [`fx.go`](../internal/agent/fx.go), + [`empryo.go`](../internal/agent/empryo.go)). `Dir`, `Path` and `Bin` find + the app; each `Field` (`model`, `effort`, …) has `Get`, `Set` and + `Options`. Connecting adds a `magpie` provider at the gateway, keyed + `magpie-`, and sets your model to one of magpie's; `Set("")` (the + agent's default) or `Unwire` takes magpie's entries out and restores + what was there. Only the keys magpie sets are touched; the user's other + settings, providers and comments stay. `Notice` says when your app must + be restarted to see a change; `Sync` rewrites a model list your app keeps + in a file rather than asking `/v1/models`. +- **Your app takes a provider only through its own import link, which the + user confirms in your app** ([`cindy.go`](../internal/agent/cindy.go)). + `Import` returns the link (`yourapp://provider/import?…` carrying the + gateway's URL, the key `magpie-` and the endpoints), the row's button + opens it, and the user says yes once, in your app. `Added` reads, + read-only, whether your app has magpie already. magpie writes nothing of + yours. This suits an app that keeps its providers in a database or + encrypted. +- **Your app has a local API while it runs** (Alma, at `localhost:23001`): + magpie adds itself as a provider and sets the default model through it. + +A pull request needs: the adapter and its registration, `UA` (what your +User-Agent begins with, lower-case) so Usage knows your calls, an icon in +`internal/gui/assets/icons`, tests that run under a temporary `HOME` +(connect, switch, disconnect restoring the original file), and a row in +the [Agents table](reference.md#agents). What helps us most is a stable, +documented config format or import link, and where your app keeps it on +each system. + +## 3. Plugins + +A plugin is an npm package magpie runs; the user installs it from +Settings → Plugins or with `magpie plugin add `. There are two +kinds ([plugin guide](https://usemagpie.ai/docs/plugins)): + +- **Provider plugins**, OpenCode's `auth` hook or a pi package: a new + source of models, such as a subscription magpie doesn't sign in to + itself. They sign in, list models and make requests. +- **Gateway middleware**: rewrites requests and replies as they pass + (`onRequest`, `onEvent`, `onResponse`). + +A plugin can't add a row to the Agents page or write another app's +config, so it is not how an app registers itself. + +## What isn't there + +- No API or link lets another app register itself as an agent, or install + a plugin, without the user: plugins are installed in magpie by the user, + and agent rows come from adapters in magpie's source. +- `magpie://import` links add a *provider* (a source of models, with its + key), not an agent or an app; see [Import links](reference.md#import-links). + +Questions, or an adapter you'd like to discuss first: open an issue at + or ask on +[Discord](https://discord.gg/vGSnD3ZKQF). diff --git a/docs/reference.md b/docs/reference.md index 69acfe1e..75425eb0 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -708,6 +708,9 @@ deployments, set `MAGPIE_PUBLIC_URL=https://magpie.example.com` to the base URL shown in the console and CLI, including connection examples. Local agent configs still use the local gateway address. +Building an app or agent that should use magpie, or get a row on the +Agents page: see [Integrating your app or agent](integrating.md). + A reverse proxy must enforce authentication itself, or you must enable Settings → Share on local network and use an enabled gateway key (Gateway → Gateway keys) for external clients. A public URL with no port of diff --git a/internal/gateway/thirdparty_app_test.go b/internal/gateway/thirdparty_app_test.go new file mode 100644 index 00000000..1c5e0b2e --- /dev/null +++ b/internal/gateway/thirdparty_app_test.go @@ -0,0 +1,55 @@ +package gateway + +import ( + "encoding/json" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/yetone/magpie/internal/provider" + "github.com/yetone/magpie/internal/usage" +) + +// What docs/integrating.md promises an app magpie has no adapter for (#918): +// /api/hello finds the gateway, and its calls are counted as its own in +// Usage, by the key it sends (magpie-) or else by its User-Agent. +func TestThirdPartyAppIsCountedAsItself(t *testing.T) { + setHome(t, t.TempDir()) + + rec := httptest.NewRecorder() + New().Handler().ServeHTTP(rec, httptest.NewRequest("GET", "/api/hello", nil)) + var hello struct{ Name string } + if rec.Code != 200 || json.Unmarshal(rec.Body.Bytes(), &hello) != nil || hello.Name != "magpie" { + t.Fatalf("GET /api/hello: %d %s", rec.Code, rec.Body.String()) + } + + f := &fake{t: t, reply: sse( + `data: {"id":"c1","choices":[{"delta":{"content":"OK"},"finish_reason":"stop"}],"usage":{"prompt_tokens":5,"completion_tokens":2}}`, + `data: [DONE]`)} + setup(t, provider.Chat, f) + body := `{"model":"fake/m1","stream":true,"messages":[{"role":"user","content":"hi"}]}` + for i, c := range []struct{ key, ua, want string }{ + {TokenFor("my-app"), "node-fetch/1.0", "my-app"}, + {Token, "MyApp/1.2 (darwin)", "MyApp"}, + } { + rec := httptest.NewRecorder() + req := httptest.NewRequest("POST", "/v1/chat/completions", strings.NewReader(body)) + req.Header.Set("Authorization", "Bearer "+c.key) + req.Header.Set("User-Agent", c.ua) + New().Handler().ServeHTTP(rec, req) + if rec.Code != 200 || !strings.Contains(rec.Body.String(), "OK") { + t.Fatalf("%+v: %d %s", c, rec.Code, rec.Body.String()) + } + var got []usage.Record + for range 100 { + if got = usage.Load(time.Time{}); len(got) > i { + break + } + time.Sleep(20 * time.Millisecond) + } + if len(got) <= i || got[i].Agent != c.want { + t.Fatalf("%+v: records %+v, want the last %s's", c, got, c.want) + } + } +} diff --git a/site/public/docs/import.html b/site/public/docs/import.html index 8319e51e..b8c3996f 100644 --- a/site/public/docs/import.html +++ b/site/public/docs/import.html @@ -47,6 +47,7 @@ Intent routing Plugins Add to magpie + Integrate Releases
diff --git a/site/public/docs/integrate.html b/site/public/docs/integrate.html new file mode 100644 index 00000000..3d95f17e --- /dev/null +++ b/site/public/docs/integrate.html @@ -0,0 +1,177 @@ + + + + + +Integrate your app · magpie docs + + + + + + + + + + + + + + + + + + + + +
+ + +
+

Docs · For developers

+

Integrate your app

+

For developers of an AI app, agent or client who want it to work well with magpie. There are three levels, from no work on magpie’s side to a row of your own on the Agents page.

+ +
+ + + + +
You wantRouteChange to magpie
Your app’s requests served by magpie, counted under its own name in UsageTalk to the gatewaynone
A row on the Agents page: detected, its model picked there, put back on disconnectAn agent adaptera pull request
A new model source (a subscription, a vendor), or rewriting requestsA pluginnone
+ +

1. Talk to the gateway

+

magpie runs a local LLM gateway. Every model the user has in magpie (subscriptions, API keys, local models, routing groups) is served there under one id each, so your app needs one provider entry, not one per vendor.

+ +

Find it

+

The gateway listens on 127.0.0.1:3425, or on the port in port of magpie’s settings.json (~/.config/magpie/settings.json, the same path under the user’s folder on Windows; $XDG_CONFIG_HOME/magpie when that is set). GET /api/hello answers {"name":"magpie","version":"…"} when it is magpie. Read that file, never write it. magpie must be running (the app or magpie serve); an app that finds nothing there offers its own providers as usual.

+
+ Shell + +
curl -s http://127.0.0.1:3425/api/hello
+curl -s http://127.0.0.1:3425/v1/models -H "Authorization: Bearer magpie-acme"
+
+ +

Endpoints

+

Requests go straight through when the vendor speaks your API, and are translated otherwise, streaming, tool calls, images and reasoning included. The base URL is http://127.0.0.1:<port>/v1 for an OpenAI client and http://127.0.0.1:<port> for an Anthropic or Gemini one.

+
+ + + + + + +
PathAPI
/v1/chat/completionsOpenAI Chat Completions
/v1/responsesOpenAI Responses
/v1/messages, /v1/messages/count_tokensAnthropic Messages
/v1beta/models/{model}:generateContent (and :streamGenerateContent)Google Gemini
/v1/modelsthe catalog
+ +

The key names your app

+

On this machine the gateway takes any key. Send magpie-<your-app-id> (Authorization: Bearer magpie-acme, or x-api-key) and every call is counted as acme in Usage, the Requests log and the routing rules that match on agents. Without it, magpie counts the call by the first word of your User-Agent (Acme/1.4 (darwin) is Acme); an SDK’s own User-Agent (OpenAI/JS …, ai-sdk/…) would count it as that SDK. From another computer (Settings → Share on local network) the key must be one of the user’s gateway keys, and the User-Agent names your app.

+ +

Models

+

GET /v1/models lists what the user has turned on: id (provider/model, or a routing group’s name, sent as it is), display_name, owned_by (the provider), reasoning and supported_reasoning_levels ([{"effort":"low"},…]), context_window and max_output_tokens when known, and modalities when magpie knows whether it takes images. List them from there rather than shipping a list: the user adds and removes providers in magpie. Reasoning is asked in your API’s own field (reasoning_effort, reasoning.effort, Anthropic’s thinking or output_config.effort). ?format=text gives the ids one a line.

+ +

Optional

+

Send X-Magpie-Session: <id> with a conversation’s requests and GET /v1/magpie/route?session=<id> says which model a routing group picked for the turn and the fallbacks it tried, before the first token (long-poll with after=<seq>&wait=<s>). GET /v1/magpie/quotas lists the user’s subscription allowances. Both answer only this machine, or another with a gateway key. The reference has the details.

+ +
Keep the user’s providers. Add magpie as one more provider (named Magpie) beside the ones the user set up in your app, rather than replacing them, so turning magpie off is picking another provider.
+ +

2. A row on the Agents page

+

The agents magpie lists (Claude Code, Codex, OpenCode, dsh, Alma, Cindy…) are adapters in internal/agent, one file each. A row gets your app’s name and icon, shows when your app is installed, lets the user pick its model (and reasoning) from magpie’s catalog, follows the catalog as providers change, and on disconnect puts back what your app had before. There is no runtime registration: a row is added by a pull request to magpie, and ships in the next release.

+

An adapter is an Agent value. What your app offers decides its shape:

+
    +
  • magpie edits your config file (most adapters; fx.go, empryo.go). Dir, Path and Bin find the app; each Field (model, effort…) has Get, Set and Options. Connecting adds a magpie provider at the gateway, keyed magpie-<id>, and sets your model to one of magpie’s; the agent’s default or Unwire takes magpie’s entries out and restores what was there. Only the keys magpie sets are touched. Notice says when your app must be restarted; Sync rewrites a model list your app keeps in a file.
  • +
  • Your app takes a provider only through its own import link, confirmed in your app (cindy.go). Import returns the link (yourapp://provider/import?… with the gateway’s URL, the key magpie-<id> and the endpoints), the row’s button opens it, and the user says yes once, in your app. Added reads, read-only, whether your app has magpie already. magpie writes nothing of yours. This suits an app that keeps its providers in a database or encrypted.
  • +
  • Your app has a local API while it runs (Alma): magpie adds itself as a provider and sets the default model through it.
  • +
+

A pull request needs the adapter and its entry in agents.go, UA (what your User-Agent begins with, lower-case) so Usage knows your calls, an icon in internal/gui/assets/icons, tests that run under a temporary HOME (connect, switch, disconnect restoring the original file), and a row in the reference’s Agents table. What helps most is a stable, documented config format or import link, and where your app keeps it on each system.

+ +

3. Plugins

+

A plugin is an npm package magpie runs; the user installs it from Settings → Plugins or with magpie plugin add <package>. Provider plugins (OpenCode’s auth hook, or a pi package) add a source of models, such as a subscription magpie doesn’t sign in to itself. Gateway middleware rewrites requests and replies as they pass. See the plugin guide. A plugin can’t add a row to the Agents page or write another app’s config, so it is not how an app registers itself.

+ +

What isn’t there

+
    +
  • No API or link lets another app register itself as an agent, or install a plugin, without the user: plugins are installed in magpie by the user, and agent rows come from adapters in magpie’s source.
  • +
  • magpie://import links add a provider (a source of models, with its key), not an agent or an app: see Add to magpie.
  • +
+ +

Questions, or an adapter you’d like to discuss first: open an issue or ask on Discord.

+
+
+ + + + + + + diff --git a/site/public/docs/intent.html b/site/public/docs/intent.html index 681a5f53..7404418e 100644 --- a/site/public/docs/intent.html +++ b/site/public/docs/intent.html @@ -47,6 +47,7 @@ Intent routing Plugins Add to magpie + Integrate Releases
@@ -316,6 +317,7 @@ The number of its kind (0 for none): Intent routing Plugins Add to magpie + Integrate GitHub Discord Releases diff --git a/site/public/docs/ja/import.html b/site/public/docs/ja/import.html index 2fa6132a..2226a8ad 100644 --- a/site/public/docs/ja/import.html +++ b/site/public/docs/ja/import.html @@ -47,6 +47,7 @@ インテントルーティング プラグイン magpie に追加 + アプリ連携 リリース
diff --git a/site/public/docs/ja/intent.html b/site/public/docs/ja/intent.html index b95c32fb..9fb366b3 100644 --- a/site/public/docs/ja/intent.html +++ b/site/public/docs/ja/intent.html @@ -47,6 +47,7 @@ インテントルーティング プラグイン magpie に追加 + アプリ連携 リリース
@@ -316,6 +317,7 @@ The number of its kind (0 for none): インテントルーティング プラグイン magpie に追加 + アプリ連携 GitHub Discord リリース diff --git a/site/public/docs/ja/plugins.html b/site/public/docs/ja/plugins.html index 2df4a903..da4f462c 100644 --- a/site/public/docs/ja/plugins.html +++ b/site/public/docs/ja/plugins.html @@ -47,6 +47,7 @@ インテントルーティング プラグイン magpie に追加 + アプリ連携 リリース
@@ -707,6 +708,7 @@ magpie plugin options model-map '{"mapping": {"fast": "deepseek/deepseek-chat"}} インテントルーティング プラグイン magpie に追加 + アプリ連携 GitHub Discord リリース diff --git a/site/public/docs/ja/start.html b/site/public/docs/ja/start.html index 0fb4974c..c9e0f5fa 100644 --- a/site/public/docs/ja/start.html +++ b/site/public/docs/ja/start.html @@ -47,6 +47,7 @@ インテントルーティング プラグイン magpie に追加 + アプリ連携 リリース
@@ -271,6 +272,7 @@ magpie claude group/opus-anywhere # これを使う

インテントルーティング プラグイン magpie に追加 + アプリ連携 GitHub Discord リリース diff --git a/site/public/docs/plugins.html b/site/public/docs/plugins.html index 17726d21..2b5e62cb 100644 --- a/site/public/docs/plugins.html +++ b/site/public/docs/plugins.html @@ -47,6 +47,7 @@ Intent routing Plugins Add to magpie + Integrate Releases
@@ -707,6 +708,7 @@ magpie plugin options model-map '{"mapping": {"fast": "deepseek/deepseek-chat"}} Intent routing Plugins Add to magpie + Integrate GitHub Discord Releases diff --git a/site/public/docs/start.html b/site/public/docs/start.html index 8b924925..2d009a9f 100644 --- a/site/public/docs/start.html +++ b/site/public/docs/start.html @@ -47,6 +47,7 @@ Intent routing Plugins Add to magpie + Integrate Releases
@@ -271,6 +272,7 @@ magpie claude group/opus-anywhere # use it Intent routing Plugins Add to magpie + Integrate GitHub Discord Releases diff --git a/site/public/docs/zh/import.html b/site/public/docs/zh/import.html index 982ad33f..f2379084 100644 --- a/site/public/docs/zh/import.html +++ b/site/public/docs/zh/import.html @@ -47,6 +47,7 @@ 意图路由 插件开发 Add to magpie + 接入应用 版本发布
diff --git a/site/public/docs/zh/integrate.html b/site/public/docs/zh/integrate.html new file mode 100644 index 00000000..b340d4bf --- /dev/null +++ b/site/public/docs/zh/integrate.html @@ -0,0 +1,177 @@ + + + + + +接入你的应用 · magpie 文档 + + + + + + + + + + + + + + + + + + + + +
+ + +
+

文档 · 开发者

+

接入你的应用

+

写给 AI 应用、Agent 或客户端的开发者:想让自己的应用和 magpie 配合好,有三个层次,从 magpie 这边什么都不用改,到在 Agents 页面拥有自己的一行。

+ +
+ + + + +
你想要做法magpie 需要改动
应用的请求由 magpie 提供服务,并在用量里以自己的名字统计直接调用网关无
Agents 页面上的一行:自动检测、在那里选模型、断开时还原Agent 适配器一个 PR
新的模型来源(订阅、厂商),或改写请求插件无
+ +

1. 直接调用网关

+

magpie 在本机运行一个 LLM 网关。用户在 magpie 里有的所有模型(订阅、API key、本地模型、路由组)都以各自的 id 在那里提供,所以你的应用只需要一个供应商条目,而不是每个厂商一个。

+ +

找到它

+

网关监听 127.0.0.1:3425,或 magpie 的 settings.json 里 port 指定的端口(~/.config/magpie/settings.json,Windows 上是用户目录下的同一路径;设置了 $XDG_CONFIG_HOME 时为 $XDG_CONFIG_HOME/magpie)。GET /api/hello 在是 magpie 时返回 {"name":"magpie","version":"…"}。这个文件只读、不要写。magpie 需要在运行(应用本身或 magpie serve);找不到时,你的应用照常提供它自己的供应商即可。

+
+ Shell + +
curl -s http://127.0.0.1:3425/api/hello
+curl -s http://127.0.0.1:3425/v1/models -H "Authorization: Bearer magpie-acme"
+
+ +

端点

+

厂商本身支持你的 API 时请求原样转发,否则会被转换,流式、工具调用、图片和推理都包括在内。OpenAI 客户端的 base URL 是 http://127.0.0.1:<port>/v1,Anthropic 或 Gemini 客户端是 http://127.0.0.1:<port>。

+
+ + + + + + +
路径API
/v1/chat/completionsOpenAI Chat Completions
/v1/responsesOpenAI Responses
/v1/messages、/v1/messages/count_tokensAnthropic Messages
/v1beta/models/{model}:generateContent(以及 :streamGenerateContent)Google Gemini
/v1/models模型目录
+ +

用 key 标明你的应用

+

在本机,网关接受任意 key。发送 magpie-<你的应用 id>(Authorization: Bearer magpie-acme,或 x-api-key),每次调用都会在用量、请求记录以及按 Agent 匹配的路由规则里记为 acme。不带它时,magpie 按 User-Agent 的第一个词统计(Acme/1.4 (darwin) 记为 Acme);SDK 自带的 User-Agent(OpenAI/JS …、ai-sdk/…)会被记成那个 SDK。从另一台电脑访问时(设置 → 局域网共享),key 必须是用户的网关密钥之一,应用名就靠 User-Agent。

+ +

模型

+

GET /v1/models 列出用户打开的模型:id(provider/model,或路由组的名字,原样发送即可)、display_name、owned_by(供应商)、reasoning 与 supported_reasoning_levels([{"effort":"low"},…]),已知时还有 context_window、max_output_tokens,以及 magpie 知道是否支持图片时的 modalities。请从这里读取,而不是内置一份列表:用户会在 magpie 里增删供应商。推理强度用你所用 API 自己的字段传(reasoning_effort、reasoning.effort、Anthropic 的 thinking 或 output_config.effort)。?format=text 每行一个 id。

+ +

可选

+

在同一会话的请求里带上 X-Magpie-Session: <id>,GET /v1/magpie/route?session=<id> 就能在第一个 token 之前告诉你路由组为这一轮选了哪个模型、尝试过哪些后备(用 after=<seq>&wait=<s> 长轮询)。GET /v1/magpie/quotas 列出用户各订阅的额度。两者只回答本机,或带网关密钥的其他机器。细节见参考文档。

+ +
保留用户自己的供应商。把 magpie 作为又一个供应商(名为 Magpie)加在用户已有的供应商旁边,而不是替换它们,这样关掉 magpie 就只是换选另一个供应商。
+ +

2. 在 Agents 页面占一行

+

magpie 列出的 Agent(Claude Code、Codex、OpenCode、dsh、Alma、Cindy……)都是 internal/agent 里的适配器,每个一个文件。有了这一行,你的应用会显示自己的名字和图标,安装后自动出现,用户可以从 magpie 的目录里为它选模型(和推理强度),供应商变化时跟着更新,断开时还原你的应用原来的设置。目前没有运行时注册:这一行通过给 magpie 提 PR 加入,随下一个版本发布。

+

适配器是一个 Agent 值,形态取决于你的应用提供什么:

+
    +
  • magpie 编辑你的配置文件(大多数适配器,如 fx.go、empryo.go)。Dir、Path、Bin 用来检测应用;每个 Field(model、effort……)有 Get、Set、Options。连接时加入一个指向网关、key 为 magpie-<id> 的 magpie 供应商,并把模型设为 magpie 的模型;选回默认或 Unwire 会移除 magpie 的条目并还原原值。只动 magpie 设置的那些键。Notice 提示何时需要重启应用;Sync 更新你的应用保存在文件里的模型列表。
  • +
  • 你的应用只通过自己的导入链接接收供应商,由用户在你的应用里确认(cindy.go)。Import 返回这个链接(yourapp://provider/import?…,带网关地址、key magpie-<id> 和各端点),这一行的按钮会打开它,用户在你的应用里确认一次即可。Added 只读地检查你的应用是否已经有 magpie。magpie 不写你的任何文件。适合把供应商存在数据库里或加密保存的应用——这也最接近“检测到 magpie → 用户确认一次 → 完成接入”。
  • +
  • 你的应用运行时有本地 API(如 Alma):magpie 通过它把自己加为供应商并设置默认模型。
  • +
+

一个 PR 需要:适配器及其在 agents.go 里的注册;UA(你的 User-Agent 开头,小写),让用量认得你的调用;internal/gui/assets/icons 里的图标;在临时 HOME 下运行的测试(连接、切换、断开后原文件还原);参考文档 Agents 表里的一行。最有帮助的是一个稳定、有文档的配置格式或导入链接,以及它在各系统上的位置。

+ +

3. 插件

+

插件是 magpie 运行的 npm 包,由用户在 设置 → 插件 里或用 magpie plugin add <package> 安装。供应商插件(OpenCode 的 auth 钩子或 pi 扩展包)添加一个模型来源,比如 magpie 自己不登录的订阅。网关中间件在请求和回复经过时改写它们。见插件开发。插件不能在 Agents 页面加一行,也不能写别的应用的配置,所以它不是应用注册自己的方式。

+ +

目前没有的

+
    +
  • 没有让别的应用不经用户就把自己注册为 Agent、或安装插件的 API 或链接:插件由用户在 magpie 里安装,Agent 行来自 magpie 源码里的适配器。
  • +
  • magpie://import 链接添加的是供应商(模型来源及其 key),不是 Agent 或应用:见 Add to magpie。
  • +
+ +

有问题,或想先讨论一个适配器:提一个 issue,或来 Discord 聊。

+
+
+ + + + + + + diff --git a/site/public/docs/zh/intent.html b/site/public/docs/zh/intent.html index 6f7d8124..d8126cb5 100644 --- a/site/public/docs/zh/intent.html +++ b/site/public/docs/zh/intent.html @@ -47,6 +47,7 @@ 意图路由 插件开发 Add to magpie + 接入应用 版本发布
@@ -316,6 +317,7 @@ The number of its kind (0 for none): 意图路由 插件开发 Add to magpie + 接入应用 GitHub Discord 版本发布 diff --git a/site/public/docs/zh/plugins.html b/site/public/docs/zh/plugins.html index 0841580e..816dfec0 100644 --- a/site/public/docs/zh/plugins.html +++ b/site/public/docs/zh/plugins.html @@ -47,6 +47,7 @@ 意图路由 插件开发 Add to magpie + 接入应用 版本发布
@@ -707,6 +708,7 @@ magpie plugin options model-map '{"mapping": {"fast": "deepseek/deepseek-chat"}} 意图路由 插件开发 Add to magpie + 接入应用 GitHub Discord 版本发布 diff --git a/site/public/docs/zh/start.html b/site/public/docs/zh/start.html index 3b98da78..994fd767 100644 --- a/site/public/docs/zh/start.html +++ b/site/public/docs/zh/start.html @@ -47,6 +47,7 @@ 意图路由 插件开发 Add to magpie + 接入应用 版本发布
@@ -271,6 +272,7 @@ magpie claude group/opus-anywhere # 使用它 意图路由 插件开发 Add to magpie + 接入应用 GitHub Discord 版本发布