Documentation
¶
Overview ¶
Package plugins loads Agent Plugins 1.0.0 packages (https://agent-plugins.org).
This file validates a plugin's root plugin.json manifest under the spec's containment rules. It never makes a network request: the $schema value is only compared against the one recognized URL.
Index ¶
- Constants
- Variables
- func DataDir(cwd, name string) (string, error)
- func LegacyDataHint() string
- func LegacyDataRoot() string
- func ResolveInside(root, path string) (string, error)
- func Server(e MCPEntry, auth config.PluginServer, root, data string) (config.MCPServer, error)
- func Servers(l Loaded, cfg config.Plugin, cwd string, create bool) ([]config.MCPServer, error)
- func SkillSources(ls []Loaded) []skills.PluginSource
- func StoreName(plugin, module string) string
- func ValidName(s string) bool
- type DataKind
- type DataModule
- func (d *DataModule) Current() *DataVersion
- func (d *DataModule) LoadStored() (*DataVersion, error)
- func (d *DataModule) Rollback() error
- func (d *DataModule) RollbackTo(hash string) (*DataVersion, error)
- func (d *DataModule) Set(content []byte) (*DataVersion, error)
- func (d *DataModule) SetFile(path string) (*DataVersion, error)
- type DataVersion
- type HostFunc
- type Loaded
- type MCPConfig
- type MCPEntry
- type Manifest
- type ModuleStore
- func (s *ModuleStore) Current(module string) (string, error)
- func (s *ModuleStore) Meta(module, hash string) (*VersionMeta, error)
- func (s *ModuleStore) Modules() ([]string, error)
- func (s *ModuleStore) Pinned(module string) (Permissions, error)
- func (s *ModuleStore) Prune(module string, keep int) ([]string, error)
- func (s *ModuleStore) Put(module, ext string, data []byte, perms Permissions, manifest json.RawMessage) (string, error)
- func (s *ModuleStore) Read(module, hash string) ([]byte, *VersionMeta, error)
- func (s *ModuleStore) ReadCurrent(module string) ([]byte, *VersionMeta, error)
- func (s *ModuleStore) Rollback(module, hash string, taint Tainter) error
- func (s *ModuleStore) SetCurrent(module, hash string) error
- func (s *ModuleStore) SetSource(module, hash string) error
- func (s *ModuleStore) Source(module string) string
- func (s *ModuleStore) Versions(module string) ([]VersionMeta, error)
- type Permissions
- type RetryPolicy
- type SessionGrant
- type Tainter
- type VersionMeta
- type WasmDecl
- type WasmExport
- type WasmHost
- type WasmManifest
- type WasmModule
- func (m *WasmModule) Call(ctx context.Context, fn string, input []byte) (uint32, []byte, error)
- func (m *WasmModule) Close()
- func (m *WasmModule) Permissions() Permissions
- func (m *WasmModule) Swap(ctx context.Context, nm WasmManifest, wasm []byte) error
- func (m *WasmModule) SwapFile(ctx context.Context, nm WasmManifest, path string) error
- func (m *WasmModule) Version() string
- type WasmPool
- type WasmTools
Constants ¶
const DataRoot = ".tinyagent/plugin-data"
DataRoot is where plugins keep PLUGIN_DATA, relative to --cwd.
const DefaultKeep = 5
DefaultKeep is how many versions besides current Prune keeps.
const (
HostUserNamespace = "extism:host/user" // tinyagent-provided host functions
)
Namespaces a guest module may import from.
const MCPFile = "mcp.json"
MCPFile is the MCP configuration's name at the plugin root.
const MCPSchemaV1 = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json"
MCPSchemaV1 is the only mcp.json $schema value recognized.
const ManifestFile = "plugin.json"
ManifestFile is the manifest's name at the plugin root.
const MaxManifestBytes = 1 << 20
MaxManifestBytes caps how much of plugin.json is read.
const MaxWasmBytes = 64 << 20
MaxWasmBytes caps a module file's size.
const SchemaV1 = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json"
SchemaV1 is the only plugin.json $schema value recognized.
const SkillsDir = "skills"
SkillsDir is the plugin's skills directory, relative to the plugin root.
Variables ¶
var ErrPermission = errors.New("permission denied")
ErrPermission marks a load or swap refused because the module asks for more than it may have.
var ErrTainted = errors.New("session is tainted: module loads and swaps are refused")
ErrTainted marks a load or swap refused because the session is locked down after untrusted content entered it.
var ErrTampered = errors.New("stored module does not match its hash")
ErrTampered is returned when a stored version doesn't match its hash.
var ErrUnsupported = errors.New("unsupported transport")
ErrUnsupported marks an mcp.json entry whose transport tinyagent can't run (streamable-http and sse: remote MCP is not supported).
Functions ¶
func DataDir ¶
DataDir returns the plugin's persistent PLUGIN_DATA directory, ./.tinyagent/plugin-data/<name> inside cwd (issue #336). A location that would leave cwd (through a symlinked .tinyagent or plugin-data folder) is refused. It is not created here.
func LegacyDataHint ¶ added in v0.16.0
func LegacyDataHint() string
LegacyDataHint is the one-line stderr hint for LegacyDataRoot, or "".
func LegacyDataRoot ¶ added in v0.16.0
func LegacyDataRoot() string
LegacyDataRoot returns the old PLUGIN_DATA root (tinyagent/plugin-data under the user config directory) when it exists, else "". It is only stat'ed, for a one-line hint; nothing there is read, used or copied.
func ResolveInside ¶
ResolveInside resolves path through symlinks and returns it only when the result stays within the already-resolved root.
func Server ¶
Server maps an authorized stdio entry to a tinyagent MCP server definition: placeholders expanded once in args, env values and cwd, the mcp.json env set, and PLUGIN_ROOT and PLUGIN_DATA set last.
func Servers ¶
Servers returns the MCP server definitions the config authorizes for loaded plugin l (cfg is its config entry). A rejected plugin with authorized servers, a listed server that is missing, invalid or unsupported, or a disabled mcp.json is an error naming plugin and server. PLUGIN_DATA is ./.tinyagent/plugin-data/<name> inside cwd; with create set, that directory is created (0700).
func SkillSources ¶
func SkillSources(ls []Loaded) []skills.PluginSource
SkillSources returns the skills/ directory of each loaded plugin, in order.
Types ¶
type DataModule ¶
type DataModule struct {
Name string
Kind DataKind
Taint Tainter // optional; switches are refused once tainted
// Store, when set, keeps every version under StoreName; Set adds the
// version and makes it current.
Store *ModuleStore
StoreName string
// contains filtered or unexported fields
}
DataModule holds the active version of one data module.
func (*DataModule) Current ¶
func (d *DataModule) Current() *DataVersion
Current returns the active version, or nil before the first Set.
func (*DataModule) LoadStored ¶
func (d *DataModule) LoadStored() (*DataVersion, error)
LoadStored makes the store's verified current version active.
func (*DataModule) Rollback ¶
func (d *DataModule) Rollback() error
Rollback switches back to the previous version.
func (*DataModule) RollbackTo ¶
func (d *DataModule) RollbackTo(hash string) (*DataVersion, error)
RollbackTo moves the store's current pointer to an older hash and activates it; refused after taint.
func (*DataModule) Set ¶
func (d *DataModule) Set(content []byte) (*DataVersion, error)
Set validates content against the module's schema and atomically makes it the active version. Invalid content leaves the old version active.
func (*DataModule) SetFile ¶
func (d *DataModule) SetFile(path string) (*DataVersion, error)
SetFile is Set with content read from path.
type DataVersion ¶
type DataVersion struct {
Hash string // sha256 of Content, hex
Content []byte
Meta map[string]any // front-matter fields (prompt, skill)
Retry *RetryPolicy // retry only
}
DataVersion is one validated version of a data module.
type HostFunc ¶
type HostFunc = extism.HostFunction
HostFunc is a host function the caller may offer to modules.
type Loaded ¶
type Loaded struct {
Path string // the configured path
Manifest *Manifest
Err error
MCP *MCPConfig // nil when the plugin was rejected
}
Loaded is one configured plugin after loading. Err is set when the plugin was rejected; Manifest is set otherwise.
func Load ¶
Load loads every configured plugin in order. A rejected plugin is reported in its Loaded.Err and doesn't stop the others; two plugins with the same manifest name are an error, since names identify plugins.
func (Loaded) MCPWarnings ¶
func (l Loaded) MCPWarnings(auth []config.PluginServer) []string
MCPWarnings returns the non-fatal mcp.json problems of a loaded plugin: MCP disabled by a bad top-level file, and invalid or unsupported entries that aren't authorized (authorized ones fail in Servers instead).
type MCPConfig ¶
type MCPConfig struct {
Present bool
Err error
Digest string // SHA-256 of the file, hex
Entries []MCPEntry
}
MCPConfig is a plugin's parsed mcp.json. Present is false when the file doesn't exist; Err set means MCP is disabled for the plugin.
type MCPEntry ¶
type MCPEntry struct {
Name string
Type string
Err error
Command string
Args []string
Env map[string]string
Cwd string
}
MCPEntry is one mcp.json server. Err is set when the entry can't be started; the other fields hold the stdio definition before expansion.
type Manifest ¶
type Manifest struct {
Name string
Version string
Description string
Root string // filesystem-resolved plugin root
Extensions map[string]json.RawMessage
Warnings []string // non-fatal problems (unknown fields, bad extensions)
}
Manifest is a validated plugin.json.
func LoadManifest ¶
LoadManifest reads and validates <dir>/plugin.json. An error means the plugin is rejected; non-fatal problems are returned in Manifest.Warnings.
type ModuleStore ¶
ModuleStore is rooted at Dir.
func (*ModuleStore) Current ¶
func (s *ModuleStore) Current(module string) (string, error)
Current returns the active hash ("" with no error before any version).
func (*ModuleStore) Meta ¶
func (s *ModuleStore) Meta(module, hash string) (*VersionMeta, error)
Meta reads a version's sidecar.
func (*ModuleStore) Modules ¶
func (s *ModuleStore) Modules() ([]string, error)
Modules lists the stored modules.
func (*ModuleStore) Pinned ¶
func (s *ModuleStore) Pinned(module string) (Permissions, error)
Pinned returns the first load's permissions.
func (*ModuleStore) Prune ¶
func (s *ModuleStore) Prune(module string, keep int) ([]string, error)
Prune removes all but current and the keep newest other versions of a module, returning the removed hashes. Current is never removed.
func (*ModuleStore) Put ¶
func (s *ModuleStore) Put(module, ext string, data []byte, perms Permissions, manifest json.RawMessage) (string, error)
Put adds a version (a no-op when the hash is already stored) and returns its hash. It does not move current. The first Put of a module pins its permissions.
func (*ModuleStore) Read ¶
func (s *ModuleStore) Read(module, hash string) ([]byte, *VersionMeta, error)
Read returns a version's content after verifying its hash.
func (*ModuleStore) ReadCurrent ¶
func (s *ModuleStore) ReadCurrent(module string) ([]byte, *VersionMeta, error)
ReadCurrent reads and verifies the active version.
func (*ModuleStore) Rollback ¶
func (s *ModuleStore) Rollback(module, hash string, taint Tainter) error
Rollback points current at an older stored version. It is refused after taint, when the version's permissions are wider than the first load's, or when the version fails its hash check.
func (*ModuleStore) SetCurrent ¶
func (s *ModuleStore) SetCurrent(module, hash string) error
SetCurrent atomically points current at a stored hash.
func (*ModuleStore) SetSource ¶
func (s *ModuleStore) SetSource(module, hash string) error
SetSource records the hash last ingested from the plugin's own file.
func (*ModuleStore) Source ¶
func (s *ModuleStore) Source(module string) string
Source returns the hash last ingested from the plugin's own file.
func (*ModuleStore) Versions ¶
func (s *ModuleStore) Versions(module string) ([]VersionMeta, error)
Versions lists a module's versions, newest first.
type Permissions ¶
type Permissions struct {
HostFuncs []string `json:"host_functions,omitempty"`
Paths map[string]string `json:"allowed_paths,omitempty"` // host path -> guest path
Hosts []string `json:"allowed_hosts,omitempty"`
WASI bool `json:"wasi,omitempty"`
}
Permissions is a set of capabilities: what a caller grants, or what a module declares it needs.
type RetryPolicy ¶
type RetryPolicy struct {
MaxAttempts int `json:"max_attempts" toml:"max_attempts"`
BackoffMS int `json:"backoff_ms" toml:"backoff_ms"`
}
RetryPolicy is the retry data module's schema.
type SessionGrant ¶
type SessionGrant struct {
Root string
Hosts []string
CheckPath func(abs string, write bool) error // nil allows
Taint Tainter
}
SessionGrant derives what the session lets a module have. It is never wider than the session: tinyagent offers no host functions to modules; paths must resolve inside Root and pass CheckPath (the session's file_access rules); hosts must be listed in Hosts (the session's sandbox_allowed_domains, exact entries only); WASI itself grants no filesystem or network.
type Tainter ¶
type Tainter interface{ Tainted() bool }
Tainter reports whether the session is locked down (lockdown.State).
type VersionMeta ¶
type VersionMeta struct {
Hash string `json:"hash"`
Ext string `json:"ext"`
Manifest json.RawMessage `json:"manifest,omitempty"`
Permissions Permissions `json:"permissions"`
LoadedAt time.Time `json:"loaded_at"`
}
VersionMeta is a version's sidecar.
type WasmDecl ¶
type WasmDecl struct {
Name string `json:"name"`
File string `json:"file"`
Version string `json:"version"`
Exports []WasmExport `json:"exports"`
Requires Permissions `json:"requires"`
// Source and Lang declare a module built from Go source by TinyAgent
// (with TinyGo, an external, separately downloaded tool) instead of a
// prebuilt file: Source is a directory relative to the plugin root and
// Lang must be "go".
Source string `json:"source,omitempty"`
Lang string `json:"lang,omitempty"`
}
WasmDecl is one module declared in plugin.json.
type WasmExport ¶
WasmExport is one exported function offered as a tool.
type WasmHost ¶
type WasmHost struct {
Grant Permissions
Funcs []HostFunc // host functions the caller can offer, by name
Taint Tainter // optional
// contains filtered or unexported fields
}
WasmHost loads code modules for one caller.
func (*WasmHost) Load ¶
func (h *WasmHost) Load(ctx context.Context, m WasmManifest, wasm []byte) (*WasmModule, error)
Load loads the first version of a module. The manifest must be a subset of the host's grant; it is then pinned as the module's permission list.
func (*WasmHost) LoadFile ¶
func (h *WasmHost) LoadFile(ctx context.Context, m WasmManifest, path string) (*WasmModule, error)
LoadFile is Load with the module read from path.
type WasmManifest ¶
type WasmManifest struct {
Name string `json:"name"`
Version string `json:"version"`
Requires Permissions `json:"requires"`
}
WasmManifest describes one code module version.
type WasmModule ¶
type WasmModule struct {
// contains filtered or unexported fields
}
WasmModule is a swappable code module. Calls go to the current instance; Swap replaces it without blocking calls already running.
func (*WasmModule) Call ¶
Call runs an exported function on the current instance. A swap during the call doesn't affect it: it finishes on the instance it started on.
func (*WasmModule) Close ¶
func (m *WasmModule) Close()
Close tears down the current instance and unregisters the module.
func (*WasmModule) Permissions ¶
func (m *WasmModule) Permissions() Permissions
Permissions returns the permission list pinned at first load.
func (*WasmModule) Swap ¶
func (m *WasmModule) Swap(ctx context.Context, nm WasmManifest, wasm []byte) error
Swap replaces the module with a new version. The new manifest must stay within the permissions pinned at first load (and the host's grant). The new instance is built first; on any error the old one keeps running. The old instance closes once its in-flight calls finish.
func (*WasmModule) SwapFile ¶
func (m *WasmModule) SwapFile(ctx context.Context, nm WasmManifest, path string) error
SwapFile is Swap with the module read from path.
func (*WasmModule) Version ¶
func (m *WasmModule) Version() string
Version is the current version string.
type WasmPool ¶
type WasmPool struct {
// Store, when set, keeps every version of each module; activation loads
// the version its current pointer names (verifying its hash), and a
// changed plugin file is added as a new version and made current.
Store *ModuleStore
// Compile builds Go source files into a module (TinyGo under the OS
// sandbox). Modules declared with source need it and Store.
Compile func(ctx context.Context, files map[string][]byte) ([]byte, error)
// contains filtered or unexported fields
}
WasmPool keeps loaded code modules for the process. Activate loads them on first use and, on a later activation (an ACP session, a reload), swaps in a module whose file changed, under the permission list pinned at first load.
func (*WasmPool) Activate ¶
func (p *WasmPool) Activate(ctx context.Context, ls []Loaded, cfg []config.Plugin, g SessionGrant, w io.Writer) *WasmTools
Activate loads or refreshes every authorized module of the loaded plugins. A module that is refused is reported on w and skipped; the others still load.