Commit Graph
8 Commits
Author SHA1 Message Date
yetone df95ac6bc2 docs, site: Integrating your app or agent with magpie, at docs/integrating.md and usemagpie.ai/docs/integrate (#918, Magixyne)
A developer of an AI app asked how to work with magpie and whether an app can
register itself after one confirmation. The page says what exists: the
gateway (find it via /api/hello and settings.json's port, the OpenAI,
Anthropic, Responses and Gemini endpoints, /v1/models' fields), how a key
magpie-<id> or the User-Agent's first word names the app in Usage, a row on
the Agents page by an adapter PR in internal/agent (config-edit, Cindy-style
own import link confirmed in the app, or a local API) with what the PR needs,
what plugins can and can't do, and what isn't there: no link or API registers
an app or installs a plugin, and magpie://import adds providers only. English
and Chinese pages, linked from every docs page's nav and footer.
TestThirdPartyAppIsCountedAsItself pins the attribution the page promises.
go vet and the gateway tests pass; site node tests pass; pages checked in
headless Chromium (no errors, TOC, no horizontal scroll at 390px).
2026-10-05 22:46:35 +08:00
yetone 2f135ed4d5 plugin, gui, docs: Plugins says which plugins are providers and which are middleware, lists the community's ready-made middleware, and edits a middleware's options in its row (the owner) — the Plugins page still read as if every plugin were a subscription, and nothing showed what a middleware does or let you set its options without editing plugins.json. Every Discover card and Installed row now carries a Provider or Middleware chip (both for a plugin that is both), also for one that is off (isMiddleware/middlewareOnly from the server, read from its files); Discover splits into Subscriptions and Gateway middleware ("runs in magpie's gateway on what every agent sends and gets back, whichever provider serves it"), the latter from market entries with "kind": "middleware" and no providers or icon (the built-in market.json lists the five new @magpie-community/middleware-* packages: param-override, model-map, system-prompt, word-guard, think-tags, mostly New API's channel settings with the same JSON). A middleware row has Options: a JSON editor in the row, starting from the package's magpie.options example when none are set, which validates it is an object, saves (POST /api/plugins/options) for the next request, clears, and cancels with Esc. magpie plugin options takes a short name (model-map for @magpie-community/middleware-model-map; plugin.ShortName, also in SetOptions). en/zh/ja/de. Docs: usemagpie.ai/docs/plugins (en/zh/ja) gains Ready-made middleware and Options and the registry's kind; reference.md, both READMEs and docs/subsystems/gateway-middleware.md likewise. Tested with a real DeepSeek account and real Claude Code through magpie web --gateway in a sandbox HOME, with all five installed and options set by short name: a mapped model named back, max_tokens capped, a prompt appended for claude only, word-guard's 400 and param-override's 403 in the agent's shape, <think> stripped from Chat and Responses streams and a whole Anthropic reply, reasoning_content moved into the text; /api/plugins showed the kinds and the example. TestSetOptionsShortName is new; TestBuiltinMarket checks a middleware entry has no providers or icon and no other kind. plugin-middleware.test.cjs (Chromium and WebKit, en and zh: the chips, Discover's two sections, the options editor with its errors, no select, no scroll, no left border) fails without the change; the other plugin tests and click-scroll pass in WebKit (plugin-market's section name updated; plugin-move fails only under parallel load and passes alone). go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass. 2026-10-05 20:50:09 +08:00
yetone eebd0b4222 plugin, gateway, gui: a plugin can be gateway middleware — onRequest, onEvent and onResponse run in magpie's gateway on what agents send and get back (moejs) — a plugin could only be a subscription provider, run in the Bun host, a process away from the gateway. A plugin may now declare middleware (package.json magpie.middleware, or a *.middleware.js / .mjs file), run in-process by moejs (pure-Go JS engine): compiled once, one runtime per request from a pool, so every hook of a request shares ctx.state. onRequest(body, ctx) sees the agent's body in its own API before routing; what it returns is the body the next middleware and the gateway get, undefined leaves the bytes as they were, ctx.reject(status, msg) answers with an error in the agent's API's shape. onEvent(ev, ctx) sees each SSE event's JSON (export const events = [...] filters by name; an object changes it, null drops it, undefined passes the bytes through untouched; data: [DONE] is no JSON and passes by). onResponse(body, ctx) sees a whole JSON reply, with ctx.status. ctx has protocol, model, stream, path, agent, the plugin's options and state. A hook that throws, returns a non-object or runs past its limit (250ms request/response, 50ms an event, 1s load; interrupted) leaves the request or reply as it was and is counted and logged (60 lines a minute); a compressed reply passes as-is. Files are reloaded within a second of a change. Only agents' requests run through it (serveAgent at the gateway's agent entry points and the Codex backend), never magpie's own titles, classifier or stand-ins; it sees bodies before redaction. A middleware-only package is skipped by the Bun host. The Plugins page marks a middleware with a chip, its hooks, calls and µs per call (JSON in and out counted), failures in red with the last error, and a load error. en/zh/ja/de; docs/reference.md and usemagpie.ai/docs/plugins#middleware (en/zh/ja) with an alias example. Tested with a real DeepSeek account through magpie web --gateway in a sandbox HOME: an alias middleware served "fast" and named it in message_start, a reject came back as 403 permission_error, a Chat stream uppercased; real Claude Code (sandbox CLAUDE_CONFIG_DIR) did Read, Bash and Glob tool turns through three middlewares with 0 failures: ≈1–1.6µs an event, 0.2–0.7ms an onRequest that parses and rewrites Claude Code's ≈80KB body. Real use found two bugs fixed here: [DONE] parsed as JSON (SyntaxError on every Chat stream) and stats leaving out the JSON time. internal/middleware tests (chain, undefined keeps bytes, reject, fail-open on throw/spin/string with the runtime reused, async hook, load errors, off and Bun skip, reload, split/CRLF/filtered/dropped stream events, [DONE] untouched, whole reply and gzip, 64 in parallel; BenchmarkEvent ≈0.9µs, 11 allocs) and TestMiddlewareThroughGateway (alias routed, events by protocol, redaction still upstream, reject in Anthropic's shape; fails without the change) are new; plugin-middleware.test.cjs (Chromium and WebKit, en and zh: chip, hooks and stats, failures with last error, broken and off, no left border) fails without it. The other plugin GUI tests and click-scroll pass in WebKit. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass (internal/provider failed once under load and passes alone). 2026-10-05 19:14:31 +08:00
yetone c8278a8691 docs: plugins are OpenCode's provider plugins or pi's packages — the Plugins page's intro, magpie plugin's help, the README and the plugin docs (en, zh, ja) said OpenCode only, though pi packages that register a provider run since v0.1.772; the docs gain a pi packages section (what makes a package pi's, what is loaded and left alone, sign-in through onPrompt/onAuth and ctx.ui, pi's files under <config>/pi or PI_CODING_AGENT_DIR, Anthropic Messages requests), the pi-package search and a FAQ entry 2026-10-04 03:10:09 +08:00
yetone 8f385e113b site: usemagpie.ai draws itself in Omarchy's look on Omarchy, in the theme Omarchy has on (owner: 整个官网和文档页面能否智能识别是不是 Omarchy 在访问,如果是 Omarchy 在访问,那么整个页面风格能否变成 Omarchy 风格?而且能够适配当前 Omarchy 就更牛逼了) — every page (home, /import, the docs in en/zh/ja) loads omarchy.js in a Linux desktop browser only; it tells Omarchy by its font (a page may load local("omarchy"), which Omarchy installs system-wide and nothing else has), remembers it, and from then on paints before the page shows: the theme's palette, the system monospace (Omarchy's font), square corners, no shadows or glass, a solid bar, buttons and what's chosen in the accent, images framed in it. Until magpie tells the theme it takes Omarchy's default (tokyo-night, or catppuccin-latte on a light desktop). magpie's gateway answers GET /v1/magpie/omarchy (name, mode, stamp and the CSS variables magpie's own windows use) to this machine only, readable only by usemagpie.ai (CORS + Private Network Access; MAGPIE_SITE_ORIGIN adds an origin to try the site locally), 404 off Omarchy. The page asks it by itself only once the browser allows it to reach this computer; a chip in the corner (Omarchy's logo and the theme) asks once on a click, lists the 22 built-in themes to pick one, and turns the look off; ?omarchy=1|0|<theme> sets it anywhere. Followed while the page shows: a theme set in Omarchy's menu comes through in about 3 s. Tried in the omarchy VM's Chromium 152 with this magpie (nogui serve): detection, the home page and zh docs in tokyo-night, the chip's menu, following the computer, and omarchy-theme-set catppuccin-latte repainting the open page light. TestOmarchyThemeForTheSite covers 404 off Omarchy, the theme and its CORS for usemagpie.ai only, LAN refused and the preflight. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. The permission prompt from the public site wasn't clicked through in a real browser. 2026-10-03 16:01:53 +08:00
yetone 3c79152eb4 site: docs in Japanese (/docs/ja), and contents that work on a phone (owner: 文档也要支持日语,另外,文档要有友好的目录,在手机端也要有友好的目录) — /docs/ja/{start,intent,plugins,import} translate the English pages; every docs page gets the home page's language menu (English / 中文 / 日本語, the lang cookie) and a ja hreflang, /docs/ja opens the guide, and /ja/'s docs links go to the Japanese pages. docs.js (shared, replacing each page's inline scrollspy) builds the contents: every docs page, the current one's sections under it, the section being read marked with a pill (no left border); the list is sticky and scrolls on its own. Under 900px, where the contents were simply hidden (and under 600px the nav links too, so a phone had no way around the docs), a bar under the nav names the section being read and opens the contents as a menu that closes on a pick, a tap outside or Escape. The nav links give way to the contents under 1000px, long inline code wraps under 1100px, and .doc keeps .wrap's side padding (601-1168px ran the text to the screen's edge). node --test worker.test.mjs passes (/docs/ja redirect added); WebKit at 320-1280, light and dark, en/zh/ja: nothing scrolls sideways, the menu opens, jumps and closes, the bar follows the reading position. 2026-10-03 11:26:23 +08:00
yetone f0e4a79c06 plugins: auth.refresh — magpie renews a plugin's sign-ins before they run out, once per account at a time (owner: 按你建议的优先级,先做 1 和 2, from the pi plugin study) — each community plugin renewed its own tokens inside fetch, deduping by hand (factory's "two refreshes would spend it twice", minimax's renewing, cline's REFRESH_LEAD, workbuddy's EARLY_MS). A plugin can now give auth.refresh(auth, provider), returning the fields to keep over the old sign-in, and optionally auth.refreshLead (ms, 5 minutes by default). Before an account's loader options, provider.models and auth.usage, the host renews an OAuth account whose expires is that close: requests that find it due share one renewal (vendors that spend a refresh token once never see it twice), waiting up to 15s, and a renewal that takes longer is still saved when it ends (pending keeps the host up). What it gives is merged over the account and saved through setAuth, which clears the loader caches here and in Go, and the account is said renewed; a sign-in replaced or removed meanwhile stands. A throw leaves the account as it was and the request goes with the old token; signIn: "expired" on it marks the account and it isn't tried again until signed in again, any other error is retried after 30s. OpenCode ignores the hook, so plugins keep their in-fetch check for it. Documented in /docs/plugins (#renew, en and zh). TestPluginRenewsSignIns fails without the host change (no renewal). go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... under a temp HOME pass. 2026-10-03 03:08:15 +08:00
yetone a8309d5ca4 site: a plugin developer guide at /docs/plugins and /docs/zh/plugins — how magpie runs OpenCode plugins, the hooks it calls (config, auth methods and prompts, loader and fetch, provider.models, chat.headers, magpie's auth.usage), the API each AI SDK package maps to, accounts and their scope, X-Magpie-Sign-In, provider ids, testing in a sandbox, publishing and the registry, and the host protocol. The Acme example on it was run against v0.1.676 with a stand-in API (plugin add, login, provider test, quota). Every docs page links it; inline code wraps on phones so no page scrolls sideways. 2026-10-03 01:59:45 +08:00