@radaros/transport 0.3.7 → 0.3.8

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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Agent, Team, Workflow, VoiceAgent, A2AAgentCard } from '@radaros/core';
1
+ import { Agent, Team, Workflow, VoiceAgent, EventBus, A2AAgentCard } from '@radaros/core';
2
2
 
3
3
  interface FileUploadOptions {
4
4
  maxFileSize?: number;
@@ -87,6 +87,66 @@ interface VoiceGatewayOptions {
87
87
  }
88
88
  declare function createVoiceGateway(opts: VoiceGatewayOptions): void;
89
89
 
90
+ /**
91
+ * Minimal interface for a BrowserAgent — avoids a hard dependency on @radaros/browser.
92
+ * Any object that matches this shape (e.g. a real BrowserAgent) works.
93
+ */
94
+ interface BrowserAgentLike {
95
+ name: string;
96
+ eventBus: EventBus;
97
+ run(task: string, opts?: {
98
+ startUrl?: string;
99
+ apiKey?: string;
100
+ sessionId?: string;
101
+ }): Promise<{
102
+ result: string;
103
+ success: boolean;
104
+ finalUrl: string;
105
+ durationMs: number;
106
+ videoPath?: string;
107
+ steps: Array<{
108
+ index: number;
109
+ action: unknown;
110
+ screenshot: Buffer;
111
+ pageUrl: string;
112
+ pageTitle: string;
113
+ dom?: string;
114
+ }>;
115
+ }>;
116
+ }
117
+ interface BrowserGatewayOptions {
118
+ /** Named BrowserAgent instances. Clients select one via agentName. */
119
+ agents: Record<string, BrowserAgentLike>;
120
+ /** Socket.IO server instance */
121
+ io: any;
122
+ /** Socket.IO namespace. Default: "/radaros-browser" */
123
+ namespace?: string;
124
+ /** Optional auth middleware applied to the namespace */
125
+ authMiddleware?: (socket: any, next: (err?: Error) => void) => void;
126
+ /**
127
+ * Stream screenshots to the client in real-time.
128
+ * Default: true. Disable for bandwidth-constrained clients.
129
+ */
130
+ streamScreenshots?: boolean;
131
+ }
132
+ /**
133
+ * Create a Socket.IO gateway that streams BrowserAgent execution in real-time.
134
+ *
135
+ * ## Client → Server events
136
+ * - `browser.start` — kick off a browser task
137
+ * - `browser.stop` — cancel a running task
138
+ *
139
+ * ## Server → Client events
140
+ * - `browser.started` — task accepted
141
+ * - `browser.screenshot` — live screenshot (base64 PNG)
142
+ * - `browser.action` — action about to execute
143
+ * - `browser.step` — full step with screenshot + DOM
144
+ * - `browser.done` — task finished (result, success, duration, video)
145
+ * - `browser.error` — error occurred
146
+ * - `browser.stopped` — task was cancelled
147
+ */
148
+ declare function createBrowserGateway(opts: BrowserGatewayOptions): void;
149
+
90
150
  interface A2AServerOptions {
91
151
  agents: Record<string, Agent>;
92
152
  basePath?: string;
@@ -121,4 +181,4 @@ declare function generateMultiAgentCard(agents: Record<string, Agent>, serverUrl
121
181
  url?: string;
122
182
  }, version?: string): A2AAgentCard;
123
183
 
124
- export { type A2AServerOptions, type FileUploadOptions, type GatewayOptions, type RouterOptions, type SwaggerOptions, type VoiceGatewayOptions, buildMultiModalInput, createA2AServer, createAgentGateway, createAgentRouter, createFileUploadMiddleware, createVoiceGateway, errorHandler, generateAgentCard, generateMultiAgentCard, generateOpenAPISpec, requestLogger };
184
+ export { type A2AServerOptions, type BrowserGatewayOptions, type FileUploadOptions, type GatewayOptions, type RouterOptions, type SwaggerOptions, type VoiceGatewayOptions, buildMultiModalInput, createA2AServer, createAgentGateway, createAgentRouter, createBrowserGateway, createFileUploadMiddleware, createVoiceGateway, errorHandler, generateAgentCard, generateMultiAgentCard, generateOpenAPISpec, requestLogger };
package/dist/index.js CHANGED
@@ -885,6 +885,119 @@ function createVoiceGateway(opts) {
885
885
  });
886
886
  }
887
887
 
