Spaces:
Runtime error
Runtime error
File size: 6,556 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | # OmniRoute Plugin SDK
## Quick Start
```ts
import { definePlugin } from "omniroute/plugins/sdk";
export default definePlugin({
name: "my-plugin",
priority: 50,
onRequest: async (ctx) => {
console.log(`Request ${ctx.requestId} for ${ctx.model}`);
},
onResponse: async (ctx, response) => {
console.log(`Response for ${ctx.requestId}`);
return response;
},
onError: async (ctx, error) => {
console.error(`Error: ${error.message}`);
},
});
```
## API Reference
### `definePlugin(def: PluginDefinition): Plugin`
Factory function that creates a Plugin object with defaults.
**Parameters:**
- `name` (string, required) β Plugin name in kebab-case
- `priority` (number, optional, default: 100) β Lower runs first
- `enabled` (boolean, optional, default: true) β Start enabled?
- `onRequest` (function, optional) β Runs before chat handler
- `onResponse` (function, optional) β Runs after chat handler
- `onError` (function, optional) β Runs on handler error
### `blockRequest(response?): BlockingHookResult`
Block the request and optionally return a custom response.
```ts
onRequest: (ctx) => {
if (!ctx.headers["authorization"]) {
return blockRequest({ error: "Unauthorized", status: 401 });
}
};
```
### `modifyBody(body): PluginResult`
Modify the request body before it reaches the provider.
```ts
onRequest: (ctx) => {
return modifyBody({ ...ctx.body, temperature: 0.7 });
};
```
### `addMetadata(metadata): PluginResult`
Attach metadata to the request context.
```ts
onRequest: (ctx) => {
return addMetadata({ source: "my-plugin", version: "1.0.0" });
};
```
## Plugin Context (`PluginContext`)
| Field | Type | Description |
|---|---|---|
| `requestId` | `string` | Unique request identifier |
| `model` | `string` | Requested model name |
| `provider` | `string` | Target provider ID |
| `body` | `Record<string, unknown>` | Request body |
| `headers` | `Record<string, string>` | Request headers |
| `metadata` | `Record<string, unknown>` | Mutable metadata |
| `timestamp` | `number` | Request timestamp |
## Manifest (`plugin.json`)
```json
{
"name": "my-plugin",
"version": "1.0.0",
"description": "A sample plugin",
"author": "your-name",
"main": "index.js",
"hooks": {
"onRequest": { "enabled": true, "priority": 50 },
"onResponse": true,
"onError": false
},
"requires": {
"permissions": ["network", "file-read"]
},
"enabledByDefault": false,
"configSchema": {
"apiKey": { "type": "string", "description": "API key for external service" },
"maxRetries": { "type": "number", "min": 1, "max": 10, "default": 3 },
"debug": { "type": "boolean", "default": false },
"mode": { "type": "string", "enum": ["fast", "slow"], "default": "fast" }
}
}
```
### Hook Priority
Hooks can be configured with priority (lower = runs first):
```json
{
"hooks": {
"onRequest": { "enabled": true, "priority": 10 },
"onResponse": { "enabled": true, "priority": 100 }
}
}
```
Or as simple booleans (default priority 100):
```json
{
"hooks": {
"onRequest": true,
"onResponse": true
}
}
```
## Permission System
Plugins run in a sandboxed VM context. Access to external resources requires explicit permissions:
| Permission | Grants |
|---|---|
| `network` | `fetch`, `AbortController`, `Headers`, `Request`, `Response` |
| `file-read` | `fs.readFile`, `fs.readdir`, `fs.stat` |
| `file-write` | `fs.writeFile`, `fs.mkdir`, `fs.rm` |
| `env` | Read-only `process.env` proxy |
| `exec` | `child_process.exec`, `child_process.execSync` |
Without a permission, the corresponding globals are simply not available in the sandbox.
## Config Schema
Define configurable settings in `configSchema`:
```json
{
"configSchema": {
"apiKey": { "type": "string", "description": "External API key" },
"maxRetries": { "type": "number", "min": 1, "max": 10, "default": 3 },
"debug": { "type": "boolean", "default": false },
"mode": { "type": "string", "enum": ["fast", "slow"], "default": "fast" }
}
}
```
Field types: `string`, `number`, `boolean`, `select`
Field options: `default`, `min`, `max`, `enum`, `description`
Config values are persisted in the database and accessible via the dashboard config page.
## Built-in Events
| Event | When | Payload |
|---|---|---|
| `onRequest` | Before chat handler | Request context |
| `onResponse` | After chat handler | Response data |
| `onError` | On handler error | Error object |
| `onModelSelect` | Model selected for routing | Model info |
| `onComboResolve` | Combo routing resolved | Combo targets |
| `onRateLimit` | Rate limit hit | Limit info |
| `onQuotaExhaust` | Quota exhausted | Quota info |
| `onProviderError` | Provider returned error | Error details |
| `onStreamStart` | SSE stream started | Stream info |
| `onStreamEnd` | SSE stream ended | Stream stats |
| `onInstall` | Plugin installed | `{ name, version, manifest }` |
| `onActivate` | Plugin activated | `{ name, version, manifest }` |
| `onDeactivate` | Plugin deactivated | `{ name, version, manifest }` |
| `onUninstall` | Plugin uninstalled (before files deleted) | `{ name, version, manifest }` |
## Examples
### Request Logger
```ts
import { definePlugin } from "omniroute/plugins/sdk";
export default definePlugin({
name: "request-logger",
onRequest: async (ctx) => {
console.log(`[${new Date().toISOString()}] ${ctx.method} ${ctx.model} -> ${ctx.provider}`);
},
});
```
### Rate Limiter
```ts
import { definePlugin, blockRequest } from "omniroute/plugins/sdk";
const requests = new Map<string, number[]>();
export default definePlugin({
name: "rate-limiter",
priority: 10,
onRequest: async (ctx) => {
const key = ctx.headers["x-api-key"] || "anonymous";
const now = Date.now();
const window = 60000; // 1 minute
const maxRequests = 100;
const timestamps = (requests.get(key) || []).filter(t => t > now - window);
timestamps.push(now);
requests.set(key, timestamps);
if (timestamps.length > maxRequests) {
return blockRequest({ error: "Rate limit exceeded", status: 429 });
}
},
});
```
### Response Transformer
```ts
import { definePlugin } from "omniroute/plugins/sdk";
export default definePlugin({
name: "response-transformer",
onResponse: async (ctx, response) => {
if (response.choices) {
response.choices = response.choices.map((c: any) => ({
...c,
message: { ...c.message, content: c.message.content.trim() },
}));
}
return response;
},
});
```
|