Documentation
¶
Overview ¶
Package plugin runs OpenCode's provider plugins for magpie.
A subscription a vendor may object to being used outside its own app is not built into magpie: a plugin signs in to it and makes its requests, the way OpenCode's plugins do (opencode-gemini-auth and the like), and magpie runs those same plugins. They are npm packages (or local files) written against OpenCode's plugin API (@opencode-ai/plugin, v1): their auth hook gives the sign-in methods and a loader whose fetch carries the requests, their config and provider hooks the models. magpie runs them under Bun, downloaded the first time a plugin is added, in one process (host.js) it talks to over stdin and stdout.
What magpie keeps: plugins.json, the plugins and the config handed to them (OpenCode's, its provider section: a plugin's options); the npm packages under plugins/; plugin-auth.json, the sign-ins, in OpenCode's auth.json shape (so one can be moved between the two).
Index ¶
- Constants
- Variables
- func AuthPath() string
- func Auths(provider string) map[string]map[string]any
- func Bun(ctx context.Context) (string, error)
- func BunInUse() string
- func Call(ctx context.Context, method string, params, out any) error
- func CheckBun(ctx context.Context) (string, error)
- func Dir() string
- func Fetch(ctx context.Context, r FetchRequest) (*http.Response, error)
- func HasBun() bool
- func Icon(spec, id string) string
- func Import(ctx context.Context, provider string, auth map[string]any) (string, error)
- func Info(ctx context.Context, names []string) map[string]NPM
- func InfoCached(names []string) map[string]NPM
- func Installed(spec string) string
- func IsGit(spec string) bool
- func IsPath(spec string) bool
- func KeepBunUpdated(ctx context.Context)
- func KeepUpdated(ctx context.Context)
- func ListedAt() (time.Time, bool)
- func Name(spec string) string
- func Official(pkg string) bool
- func OnChange(f func())
- func OnSignIn(f func(provider, account, said string))
- func PackageName(spec string) string
- func Pinned(spec string) bool
- func ProviderOf(key string) string
- func RefreshMarket()
- func Refreshed()
- func ReloadInfo()
- func Remove(ctx context.Context, name string) error
- func Restart()
- func Restore(ctx context.Context, provider, key string, auth map[string]any) error
- func Running() bool
- func SetConfig(cfg map[string]any) error
- func SetOff(name string, off bool) error
- func Settle()
- func SignOut(ctx context.Context, provider, account string) error
- func SignedIn(provider string) bool
- func Take(ctx context.Context, provider string, keys []string) (map[string]map[string]any, error)
- func Target(spec string) string
- func Update(ctx context.Context) error
- func Upgrade(ctx context.Context, name string) error
- func UseCached(ps []Provider)
- func Validate(ctx context.Context, provider string, method int, key, value string) (string, error)
- func Version(spec string) string
- type Account
- type Authorization
- type Checked
- type Entry
- type FetchRequest
- type Hit
- type List
- type Listing
- type Loaded
- type Method
- type Model
- type NPM
- type Options
- type Page
- type Prompt
- type Provider
- type Saved
- type Updated
- type Updates
- type Usage
- type UsageResets
- type UsageWindow
- type VersionCheck
- type VersionChecks
- type Waiting
Constants ¶
const BunVersion = "1.4.2"
BunVersion is the Bun magpie downloads to run plugins with the first time one is needed, and the oldest it runs them on: newer releases are taken as they come (see CheckBun). Update bunSums below when it changes.
const MarketURL = "https://raw.githubusercontent.com/magpie-community/plugins/main/registry.json"
MarketURL is where the list is kept; MAGPIE_PLUGIN_MARKET moves it, and "off" keeps to the built-in copy.
const NewAccount = "new"
NewAccount is the account a sign-in goes to when it is a new one: the provider's own id while nothing is kept there. A sign-in to an account already signed in replaces that one's instead.
Variables ¶
var ErrFailed = errors.New("the sign-in failed")
ErrFailed is a sign-in the plugin says failed.
var ProxyFor func(provider, key string) string
ProxyFor is the proxy choice (netproxy.With's) of the provider's account at key, or of the provider for key "": set by the providers magpie keeps, which know them.
Functions ¶
func AuthPath ¶
func AuthPath() string
AuthPath is the plugins' sign-ins, OpenCode's auth.json in shape.
func Auths ¶ added in v0.1.506
Auths are provider's sign-ins as plugin-auth.json keeps them, by key.
func Bun ¶
Bun is the bun to run plugins with: $MAGPIE_BUN when set, else the one magpie downloaded and keeps up to date, downloading it now when there is none yet.
func BunInUse ¶ added in v0.1.585
func BunInUse() string
BunInUse is the version of the Bun plugins run on (or will, once it is downloaded): the newest magpie took, else BunVersion.
func CheckBun ¶ added in v0.1.585
CheckBun takes Bun's newest release when it is newer than the one in use, out two days and not set aside: downloaded, checked, tried, then switched to, the host restarted gracefully. It says the version taken, "" when none was.
func Fetch ¶
Fetch sends r through the provider's plugin — its loader's fetch, or Bun's own when it gives none — and streams back the reply.
func Icon ¶ added in v0.1.497
Icon is the icon the market gives the plugin spec, or else any listed plugin signing in to provider id; "" when none does. It never goes to the network: the list fetched last, else the cached copy, else the one built in.
func Import ¶ added in v0.1.506
Import keeps auth (a plugin-auth.json entry) as one more of provider's accounts — or, the same account as one kept already, in its place — and gives the account's key. The plugin's host is started for it: it alone writes the file while it runs.
func Info ¶ added in v0.1.489
Info is what npm says of each package, asked at most hourly: a few at a time, and for no longer than npmAll in all (or ctx). A package npm didn't answer for in time is what it said last, or missing when it never has; its answer, when it comes, is kept for the next time. A package npm doesn't have has no Version.
func InfoCached ¶ added in v0.1.615
InfoCached is what npm said last of each package it was asked of, however long ago, without asking again; a package never asked isn't in it.
func Installed ¶ added in v0.1.489
Installed is the version of the plugin spec installed, "" for a path or one not installed.
func IsGit ¶ added in v0.1.603
IsGit is whether spec names a git repository rather than an npm package or a path. The package bun installs from it is named by its own package.json, not by spec.
func IsPath ¶
IsPath is whether spec names a file or folder rather than a package, as OpenCode tells them apart.
func KeepBunUpdated ¶ added in v0.1.585
KeepBunUpdated looks for a newer Bun a little after magpie starts, then every updateEvery, while there are plugins to run on it.
func KeepUpdated ¶ added in v0.1.573
KeepUpdated looks for plugin updates a little after magpie starts, then every updateEvery, run by the magpie serving the gateway (one magpie, never two at once).
func ListedAt ¶ added in v0.1.552
ListedAt is when the plugins last listed their providers and models, as a built-in's list is dated by when it was fetched.
func Name ¶
Name is the package spec names, without its version: "@scope/x" of "@scope/x@1.2", the package installed from a git repository (the spec itself until it is), or the path.
func Official ¶ added in v0.1.573
Official is whether the package is the community's, magpie's own, which magpie keeps up to date by itself.
func OnChange ¶
func OnChange(f func())
OnChange registers f to be told when a plugin sign-in or the plugins change (a sign-in saved or refreshed, a plugin added).
func OnSignIn ¶ added in v0.1.547
func OnSignIn(f func(provider, account, said string))
OnSignIn registers f to be told what a plugin said, outside an answer, its account's sign-in is: "expired", "kept" or "renewed" (a models hook's error saying it).
func PackageName ¶ added in v0.1.506
PackageName is the npm package spec is: its name, or, for a plugin added from a folder or file (a checkout of it), the name its package.json gives.
func Pinned ¶ added in v0.1.573
Pinned is whether spec names a version (or a range or a tag other than latest): the user chose it, and it stays. A git one's version is its repository's, not npm's: it is never pinned, and never asked of npm.
func ProviderOf ¶ added in v0.1.500
ProviderOf is the provider an account key is one of.
func RefreshMarket ¶ added in v0.1.721
func RefreshMarket()
RefreshMarket has the next Market fetch the list again, as with the 「国内镜像」 switch just turned on; the one held is kept till then.
func Refreshed ¶ added in v0.1.591
func Refreshed()
Refreshed waits for Cached's refreshes in the background to end, the host left running: for tests that watch the providers' list on disk.
func ReloadInfo ¶ added in v0.1.615
func ReloadInfo()
ReloadInfo forgets what npm said, as kept in memory: the next ask reads it from disk again, as a magpie just started does.
func Restart ¶
func Restart()
Restart stops the host, so the next call starts one with the plugins as they are now. A host answering calls (a reply streaming, a sign-in waiting for its browser) finishes them first, while the calls made from now on go to the new one: a plugin updating never cuts a reply.
func Settle ¶
func Settle()
Settle waits for Cached's refreshes to end, then stops the host: for tests, whose folders the host runs in go when they end. Each ask is bounded and the retries are few, so this waits a bounded time even for a host that never answers.
func Take ¶ added in v0.1.506
Take gives provider's accounts named by keys (every one when there are none) and signs them out in one step, so the plugin renews none of their tokens after it gave them.
func Target ¶
Target is where the plugin is to load from: the installed package's folder, or the path.
func Update ¶
Update installs the version of each npm plugin its spec says now (latest, for the most part), and fetches each git one again.
func Upgrade ¶ added in v0.1.489
Upgrade installs the newest version of one plugin: npm's, or its git repository's commit now.
func UseCached ¶ added in v0.1.538
func UseCached(ps []Provider)
UseCached is for tests: Cached answers with ps, as though the plugins had just been asked, without Bun; nil forgets them.
Types ¶
type Account ¶ added in v0.1.500
type Account struct {
Key string `json:"key"`
Type string `json:"type"`
AccountID string `json:"accountId"`
// Hint tells an account with no id from another: the end of its key.
Hint string `json:"hint,omitempty"`
// Models are the ids of the provider's models this account has, when
// the provider has more than one account; none, it has them all.
Models []string `json:"models,omitempty"`
FellBack bool `json:"fellBack,omitempty"`
}
Account is one account a provider is signed in to: Key is where plugin-auth.json keeps it (the provider's id, else id#slot).
type Authorization ¶
type Authorization struct {
Session string `json:"session"`
URL string `json:"url"`
Instructions string `json:"instructions"`
Method string `json:"method"`
}
Authorization is an OAuth sign-in begun: the page to open, and whether the plugin waits for it itself ("auto") or needs the code the page shows pasted back ("code").
type Checked ¶ added in v0.1.552
type Checked struct {
Models []string `json:"models"`
Usage *Usage `json:"usage"`
Refused string `json:"refused"`
}
Checked is what trying an account gave: the model ids the plugin lists for it, its usage read (nil when the plugin tells none), and why its models hook said the vendor refused the sign-in, if it did.
func Check ¶ added in v0.1.506
Check tries one of provider's accounts as a request would — its auth loader, then its models as the plugin lists them for it — and reads its usage, which asks the vendor of the account itself. It fails when the plugin reached none of the places it asked (the vendor offline): a models hook falling back to a list it keeps proves nothing.
type Entry ¶
type Entry struct {
// Spec is how it was added: an npm package (name, name@version), a git
// repository (github:owner/repo, git+https://…) or a path to a file
// or folder.
Spec string `json:"spec"`
// Off is set on a plugin the user turned off.
Off bool `json:"off,omitempty"`
// Options are handed to the plugin as its second argument, as
// OpenCode's ["name", {options}] does.
Options map[string]any `json:"options,omitempty"`
}
Entry is one plugin the user added.
type FetchRequest ¶
type FetchRequest struct {
Provider string `json:"provider"`
Account string `json:"account,omitempty"` // the provider's first when ""
Model string `json:"model"`
NPM string `json:"npm"`
URL string `json:"url"`
Method string `json:"method"`
Headers map[string]string `json:"headers"`
Body []byte `json:"-"`
Session string `json:"session,omitempty"`
// Proxy is the provider's or the account's own proxy (netproxy.With):
// "direct", or its URL; "" follows magpie's. Fetch takes it from ctx
// when it isn't set.
Proxy string `json:"proxy,omitempty"`
}
FetchRequest is a request a provider's plugin makes.
type List ¶
type List struct {
Plugins []Entry `json:"plugins"`
// Config is OpenCode's config the plugins are handed: its provider
// section says what a plugin reads of it
// (provider.google.options.projectId).
Config map[string]any `json:"config,omitempty"`
}
List is plugins.json.
type Listing ¶ added in v0.1.489
type Listing struct {
Package string `json:"package"`
Name string `json:"name"`
Icon string `json:"icon,omitempty"`
Providers []string `json:"providers,omitempty"` // OpenCode's ids of those it signs in to
Community bool `json:"community,omitempty"` // written by magpie's community
Replaces string `json:"replaces,omitempty"` // the built-in subscription it does the work of
Summary map[string]string `json:"summary,omitempty"` // by language: en, zh
}
Listing is a plugin the market suggests.
type Method ¶
type Method struct {
Type string `json:"type"`
Label string `json:"label"`
// Placeholder is the hint an "api" method gives in its key's field
// (magpie's own field: OpenCode's says "API key")
Placeholder string `json:"placeholder,omitempty"`
}
Method is a way a plugin signs in: "oauth" (a browser, then a code pasted back or not) or "api" (a key).
type Model ¶
type Model struct {
ID string `json:"id"`
Name string `json:"name"`
NPM string `json:"npm"` // the AI SDK package it is spoken to with
URL string `json:"url"`
APIID string `json:"apiId"`
Context int `json:"context"`
Input int `json:"input"`
Output int `json:"output"`
Reasoning bool `json:"reasoning"`
Image bool `json:"image"`
Released string `json:"released"`
Variants []string `json:"variants"`
// Free is set by the plugin on a model the plan serves at no cost to
// its allowance (WorkBuddy's "credits": "x0.00")
Free bool `json:"free"`
// Rate is set by the plugin on a model whose price its vendor lists:
// the credits a request costs, as a multiple (Qoder's price_factor
// 0.5, WorkBuddy's "credits": "x0.03"), and RateWas the price before a
// discount running now. The plugin gives either as a number or as the
// vendor writes it ("x0.03"), on the model it lists (m.rate,
// m.rateWas); 0 is none.
Rate float64 `json:"rate"`
RateWas float64 `json:"rateWas"`
Cost *struct {
Input float64 `json:"input"`
Output float64 `json:"output"`
} `json:"cost"`
// ImageSaid is whether the plugin (or models.dev) said if it takes
// images: Image false without it is not known
ImageSaid bool `json:"imageSaid"`
}
Model is a model a plugin's provider serves, as OpenCode lists it.
type NPM ¶ added in v0.1.489
type NPM struct {
Version string `json:"version,omitempty"` // latest; none when npm has no such package
Description string `json:"description,omitempty"`
Publisher string `json:"publisher,omitempty"`
License string `json:"license,omitempty"`
Homepage string `json:"homepage,omitempty"`
Repository string `json:"repository,omitempty"`
Weekly int `json:"weekly"` // downloads last week
}
NPM is what npm says of a package now.
type Options ¶
type Options struct {
BaseURL string `json:"baseURL"`
APIKey string `json:"apiKey"`
Headers map[string]string `json:"headers"`
Fetch bool `json:"fetch"`
}
Options is what the provider's auth loader gave: where its requests go, the key the AI SDK would send, and whether it carries them itself.
type Prompt ¶
type Prompt struct {
Type string `json:"type"` // text, select
Key string `json:"key"`
Message string `json:"message"`
Placeholder string `json:"placeholder,omitempty"`
Options []struct {
Label string `json:"label"`
Value string `json:"value"`
Hint string `json:"hint,omitempty"`
} `json:"options,omitempty"`
}
Prompt is a question a sign-in method asks before it starts.
type Provider ¶
type Provider struct {
ID string `json:"id"` // OpenCode's: google, github-copilot
Spec string `json:"spec"` // the plugin
Name string `json:"name"`
NPM string `json:"npm"`
API string `json:"api"`
Methods []Method `json:"methods"`
// Icon is the picture the plugin gives the provider, as it said it:
// an https URL or a data:image URI (internal/provider keeps it)
Icon string `json:"icon,omitempty"`
// Usage says the plugin tells each account's allowance (auth.usage)
Usage bool `json:"usage"`
SignedIn bool `json:"signedIn"`
AuthType string `json:"authType"`
AccountID string `json:"accountId"`
Models []Model `json:"models"`
// FellBack says the plugin's models hook couldn't fetch its vendor's
// list and gave the default one back.
FellBack bool `json:"fellBack,omitempty"`
// Accounts are the accounts signed in to it, the one kept under its
// own id first; SignedIn, AuthType and AccountID are that one's.
Accounts []Account `json:"accounts"`
// MaxConcurrency is how many requests the plugin says each of its
// accounts takes at once (magpie's own field, which OpenCode ignores:
// the auth hook's maxConcurrency, else package.json's
// magpie.maxConcurrency); 0 for none said. The user's setting on the
// provider goes over it.
MaxConcurrency int `json:"maxConcurrency,omitempty"`
}
Provider is a provider a plugin signs in to.
type Saved ¶ added in v0.1.500
Saved is where a sign-in was kept: the provider (a plugin may sign in to another than asked) and the account's key.
type Updated ¶ added in v0.1.573
type Updated struct {
Package string `json:"package"`
From string `json:"from"`
To string `json:"to"`
At time.Time `json:"at"`
}
Updated is a plugin magpie updated by itself.
type Updates ¶ added in v0.1.573
type Updates struct {
Checked time.Time `json:"checked"`
// Waiting are the plugins with a newer version that magpie leaves to
// the reader: someone else's, or one pinned to a version.
Waiting []Waiting `json:"waiting"`
// Updated are the plugins magpie updated by itself, the latest last.
Updated []Updated `json:"updated"`
}
Updates is what magpie's last look at npm found for the plugins.
func CheckUpdates ¶ added in v0.1.573
CheckUpdates asks npm for each plugin's newest version, updates the community's (unpinned, switched on) to it and notes the others' as waiting. The plugins updated are loaded again, a reply streaming through the old ones finishing first.
func PendingUpdates ¶ added in v0.1.573
func PendingUpdates() Updates
PendingUpdates is what the last look found, less what has changed since: a plugin updated, removed or switched off since waits no more.
type Usage ¶ added in v0.1.514
type Usage struct {
Plan string `json:"plan"`
Until string `json:"until"` // RFC 3339, "" when not told
Renew string `json:"renew"`
Balance string `json:"balance"`
Error string `json:"error"`
User string `json:"user"`
SignIn string `json:"signIn"` // "expired", "kept", "renewed" or ""
Windows []UsageWindow `json:"windows"`
Resets *UsageResets `json:"resets"`
}
Usage is how much of its allowance one account has used, as the plugin's auth.usage tells it (host.js has the shape).
type UsageResets ¶ added in v0.1.514
type UsageResets struct {
Count int `json:"count"`
Until string `json:"until"`
ByWindow bool `json:"byWindow"`
FiveHour int `json:"fiveHour"`
Weekly int `json:"weekly"`
}
UsageResets are the rate-limit resets an account may spend.
type UsageWindow ¶ added in v0.1.514
type UsageWindow struct {
Name string `json:"name"`
Used float64 `json:"used"` // percent
ResetsAt string `json:"resetsAt"` // RFC 3339
ResetSecs int64 `json:"resetSecs"`
Display string `json:"display"`
Span float64 `json:"span"` // seconds
Model string `json:"model"`
Models []string `json:"models"`
NotModels []string `json:"notModels"`
Aside bool `json:"aside"`
}
type VersionCheck ¶ added in v0.1.663
type VersionCheck struct {
Spec string `json:"spec"`
Package string `json:"package"`
Version string `json:"version"` // installed
Latest string `json:"latest,omitempty"` // npm's newest, when it answered
// Status is "update" (npm has a newer version), "current", "unknown"
// (npm didn't say: Why and Error say why), or "git" or "folder" for
// one npm has no versions of
Status string `json:"status"`
// Why is why npm didn't say: "offline" (not reached), "limited" (too
// many requests), "registry" (it answered with an error) or "missing"
// (it has no such package)
Why string `json:"why,omitempty"`
Error string `json:"error,omitempty"`
// Auto is whether magpie updates it by itself (the community's,
// unpinned, switched on), so an update found would come anyway
Auto bool `json:"auto"`
Off bool `json:"off"`
}
VersionCheck is what asking npm now found of one installed plugin.
type VersionChecks ¶ added in v0.1.663
type VersionChecks struct {
At time.Time `json:"at"`
Plugins []VersionCheck `json:"plugins"`
}
VersionChecks is what a check asked now found.
func CheckNow ¶ added in v0.1.663
func CheckNow(ctx context.Context) VersionChecks
CheckNow asks npm now, not what it said within the hour, for the newest version of each installed plugin, for the reader's Check for updates. Nothing is installed: what it finds is updated as any update is, with Upgrade. What npm says is kept, as Info keeps it, and the updates found for the reader (someone else's, or pinned) wait for them as the background look's do, putting the dot on Plugins.