888
+ // src/socketio/browser-gateway.ts
889
+ function createBrowserGateway(opts) {
890
+ const ns = opts.io.of(opts.namespace ?? "/radaros-browser");
891
+ const streamScreenshots = opts.streamScreenshots ?? true;
892
+ if (opts.authMiddleware) {
893
+ ns.use(opts.authMiddleware);
894
+ }
895
+ const activeRuns = /* @__PURE__ */ new Map();
896
+ ns.on("connection", (socket) => {
897
+ socket.on(
898
+ "browser.start",
899
+ async (data) => {
900
+ const agent = opts.agents[data.agentName];
901
+ if (!agent) {
902
+ socket.emit("browser.error", {
903
+ error: `Browser agent "${data.agentName}" not found`
904
+ });
905
+ return;
906
+ }
907
+ if (activeRuns.has(socket.id)) {
908
+ socket.emit("browser.error", {
909
+ error: "A browser task is already running for this connection"
910
+ });
911
+ return;
912
+ }
913
+ const abort = new AbortController();
914
+ activeRuns.set(socket.id, abort);
915
+ const onScreenshot = (ev) => {
916
+ if (streamScreenshots && !abort.signal.aborted) {
917
+ socket.emit("browser.screenshot", {
918
+ data: ev.data.toString("base64"),
919
+ mimeType: "image/png"
920
+ });
921
+ }
922
+ };
923
+ const onAction = (ev) => {
924
+ if (!abort.signal.aborted) {
925
+ socket.emit("browser.action", { action: ev.action });
926
+ }
927
+ };
928
+ const onStep = (ev) => {
929
+ if (!abort.signal.aborted) {
930
+ socket.emit("browser.step", {
931
+ index: ev.index,
932
+ action: ev.action,
933
+ pageUrl: ev.pageUrl,
934
+ screenshot: streamScreenshots ? ev.screenshot.toString("base64") : void 0
935
+ });
936
+ }
937
+ };
938
+ const onError = (ev) => {
939
+ if (!abort.signal.aborted) {
940
+ socket.emit("browser.error", { error: ev.error.message });
941
+ }
942
+ };
943
+ agent.eventBus.on("browser.screenshot", onScreenshot);
944
+ agent.eventBus.on("browser.action", onAction);
945
+ agent.eventBus.on("browser.step", onStep);
946
+ agent.eventBus.on("browser.error", onError);
947
+ const cleanup = () => {
948
+ agent.eventBus.off("browser.screenshot", onScreenshot);
949
+ agent.eventBus.off("browser.action", onAction);
950
+ agent.eventBus.off("browser.step", onStep);
951
+ agent.eventBus.off("browser.error", onError);
952
+ activeRuns.delete(socket.id);
953
+ };
954
+ socket.emit("browser.started", {
955
+ agentName: data.agentName,
956
+ task: data.task
957
+ });
958
+ try {
959
+ const result = await agent.run(data.task, {
960
+ startUrl: data.startUrl,
961
+ apiKey: data.apiKey ?? socket.handshake?.auth?.apiKey,
962
+ sessionId: data.sessionId
963
+ });
964
+ cleanup();
965
+ if (!abort.signal.aborted) {
966
+ socket.emit("browser.done", {
967
+ result: result.result,
968
+ success: result.success,
969
+ finalUrl: result.finalUrl,
970
+ durationMs: result.durationMs,
971
+ totalSteps: result.steps.length,
972
+ videoPath: result.videoPath
973
+ });
974
+ }
975
+ } catch (error) {
976
+ cleanup();
977
+ if (!abort.signal.aborted) {
978
+ socket.emit("browser.error", { error: error.message });
979
+ }
980
+ }
981
+ }
982
+ );
983
+ socket.on("browser.stop", () => {
984
+ const abort = activeRuns.get(socket.id);
985
+ if (abort) {
986
+ abort.abort();
987
+ activeRuns.delete(socket.id);
988
+ socket.emit("browser.stopped");
989
+ }
990
+ });
991
+ socket.on("disconnect", () => {
992
+ const abort = activeRuns.get(socket.id);
993
+ if (abort) {
994
+ abort.abort();
995
+ activeRuns.delete(socket.id);
996
+ }
997
+ });
998
+ });
999
+ }
1000
+
888
1001
  // src/a2a/a2a-server.ts
889
1002
  import { createRequire as createRequire4 } from "module";
890
1003
  import { randomUUID } from "crypto";
@@ -1236,6 +1349,7 @@ export {
1236
1349
  createA2AServer,
1237
1350
  createAgentGateway,
1238
1351
  createAgentRouter,
1352
+ createBrowserGateway,
1239
1353
  createFileUploadMiddleware,
1240
1354
  createVoiceGateway,
1241
1355
  errorHandler,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radaros/transport",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "typescript": "^5.6.0"
25
25
  },
26
26
  "peerDependencies": {
27
- "@radaros/core": "^0.3.7",
27
+ "@radaros/core": "^0.3.8",
28
28
  "@types/express": "^4.0.0 || ^5.0.0",
29
29
  "express": "^4.0.0 || ^5.0.0",
30
30
  "multer": ">=1.4.0",