← Back to PRs

#16558: feat(plugins): add sessions.spawn and rateLimit to plugin runtime

by Zephyr-Blessed open 2026-02-14 21:32 View on GitHub →
docs stale size: M
## Summary Exposes two new capabilities on the plugin runtime: ### 1. `api.runtime.sessions.spawn()` Plugins can spawn isolated agent sessions with restricted tool policies. This enables plugins to process external requests (webhooks, A2A messages, inter-agent communication) safely — the plugin controls which tools each session gets. ```ts const result = await api.runtime.sessions.spawn({ message: "Check my calendar for free slots this week", systemPrompt: "You are handling a request from a trusted friend's agent. Only use calendar tools.", toolPolicy: { allow: ["calendar", "web_search"], deny: ["exec", "write", "message"], }, timeoutSeconds: 60, label: "a2a-calendar-check", }); ``` Uses the existing subagent infrastructure (`callGateway` → `agent` handler). No new execution machinery — just exposing what `sessions_spawn` already does internally, but accessible to plugins. **Built-in safety guardrails:** - Max 10 concurrent plugin-spawned sessions - Max 20 spawns per minute (global across all plugins) - Existing `tools.subagents.tools.allow/deny` config applies to all spawned sessions ### 2. `api.runtime.rateLimit.check()` In-memory sliding-window rate limiter. Zero dependencies. Plugins provide the key (IP, sender URL, agent ID) and limits. ```ts if (!api.runtime.rateLimit.check(`ip:${remoteAddress}`, { maxRequests: 30, windowMs: 60_000 })) { return res.writeHead(429).end("Rate limited"); } ``` ### Use case: A2A (Agent-to-Agent) protocol We're building an [A2A plugin](https://github.com/Zephyr-Blessed/openclaw-a2a) that enables OpenClaw agents to communicate with other agents via Google's A2A protocol. A friend's agent can ask your agent to check your calendar and book a meeting — but a stranger's agent gets chat-only access with no tools. This requires plugins to be able to route external messages through the LLM with controlled tool access, which isn't currently possible. ### Discussion: Config gating? We considered adding a config toggle (e.g. `plugins.allowSessionSpawn: true`) but decided against it because: - No existing `PluginRuntime` method requires config opt-in - Plugins are treated as trusted code ("treat them as trusted code" per docs) - The existing `tools.subagents.tools` config already controls spawned session tool access - Plugin installation itself (`plugins.allow/deny`) is the trust gate **Question for maintainers**: Would you prefer a config gate here? We're happy to add one if the team feels it's warranted. The hardcoded concurrency/rate limits provide basic safety regardless. ### Files changed | File | Change | |------|--------| | `src/plugins/runtime/types.ts` | New types: `PluginSessionSpawnOptions`, `PluginSessionSpawnResult`, `RateLimitOptions` | | `src/plugins/runtime/index.ts` | Implementation: `spawnPluginSession`, `rateLimitCheck/Reset`, concurrency guards | | `src/plugin-sdk/index.ts` | Export new types | | `docs/tools/plugin.md` | Documentation with examples | | `src/plugins/runtime/rate-limit.test.ts` | Rate limiter tests | ### Note on tool policy override The current implementation passes `toolPolicy` via `sessions.patch` before spawning. If `sessions.patch` doesn't support `toolPolicy` yet, the session falls back to the default subagent tool policy (which already denies `sessions_spawn`, `gateway`, `cron`, `memory_*`, etc.). The `extraSystemPrompt` provides additional guidance to the LLM. A follow-up PR could add `toolPolicyOverride` to the `agent` gateway method for runtime-enforced per-session tool restrictions. --- *This PR is part of the [OpenClaw A2A plugin](https://github.com/Zephyr-Blessed/openclaw-a2a) project — enabling inter-agent communication via Google's A2A protocol.*

Most Similar PRs