@radaros/transport 0.3.6 → 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 +70 -2
- package/dist/index.js +233 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Agent, Team, Workflow, 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;
|
|
@@ -79,6 +79,74 @@ interface GatewayOptions {
|
|
|
79
79
|
|
|
80
80
|
declare function createAgentGateway(opts: GatewayOptions): void;
|
|
81
81
|
|
|
82
|
+
interface VoiceGatewayOptions {
|
|
83
|
+
agents: Record<string, VoiceAgent>;
|
|
84
|
+
io: any;
|
|
85
|
+
namespace?: string;
|
|
86
|
+
authMiddleware?: (socket: any, next: (err?: Error) => void) => void;
|
|
87
|
+
}
|
|
88
|
+
declare function createVoiceGateway(opts: VoiceGatewayOptions): void;
|
|
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
|
+
|
|
82
150
|
interface A2AServerOptions {
|
|
83
151
|
agents: Record<string, Agent>;
|
|
84
152
|
basePath?: string;
|
|
@@ -113,4 +181,4 @@ declare function generateMultiAgentCard(agents: Record<string, Agent>, serverUrl
|
|
|
113
181
|
url?: string;
|
|
114
182
|
}, version?: string): A2AAgentCard;
|
|
115
183
|
|
|
116
|
-
export { type A2AServerOptions, type FileUploadOptions, type GatewayOptions, type RouterOptions, type SwaggerOptions, buildMultiModalInput, createA2AServer, createAgentGateway, createAgentRouter, createFileUploadMiddleware, 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
|
@@ -767,6 +767,237 @@ function createAgentGateway(opts) {
|
|
|
767
767
|
});
|
|
768
768
|
}
|
|
769
769
|
|
|
770
|
+
// src/socketio/voice-gateway.ts
|
|
771
|
+
function createVoiceGateway(opts) {
|
|
772
|
+
const ns = opts.io.of(opts.namespace ?? "/radaros-voice");
|
|
773
|
+
if (opts.authMiddleware) {
|
|
774
|
+
ns.use(opts.authMiddleware);
|
|
775
|
+
}
|
|
776
|
+
const activeSessions = /* @__PURE__ */ new Map();
|
|
777
|
+
ns.on("connection", (socket) => {
|
|
778
|
+
socket.on(
|
|
779
|
+
"voice.start",
|
|
780
|
+
async (data) => {
|
|
781
|
+
const agent = opts.agents[data.agentName];
|
|
782
|
+
if (!agent) {
|
|
783
|
+
socket.emit("voice.error", {
|
|
784
|
+
error: `Voice agent "${data.agentName}" not found`
|
|
785
|
+
});
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
if (activeSessions.has(socket.id)) {
|
|
789
|
+
socket.emit("voice.error", {
|
|
790
|
+
error: "A voice session is already active for this connection"
|
|
791
|
+
});
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
const apiKey = data.apiKey ?? socket.handshake?.auth?.apiKey;
|
|
796
|
+
const userId = data.userId ?? socket.handshake?.auth?.userId;
|
|
797
|
+
const sessionId = data.sessionId ?? socket.handshake?.auth?.sessionId;
|
|
798
|
+
const session = await agent.connect({
|
|
799
|
+
apiKey,
|
|
800
|
+
userId,
|
|
801
|
+
sessionId
|
|
802
|
+
});
|
|
803
|
+
activeSessions.set(socket.id, session);
|
|
804
|
+
session.on("audio", (ev) => {
|
|
805
|
+
socket.emit("voice.audio", {
|
|
806
|
+
data: ev.data.toString("base64"),
|
|
807
|
+
mimeType: ev.mimeType ?? "audio/pcm"
|
|
808
|
+
});
|
|
809
|
+
});
|
|
810
|
+
session.on("transcript", (ev) => {
|
|
811
|
+
socket.emit("voice.transcript", {
|
|
812
|
+
text: ev.text,
|
|
813
|
+
role: ev.role
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
session.on("text", (ev) => {
|
|
817
|
+
socket.emit("voice.text", { text: ev.text });
|
|
818
|
+
});
|
|
819
|
+
session.on(
|
|
820
|
+
"tool_call_start",
|
|
821
|
+
(ev) => {
|
|
822
|
+
socket.emit("voice.tool.call", {
|
|
823
|
+
name: ev.name,
|
|
824
|
+
args: ev.args
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
);
|
|
828
|
+
session.on(
|
|
829
|
+
"tool_result",
|
|
830
|
+
(ev) => {
|
|
831
|
+
socket.emit("voice.tool.result", {
|
|
832
|
+
name: ev.name,
|
|
833
|
+
result: ev.result
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
);
|
|
837
|
+
session.on("interrupted", () => {
|
|
838
|
+
socket.emit("voice.interrupted");
|
|
839
|
+
});
|
|
840
|
+
session.on("error", (ev) => {
|
|
841
|
+
socket.emit("voice.error", { error: ev.error.message });
|
|
842
|
+
});
|
|
843
|
+
session.on("disconnected", () => {
|
|
844
|
+
activeSessions.delete(socket.id);
|
|
845
|
+
socket.emit("voice.stopped");
|
|
846
|
+
});
|
|
847
|
+
socket.emit("voice.started", { userId });
|
|
848
|
+
} catch (error) {
|
|
849
|
+
socket.emit("voice.error", { error: error.message });
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
);
|
|
853
|
+
socket.on("voice.audio", (data) => {
|
|
854
|
+
const session = activeSessions.get(socket.id);
|
|
855
|
+
if (!session) return;
|
|
856
|
+
session.sendAudio(Buffer.from(data.data, "base64"));
|
|
857
|
+
});
|
|
858
|
+
socket.on("voice.text", (data) => {
|
|
859
|
+
const session = activeSessions.get(socket.id);
|
|
860
|
+
if (!session) return;
|
|
861
|
+
session.sendText(data.text);
|
|
862
|
+
});
|
|
863
|
+
socket.on("voice.interrupt", () => {
|
|
864
|
+
const session = activeSessions.get(socket.id);
|
|
865
|
+
if (!session) return;
|
|
866
|
+
session.interrupt();
|
|
867
|
+
});
|
|
868
|
+
socket.on("voice.stop", async () => {
|
|
869
|
+
const session = activeSessions.get(socket.id);
|
|
870
|
+
if (!session) return;
|
|
871
|
+
await session.close();
|
|
872
|
+
activeSessions.delete(socket.id);
|
|
873
|
+
socket.emit("voice.stopped");
|
|
874
|
+
});
|
|
875
|
+
socket.on("disconnect", async () => {
|
|
876
|
+
const session = activeSessions.get(socket.id);
|
|
877
|
+
if (session) {
|
|
878
|
+
try {
|
|
879
|
+
await session.close();
|
|
880
|
+
} catch {
|
|
881
|
+
}
|
|
882
|
+
activeSessions.delete(socket.id);
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
});
|
|
886
|
+
}
|
|
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
|
+
|
|
770
1001
|
// src/a2a/a2a-server.ts
|
|
771
1002
|
import { createRequire as createRequire4 } from "module";
|
|
772
1003
|
import { randomUUID } from "crypto";
|
|
@@ -1118,7 +1349,9 @@ export {
|
|
|
1118
1349
|
createA2AServer,
|
|
1119
1350
|
createAgentGateway,
|
|
1120
1351
|
createAgentRouter,
|
|
1352
|
+
createBrowserGateway,
|
|
1121
1353
|
createFileUploadMiddleware,
|
|
1354
|
+
createVoiceGateway,
|
|
1122
1355
|
errorHandler,
|
|
1123
1356
|
generateAgentCard,
|
|
1124
1357
|
generateMultiAgentCard,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radaros/transport",
|
|
3
|
-
"version": "0.3.
|
|
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.
|
|
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",
|