@radaros/transport 0.3.12 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/index.d.ts +52 -3
- package/dist/index.js +253 -7
- package/package.json +17 -2
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @radaros/transport
|
|
2
|
+
|
|
3
|
+
HTTP and WebSocket transport layer for deploying RadarOS agents as APIs.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @radaros/transport
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import express from "express";
|
|
15
|
+
import { Agent, openai } from "@radaros/core";
|
|
16
|
+
import { createAgentRouter } from "@radaros/transport";
|
|
17
|
+
|
|
18
|
+
const app = express();
|
|
19
|
+
app.use(express.json());
|
|
20
|
+
|
|
21
|
+
const agent = new Agent({
|
|
22
|
+
name: "assistant",
|
|
23
|
+
model: openai("gpt-4o"),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
app.use("/api", createAgentRouter({ agents: { assistant: agent } }));
|
|
27
|
+
app.listen(3000);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- **Express Router** — REST API with streaming support
|
|
33
|
+
- **Socket.IO Gateway** — Real-time WebSocket communication
|
|
34
|
+
- **A2A Server** — Agent-to-Agent protocol support
|
|
35
|
+
- **CORS & Rate Limiting** — Built-in security middleware
|
|
36
|
+
- **Swagger** — Auto-generated API documentation
|
|
37
|
+
- **File Upload** — Multipart form data support
|
|
38
|
+
|
|
39
|
+
## Documentation
|
|
40
|
+
|
|
41
|
+
Full docs at [radaros.mintlify.dev](https://radaros.mintlify.dev)
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Agent, A2AAgentCard, Team, Workflow, EventBus, VoiceAgent } from '@radaros/core';
|
|
1
|
+
import { Agent, A2AAgentCard, Registry, Servable, Team, Workflow, EventBus, VoiceAgent } from '@radaros/core';
|
|
2
2
|
|
|
3
3
|
interface A2AServerOptions {
|
|
4
4
|
agents: Record<string, Agent>;
|
|
@@ -42,8 +42,12 @@ interface FileUploadOptions {
|
|
|
42
42
|
declare function createFileUploadMiddleware(opts?: FileUploadOptions): any;
|
|
43
43
|
declare function buildMultiModalInput(body: any, files?: any[]): string | any[];
|
|
44
44
|
|
|
45
|
-
declare function errorHandler(
|
|
46
|
-
|
|
45
|
+
declare function errorHandler(options?: {
|
|
46
|
+
logger?: Pick<Console, "error">;
|
|
47
|
+
}): (err: any, _req: any, res: any, _next: any) => void;
|
|
48
|
+
declare function requestLogger(options?: {
|
|
49
|
+
logger?: Pick<Console, "log">;
|
|
50
|
+
}): (req: any, _res: any, next: any) => void;
|
|
47
51
|
|
|
48
52
|
interface SwaggerOptions {
|
|
49
53
|
/** Enable Swagger UI at /docs. Default: false */
|
|
@@ -67,6 +71,24 @@ interface SwaggerOptions {
|
|
|
67
71
|
specPath?: string;
|
|
68
72
|
}
|
|
69
73
|
interface RouterOptions {
|
|
74
|
+
/**
|
|
75
|
+
* Use a Registry for live auto-discovery. The router creates dynamic routes
|
|
76
|
+
* that resolve agents/teams/workflows at request time — any instance created
|
|
77
|
+
* after the router is mounted is automatically available.
|
|
78
|
+
*
|
|
79
|
+
* When omitted, falls back to the global registry from `@radaros/core`.
|
|
80
|
+
* Pass `false` to disable registry-based routing entirely (use explicit maps only).
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* createAgentRouter({ cors: true });
|
|
84
|
+
* new Agent({ name: "bot", model: openai("gpt-4o") }); // immediately routable
|
|
85
|
+
*/
|
|
86
|
+
registry?: Registry | false;
|
|
87
|
+
/**
|
|
88
|
+
* Auto-discover agents, teams, and workflows from a mixed array.
|
|
89
|
+
* Each item is classified by its `.kind` and keyed by `.name`.
|
|
90
|
+
*/
|
|
91
|
+
serve?: Servable[];
|
|
70
92
|
agents?: Record<string, Agent>;
|
|
71
93
|
teams?: Record<string, Team>;
|
|
72
94
|
workflows?: Record<string, Workflow<any>>;
|
|
@@ -75,6 +97,13 @@ interface RouterOptions {
|
|
|
75
97
|
swagger?: SwaggerOptions;
|
|
76
98
|
/** File upload configuration for multi-modal inputs */
|
|
77
99
|
fileUpload?: boolean | FileUploadOptions;
|
|
100
|
+
/** CORS configuration. Pass true or '*' for permissive, a string for a single origin, or an array for multiple origins. */
|
|
101
|
+
cors?: string | string[] | boolean;
|
|
102
|
+
/** Rate limiting configuration. Pass true for defaults (100 req/min), or an object to customize. */
|
|
103
|
+
rateLimit?: {
|
|
104
|
+
windowMs?: number;
|
|
105
|
+
max?: number;
|
|
106
|
+
} | boolean;
|
|
78
107
|
}
|
|
79
108
|
|
|
80
109
|
declare function createAgentRouter(opts: RouterOptions): any;
|
|
@@ -164,11 +193,31 @@ interface BrowserGatewayOptions {
|
|
|
164
193
|
declare function createBrowserGateway(opts: BrowserGatewayOptions): void;
|
|
165
194
|
|
|
166
195
|
interface GatewayOptions {
|
|
196
|
+
/**
|
|
197
|
+
* Use a Registry for live auto-discovery. The gateway resolves agents/teams
|
|
198
|
+
* at event time — any instance created after the gateway starts is automatically
|
|
199
|
+
* reachable.
|
|
200
|
+
*
|
|
201
|
+
* When omitted, falls back to the global registry from `@radaros/core`.
|
|
202
|
+
* Pass `false` to disable registry-based lookup (use explicit maps only).
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* createAgentGateway({ io });
|
|
206
|
+
* new Agent({ name: "bot", model: openai("gpt-4o") }); // immediately reachable
|
|
207
|
+
*/
|
|
208
|
+
registry?: Registry | false;
|
|
209
|
+
/**
|
|
210
|
+
* Auto-discover agents and teams from a mixed array.
|
|
211
|
+
* Each item is classified by its `.kind` and keyed by `.name`.
|
|
212
|
+
*/
|
|
213
|
+
serve?: Servable[];
|
|
167
214
|
agents?: Record<string, Agent>;
|
|
168
215
|
teams?: Record<string, Team>;
|
|
169
216
|
io: any;
|
|
170
217
|
namespace?: string;
|
|
171
218
|
authMiddleware?: (socket: any, next: (err?: Error) => void) => void;
|
|
219
|
+
/** Max requests per minute per socket. Default: 60 */
|
|
220
|
+
maxRequestsPerMinute?: number;
|
|
172
221
|
}
|
|
173
222
|
|
|
174
223
|
declare function createAgentGateway(opts: GatewayOptions): void;
|
package/dist/index.js
CHANGED
|
@@ -412,23 +412,26 @@ function buildMultiModalInput(body, files) {
|
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
// src/express/middleware.ts
|
|
415
|
-
function errorHandler() {
|
|
415
|
+
function errorHandler(options) {
|
|
416
|
+
const log = options?.logger ?? console;
|
|
416
417
|
return (err, _req, res, _next) => {
|
|
417
|
-
|
|
418
|
+
log.error("[radaros:transport] Error:", err.message);
|
|
418
419
|
res.status(err.statusCode ?? 500).json({
|
|
419
420
|
error: err.message ?? "Internal server error"
|
|
420
421
|
});
|
|
421
422
|
};
|
|
422
423
|
}
|
|
423
|
-
function requestLogger() {
|
|
424
|
+
function requestLogger(options) {
|
|
425
|
+
const log = options?.logger ?? console;
|
|
424
426
|
return (req, _res, next) => {
|
|
425
|
-
|
|
427
|
+
log.log(`[radaros:transport] ${req.method} ${req.path}`);
|
|
426
428
|
next();
|
|
427
429
|
};
|
|
428
430
|
}
|
|
429
431
|
|
|
430
432
|
// src/express/router-factory.ts
|
|
431
433
|
import { createRequire as createRequire4 } from "module";
|
|
434
|
+
import { classifyServables, registry as globalRegistry } from "@radaros/core";
|
|
432
435
|
|
|
433
436
|
// src/express/swagger.ts
|
|
434
437
|
import { createRequire as createRequire3 } from "module";
|
|
@@ -873,6 +876,53 @@ function serveSwaggerUI(spec) {
|
|
|
873
876
|
|
|
874
877
|
// src/express/router-factory.ts
|
|
875
878
|
var _require4 = createRequire4(import.meta.url);
|
|
879
|
+
function corsMiddleware(origins) {
|
|
880
|
+
return (req, res, next) => {
|
|
881
|
+
const origin = req.headers.origin;
|
|
882
|
+
let allowed = false;
|
|
883
|
+
if (origins === true || origins === "*") {
|
|
884
|
+
allowed = true;
|
|
885
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
886
|
+
} else if (typeof origins === "string") {
|
|
887
|
+
allowed = origin === origins;
|
|
888
|
+
if (allowed) res.setHeader("Access-Control-Allow-Origin", origin);
|
|
889
|
+
} else if (Array.isArray(origins)) {
|
|
890
|
+
allowed = origins.includes(origin);
|
|
891
|
+
if (allowed) res.setHeader("Access-Control-Allow-Origin", origin);
|
|
892
|
+
}
|
|
893
|
+
if (allowed) {
|
|
894
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
895
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key");
|
|
896
|
+
res.setHeader("Access-Control-Max-Age", "86400");
|
|
897
|
+
}
|
|
898
|
+
if (req.method === "OPTIONS") {
|
|
899
|
+
res.status(204).end();
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
next();
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
function rateLimitMiddleware(config = {}) {
|
|
906
|
+
const windowMs = config.windowMs ?? 6e4;
|
|
907
|
+
const max = config.max ?? 100;
|
|
908
|
+
const hits = /* @__PURE__ */ new Map();
|
|
909
|
+
return (req, res, next) => {
|
|
910
|
+
const key = req.ip ?? req.socket?.remoteAddress ?? "unknown";
|
|
911
|
+
const now = Date.now();
|
|
912
|
+
const record = hits.get(key);
|
|
913
|
+
if (!record || now > record.resetTime) {
|
|
914
|
+
hits.set(key, { count: 1, resetTime: now + windowMs });
|
|
915
|
+
next();
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
record.count++;
|
|
919
|
+
if (record.count > max) {
|
|
920
|
+
res.status(429).json({ error: "Too many requests, please try again later" });
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
next();
|
|
924
|
+
};
|
|
925
|
+
}
|
|
876
926
|
var API_KEY_HEADERS = {
|
|
877
927
|
"x-openai-api-key": "openai",
|
|
878
928
|
"x-google-api-key": "google",
|
|
@@ -906,6 +956,16 @@ function extractApiKey(req, agent) {
|
|
|
906
956
|
return req.body?.apiKey ?? void 0;
|
|
907
957
|
}
|
|
908
958
|
function createAgentRouter(opts) {
|
|
959
|
+
if (opts.serve?.length) {
|
|
960
|
+
const discovered = classifyServables(opts.serve);
|
|
961
|
+
opts = {
|
|
962
|
+
...opts,
|
|
963
|
+
agents: { ...discovered.agents, ...opts.agents },
|
|
964
|
+
teams: { ...discovered.teams, ...opts.teams },
|
|
965
|
+
workflows: { ...discovered.workflows, ...opts.workflows }
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
const reg = opts.registry === false ? null : opts.registry ?? globalRegistry;
|
|
909
969
|
let express;
|
|
910
970
|
try {
|
|
911
971
|
express = _require4("express");
|
|
@@ -913,6 +973,13 @@ function createAgentRouter(opts) {
|
|
|
913
973
|
throw new Error("express is required for createAgentRouter. Install it: npm install express");
|
|
914
974
|
}
|
|
915
975
|
const router = express.Router();
|
|
976
|
+
if (opts.cors) {
|
|
977
|
+
router.use(corsMiddleware(opts.cors));
|
|
978
|
+
}
|
|
979
|
+
if (opts.rateLimit) {
|
|
980
|
+
const config = opts.rateLimit === true ? {} : opts.rateLimit;
|
|
981
|
+
router.use(rateLimitMiddleware(config));
|
|
982
|
+
}
|
|
916
983
|
if (opts.middleware) {
|
|
917
984
|
for (const mw of opts.middleware) {
|
|
918
985
|
router.use(mw);
|
|
@@ -1088,6 +1155,138 @@ function createAgentRouter(opts) {
|
|
|
1088
1155
|
});
|
|
1089
1156
|
}
|
|
1090
1157
|
}
|
|
1158
|
+
if (reg) {
|
|
1159
|
+
router.post(
|
|
1160
|
+
"/agents/:name/run",
|
|
1161
|
+
withUpload(async (req, res) => {
|
|
1162
|
+
const agent = reg.getAgent(req.params.name);
|
|
1163
|
+
if (!agent) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
|
|
1164
|
+
try {
|
|
1165
|
+
const validated = validateBody(req.body, { input: "string", sessionId: "string?", userId: "string?" });
|
|
1166
|
+
const input = buildMultiModalInput(req.body, req.files) ?? validated.input;
|
|
1167
|
+
if (!input) return res.status(400).json({ error: "input is required" });
|
|
1168
|
+
const apiKey = extractApiKey(req, agent);
|
|
1169
|
+
const result = await agent.run(input, {
|
|
1170
|
+
sessionId: validated.sessionId,
|
|
1171
|
+
userId: validated.userId,
|
|
1172
|
+
apiKey
|
|
1173
|
+
});
|
|
1174
|
+
res.json(result);
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
res.status(400).json({ error: error.message });
|
|
1177
|
+
}
|
|
1178
|
+
})
|
|
1179
|
+
);
|
|
1180
|
+
router.post("/agents/:name/stream", async (req, res) => {
|
|
1181
|
+
const agent = reg.getAgent(req.params.name);
|
|
1182
|
+
if (!agent) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
|
|
1183
|
+
try {
|
|
1184
|
+
const validated = validateBody(req.body, { input: "string", sessionId: "string?", userId: "string?" });
|
|
1185
|
+
const input = validated.input;
|
|
1186
|
+
if (!input) return res.status(400).json({ error: "input is required" });
|
|
1187
|
+
const apiKey = extractApiKey(req, agent);
|
|
1188
|
+
res.writeHead(200, {
|
|
1189
|
+
"Content-Type": "text/event-stream",
|
|
1190
|
+
"Cache-Control": "no-cache",
|
|
1191
|
+
Connection: "keep-alive"
|
|
1192
|
+
});
|
|
1193
|
+
for await (const chunk of agent.stream(input, {
|
|
1194
|
+
sessionId: validated.sessionId,
|
|
1195
|
+
userId: validated.userId,
|
|
1196
|
+
apiKey
|
|
1197
|
+
})) {
|
|
1198
|
+
res.write(`data: ${JSON.stringify(chunk)}
|
|
1199
|
+
|
|
1200
|
+
`);
|
|
1201
|
+
}
|
|
1202
|
+
res.write("data: [DONE]\n\n");
|
|
1203
|
+
res.end();
|
|
1204
|
+
} catch (error) {
|
|
1205
|
+
if (!res.headersSent) res.status(500).json({ error: error.message });
|
|
1206
|
+
else {
|
|
1207
|
+
res.write(`data: ${JSON.stringify({ type: "error", error: error.message })}
|
|
1208
|
+
|
|
1209
|
+
`);
|
|
1210
|
+
res.end();
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
router.post("/teams/:name/run", async (req, res) => {
|
|
1215
|
+
const team = reg.getTeam(req.params.name);
|
|
1216
|
+
if (!team) return res.status(404).json({ error: `Team "${req.params.name}" not found` });
|
|
1217
|
+
try {
|
|
1218
|
+
const validated = validateBody(req.body, { input: "string", sessionId: "string?", userId: "string?" });
|
|
1219
|
+
const input = validated.input;
|
|
1220
|
+
if (!input) return res.status(400).json({ error: "input is required" });
|
|
1221
|
+
const apiKey = req.headers["x-api-key"] ?? req.body?.apiKey;
|
|
1222
|
+
const result = await team.run(input, {
|
|
1223
|
+
sessionId: validated.sessionId,
|
|
1224
|
+
userId: validated.userId,
|
|
1225
|
+
apiKey
|
|
1226
|
+
});
|
|
1227
|
+
res.json(result);
|
|
1228
|
+
} catch (error) {
|
|
1229
|
+
res.status(500).json({ error: error.message });
|
|
1230
|
+
}
|
|
1231
|
+
});
|
|
1232
|
+
router.post("/teams/:name/stream", async (req, res) => {
|
|
1233
|
+
const team = reg.getTeam(req.params.name);
|
|
1234
|
+
if (!team) return res.status(404).json({ error: `Team "${req.params.name}" not found` });
|
|
1235
|
+
try {
|
|
1236
|
+
const validated = validateBody(req.body, { input: "string", sessionId: "string?", userId: "string?" });
|
|
1237
|
+
const input = validated.input;
|
|
1238
|
+
if (!input) return res.status(400).json({ error: "input is required" });
|
|
1239
|
+
const apiKey = req.headers["x-api-key"] ?? req.body?.apiKey;
|
|
1240
|
+
res.writeHead(200, {
|
|
1241
|
+
"Content-Type": "text/event-stream",
|
|
1242
|
+
"Cache-Control": "no-cache",
|
|
1243
|
+
Connection: "keep-alive"
|
|
1244
|
+
});
|
|
1245
|
+
for await (const chunk of team.stream(input, {
|
|
1246
|
+
sessionId: validated.sessionId,
|
|
1247
|
+
userId: validated.userId,
|
|
1248
|
+
apiKey
|
|
1249
|
+
})) {
|
|
1250
|
+
res.write(`data: ${JSON.stringify(chunk)}
|
|
1251
|
+
|
|
1252
|
+
`);
|
|
1253
|
+
}
|
|
1254
|
+
res.write("data: [DONE]\n\n");
|
|
1255
|
+
res.end();
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
if (!res.headersSent) res.status(500).json({ error: error.message });
|
|
1258
|
+
else {
|
|
1259
|
+
res.write(`data: ${JSON.stringify({ type: "error", error: error.message })}
|
|
1260
|
+
|
|
1261
|
+
`);
|
|
1262
|
+
res.end();
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
router.post("/workflows/:name/run", async (req, res) => {
|
|
1267
|
+
const workflow = reg.getWorkflow(req.params.name);
|
|
1268
|
+
if (!workflow) return res.status(404).json({ error: `Workflow "${req.params.name}" not found` });
|
|
1269
|
+
try {
|
|
1270
|
+
const { sessionId, userId } = req.body ?? {};
|
|
1271
|
+
const result = await workflow.run({ sessionId, userId });
|
|
1272
|
+
res.json(result);
|
|
1273
|
+
} catch (error) {
|
|
1274
|
+
res.status(500).json({ error: error.message });
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
router.get("/agents", (_req, res) => {
|
|
1278
|
+
res.json(reg.describeAgents());
|
|
1279
|
+
});
|
|
1280
|
+
router.get("/teams", (_req, res) => {
|
|
1281
|
+
res.json(reg.describeTeams());
|
|
1282
|
+
});
|
|
1283
|
+
router.get("/workflows", (_req, res) => {
|
|
1284
|
+
res.json(reg.describeWorkflows());
|
|
1285
|
+
});
|
|
1286
|
+
router.get("/registry", (_req, res) => {
|
|
1287
|
+
res.json(reg.list());
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1091
1290
|
return router;
|
|
1092
1291
|
}
|
|
1093
1292
|
|
|
@@ -1205,13 +1404,44 @@ function createBrowserGateway(opts) {
|
|
|
1205
1404
|
}
|
|
1206
1405
|
|
|
1207
1406
|
// src/socketio/gateway.ts
|
|
1407
|
+
import { classifyServables as classifyServables2, registry as globalRegistry2 } from "@radaros/core";
|
|
1408
|
+
function createSocketRateLimiter(maxPerMinute = 60) {
|
|
1409
|
+
return () => {
|
|
1410
|
+
let count = 0;
|
|
1411
|
+
let resetTime = Date.now() + 6e4;
|
|
1412
|
+
return () => {
|
|
1413
|
+
const now = Date.now();
|
|
1414
|
+
if (now > resetTime) {
|
|
1415
|
+
count = 0;
|
|
1416
|
+
resetTime = now + 6e4;
|
|
1417
|
+
}
|
|
1418
|
+
count++;
|
|
1419
|
+
return count <= maxPerMinute;
|
|
1420
|
+
};
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1208
1423
|
function createAgentGateway(opts) {
|
|
1424
|
+
if (opts.serve?.length) {
|
|
1425
|
+
const discovered = classifyServables2(opts.serve);
|
|
1426
|
+
opts = {
|
|
1427
|
+
...opts,
|
|
1428
|
+
agents: { ...discovered.agents, ...opts.agents },
|
|
1429
|
+
teams: { ...discovered.teams, ...opts.teams }
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
const reg = opts.registry === false ? null : opts.registry ?? globalRegistry2;
|
|
1209
1433
|
const ns = opts.io.of(opts.namespace ?? "/radaros");
|
|
1210
1434
|
if (opts.authMiddleware) {
|
|
1211
1435
|
ns.use(opts.authMiddleware);
|
|
1212
1436
|
}
|
|
1437
|
+
const rateLimiterFactory = createSocketRateLimiter(opts.maxRequestsPerMinute ?? 60);
|
|
1213
1438
|
ns.on("connection", (socket) => {
|
|
1439
|
+
const checkRate = rateLimiterFactory();
|
|
1214
1440
|
socket.on("agent.run", async (data) => {
|
|
1441
|
+
if (!checkRate()) {
|
|
1442
|
+
socket.emit("agent.error", { error: "Rate limit exceeded" });
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1215
1445
|
if (!data || typeof data.input !== "string" || !data.input.trim()) {
|
|
1216
1446
|
socket.emit("agent.error", { error: "Invalid input: must be a non-empty string" });
|
|
1217
1447
|
return;
|
|
@@ -1220,7 +1450,7 @@ function createAgentGateway(opts) {
|
|
|
1220
1450
|
socket.emit("agent.error", { error: "Invalid sessionId: must be a string" });
|
|
1221
1451
|
return;
|
|
1222
1452
|
}
|
|
1223
|
-
const agent = opts.agents?.[data.name];
|
|
1453
|
+
const agent = opts.agents?.[data.name] ?? reg?.getAgent(data.name);
|
|
1224
1454
|
if (!agent) {
|
|
1225
1455
|
socket.emit("agent.error", {
|
|
1226
1456
|
error: `Agent "${data.name}" not found`
|
|
@@ -1255,7 +1485,19 @@ function createAgentGateway(opts) {
|
|
|
1255
1485
|
socket.on("disconnect", () => {
|
|
1256
1486
|
});
|
|
1257
1487
|
socket.on("team.run", async (data) => {
|
|
1258
|
-
|
|
1488
|
+
if (!checkRate()) {
|
|
1489
|
+
socket.emit("agent.error", { error: "Rate limit exceeded" });
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
if (!data || typeof data.input !== "string" || !data.input.trim()) {
|
|
1493
|
+
socket.emit("agent.error", { error: "Invalid input: must be a non-empty string" });
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (data.sessionId !== void 0 && typeof data.sessionId !== "string") {
|
|
1497
|
+
socket.emit("agent.error", { error: "Invalid sessionId: must be a string" });
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
const team = opts.teams?.[data.name] ?? reg?.getTeam(data.name);
|
|
1259
1501
|
if (!team) {
|
|
1260
1502
|
socket.emit("agent.error", {
|
|
1261
1503
|
error: `Team "${data.name}" not found`
|
|
@@ -1380,7 +1622,11 @@ function createVoiceGateway(opts) {
|
|
|
1380
1622
|
if (session) {
|
|
1381
1623
|
try {
|
|
1382
1624
|
await session.close();
|
|
1383
|
-
} catch {
|
|
1625
|
+
} catch (err) {
|
|
1626
|
+
console.warn(
|
|
1627
|
+
"[radaros/voice-gateway] Error closing session on disconnect:",
|
|
1628
|
+
err instanceof Error ? err.message : err
|
|
1629
|
+
);
|
|
1384
1630
|
}
|
|
1385
1631
|
activeSessions.delete(socket.id);
|
|
1386
1632
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radaros/transport",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
|
+
"description": "HTTP and WebSocket transport layer for RadarOS agents",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/xhipment/agentOs.git",
|
|
9
|
+
"directory": "packages/transport"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"ai",
|
|
13
|
+
"agents",
|
|
14
|
+
"express",
|
|
15
|
+
"socketio",
|
|
16
|
+
"api",
|
|
17
|
+
"transport"
|
|
18
|
+
],
|
|
4
19
|
"type": "module",
|
|
5
20
|
"main": "./dist/index.js",
|
|
6
21
|
"types": "./dist/index.d.ts",
|
|
@@ -24,7 +39,7 @@
|
|
|
24
39
|
"typescript": "^5.6.0"
|
|
25
40
|
},
|
|
26
41
|
"peerDependencies": {
|
|
27
|
-
"@radaros/core": "^0.3.
|
|
42
|
+
"@radaros/core": "^0.3.14",
|
|
28
43
|
"@types/express": "^4.0.0 || ^5.0.0",
|
|
29
44
|
"express": "^4.0.0 || ^5.0.0",
|
|
30
45
|
"multer": ">=2.0.0",
|