@elizaos/plugin-xr 2.0.3-beta.5 → 2.0.3-beta.7
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/actions/xr-query-vision.d.ts +3 -0
- package/dist/actions/xr-query-vision.d.ts.map +1 -0
- package/dist/actions/xr-query-vision.js +39 -0
- package/dist/actions/xr-query-vision.js.map +1 -0
- package/dist/actions/xr-view-actions.d.ts +18 -0
- package/dist/actions/xr-view-actions.d.ts.map +1 -0
- package/dist/actions/xr-view-actions.js +304 -0
- package/dist/actions/xr-view-actions.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +124 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +18 -0
- package/dist/protocol.js.map +1 -0
- package/dist/providers/xr-context.d.ts +3 -0
- package/dist/providers/xr-context.d.ts.map +1 -0
- package/dist/providers/xr-context.js +34 -0
- package/dist/providers/xr-context.js.map +1 -0
- package/dist/routes/xr-connect.d.ts +3 -0
- package/dist/routes/xr-connect.d.ts.map +1 -0
- package/{src/routes/xr-connect.ts → dist/routes/xr-connect.js} +12 -15
- package/dist/routes/xr-connect.js.map +1 -0
- package/dist/routes/xr-simulator-route.d.ts +8 -0
- package/dist/routes/xr-simulator-route.d.ts.map +1 -0
- package/{src/routes/xr-simulator-route.ts → dist/routes/xr-simulator-route.js} +10 -16
- package/dist/routes/xr-simulator-route.js.map +1 -0
- package/dist/routes/xr-status.d.ts +3 -0
- package/dist/routes/xr-status.d.ts.map +1 -0
- package/{src/routes/xr-status.ts → dist/routes/xr-status.js} +13 -15
- package/dist/routes/xr-status.js.map +1 -0
- package/dist/routes/xr-view-host.d.ts +24 -0
- package/dist/routes/xr-view-host.d.ts.map +1 -0
- package/{src/routes/xr-view-host.ts → dist/routes/xr-view-host.js} +22 -59
- package/dist/routes/xr-view-host.js.map +1 -0
- package/dist/routes/xr-views.d.ts +8 -0
- package/dist/routes/xr-views.d.ts.map +1 -0
- package/dist/routes/xr-views.js +31 -0
- package/dist/routes/xr-views.js.map +1 -0
- package/dist/services/audio-pipeline.d.ts +20 -0
- package/dist/services/audio-pipeline.d.ts.map +1 -0
- package/{src/services/audio-pipeline.ts → dist/services/audio-pipeline.js} +25 -58
- package/dist/services/audio-pipeline.js.map +1 -0
- package/dist/services/vision-pipeline.d.ts +16 -0
- package/dist/services/vision-pipeline.d.ts.map +1 -0
- package/dist/services/vision-pipeline.js +39 -0
- package/dist/services/vision-pipeline.js.map +1 -0
- package/dist/services/xr-session-service.d.ts +50 -0
- package/dist/services/xr-session-service.d.ts.map +1 -0
- package/{src/services/xr-session-service.ts → dist/services/xr-session-service.js} +85 -194
- package/dist/services/xr-session-service.js.map +1 -0
- package/package.json +9 -4
- package/AGENTS.md +0 -151
- package/CLAUDE.md +0 -151
- package/simulator/bun.lock +0 -159
- package/simulator/package.json +0 -28
- package/simulator/src/emulator.ts +0 -174
- package/simulator/src/mock-agent.ts +0 -233
- package/simulator/src/node.ts +0 -9
- package/simulator/src/playwright-fixture.ts +0 -169
- package/simulator/src/types.ts +0 -51
- package/simulator/tsconfig.json +0 -13
- package/simulator/vite.config.ts +0 -25
- package/src/__tests__/audio-pipeline.test.ts +0 -129
- package/src/__tests__/protocol.test.ts +0 -53
- package/src/__tests__/routes-e2e.test.ts +0 -276
- package/src/__tests__/vision-pipeline.test.ts +0 -73
- package/src/__tests__/xr-bundle-coverage.test.ts +0 -303
- package/src/__tests__/xr-feature-parity.test.ts +0 -524
- package/src/__tests__/xr-functional-parity.test.ts +0 -522
- package/src/__tests__/xr-view-host-http.test.ts +0 -239
- package/src/__tests__/xr-view-host.test.ts +0 -174
- package/src/actions/xr-query-vision.ts +0 -64
- package/src/actions/xr-view-actions.ts +0 -386
- package/src/index.ts +0 -55
- package/src/protocol.ts +0 -126
- package/src/providers/xr-context.ts +0 -49
- package/src/routes/xr-views.ts +0 -43
- package/src/services/vision-pipeline.ts +0 -57
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -30
- package/vitest.config.ts +0 -21
|
@@ -1,203 +1,132 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Content,
|
|
3
|
-
HandlerCallback,
|
|
4
|
-
IAgentRuntime,
|
|
5
|
-
Memory,
|
|
6
|
-
UUID,
|
|
7
|
-
} from "@elizaos/core";
|
|
8
1
|
import {
|
|
9
2
|
ChannelType,
|
|
10
3
|
createMessageMemory,
|
|
11
4
|
ModelType,
|
|
12
|
-
Service
|
|
5
|
+
Service
|
|
13
6
|
} from "@elizaos/core";
|
|
14
|
-
import {
|
|
7
|
+
import { WebSocketServer } from "ws";
|
|
15
8
|
import {
|
|
16
9
|
decodeBinaryFrame,
|
|
17
|
-
encodeBinaryFrame
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
id: string;
|
|
33
|
-
ws: WebSocket;
|
|
34
|
-
deviceType: XRDeviceType;
|
|
35
|
-
entityId: UUID;
|
|
36
|
-
roomId: UUID;
|
|
37
|
-
connectedAt: Date;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export class XRSessionService extends Service {
|
|
41
|
-
static override serviceType = XR_SERVICE_TYPE;
|
|
42
|
-
|
|
43
|
-
readonly capabilityDescription =
|
|
44
|
-
"Streams audio and camera from XR headsets (Quest 3, XReal) to the agent and returns voice responses.";
|
|
45
|
-
|
|
46
|
-
private wss!: WebSocketServer;
|
|
47
|
-
private connections = new Map<string, XRConnection>();
|
|
48
|
-
private audioPipeline!: AudioPipeline;
|
|
49
|
-
private visionPipeline!: VisionPipeline;
|
|
50
|
-
|
|
51
|
-
static override async start(runtime: IAgentRuntime): Promise<Service> {
|
|
10
|
+
encodeBinaryFrame
|
|
11
|
+
} from "../protocol.js";
|
|
12
|
+
import { AudioPipeline } from "./audio-pipeline.js";
|
|
13
|
+
import { VisionPipeline } from "./vision-pipeline.js";
|
|
14
|
+
const XR_SERVICE_TYPE = "xr-session";
|
|
15
|
+
const XR_WS_PORT_DEFAULT = 31338;
|
|
16
|
+
const XR_WS_PORT_ENV = "XR_WS_PORT";
|
|
17
|
+
class XRSessionService extends Service {
|
|
18
|
+
static serviceType = XR_SERVICE_TYPE;
|
|
19
|
+
capabilityDescription = "Streams audio and camera from XR headsets (Quest 3, XReal) to the agent and returns voice responses.";
|
|
20
|
+
wss;
|
|
21
|
+
connections = /* @__PURE__ */ new Map();
|
|
22
|
+
audioPipeline;
|
|
23
|
+
visionPipeline;
|
|
24
|
+
static async start(runtime) {
|
|
52
25
|
const svc = new XRSessionService(runtime);
|
|
53
26
|
await svc.initialize(runtime);
|
|
54
27
|
return svc;
|
|
55
28
|
}
|
|
56
|
-
|
|
57
|
-
private async initialize(runtime: IAgentRuntime): Promise<void> {
|
|
29
|
+
async initialize(runtime) {
|
|
58
30
|
this.visionPipeline = new VisionPipeline();
|
|
59
31
|
this.audioPipeline = new AudioPipeline(
|
|
60
32
|
runtime,
|
|
61
|
-
(connectionId, transcript) =>
|
|
62
|
-
this.handleTranscript(connectionId, transcript),
|
|
33
|
+
(connectionId, transcript) => this.handleTranscript(connectionId, transcript)
|
|
63
34
|
);
|
|
64
|
-
|
|
65
35
|
const port = Number(
|
|
66
|
-
runtime.getSetting(XR_WS_PORT_ENV) ?? XR_WS_PORT_DEFAULT
|
|
36
|
+
runtime.getSetting(XR_WS_PORT_ENV) ?? XR_WS_PORT_DEFAULT
|
|
67
37
|
);
|
|
68
38
|
this.wss = new WebSocketServer({ port });
|
|
69
|
-
|
|
70
|
-
this.wss.on(
|
|
71
|
-
|
|
72
|
-
console.error("[plugin-xr] WebSocket server error:", err)
|
|
39
|
+
this.wss.on("connection", (ws) => this.onConnect(runtime, ws));
|
|
40
|
+
this.wss.on(
|
|
41
|
+
"error",
|
|
42
|
+
(err) => console.error("[plugin-xr] WebSocket server error:", err)
|
|
73
43
|
);
|
|
74
|
-
|
|
75
44
|
console.info(
|
|
76
|
-
`[plugin-xr] WebSocket server listening on ws://localhost:${port}
|
|
45
|
+
`[plugin-xr] WebSocket server listening on ws://localhost:${port}`
|
|
77
46
|
);
|
|
78
47
|
}
|
|
79
|
-
|
|
80
|
-
override async stop(): Promise<void> {
|
|
48
|
+
async stop() {
|
|
81
49
|
for (const conn of this.connections.values()) {
|
|
82
50
|
this.audioPipeline.clear(conn.id);
|
|
83
51
|
this.visionPipeline.clear(conn.id);
|
|
84
52
|
conn.ws.close();
|
|
85
53
|
}
|
|
86
54
|
this.connections.clear();
|
|
87
|
-
await new Promise
|
|
55
|
+
await new Promise((resolve) => this.wss.close(() => resolve()));
|
|
88
56
|
}
|
|
89
|
-
|
|
90
57
|
// ── Public accessors used by provider / action ──────────────────────────
|
|
91
|
-
|
|
92
|
-
getConnections(): XRConnection[] {
|
|
58
|
+
getConnections() {
|
|
93
59
|
return [...this.connections.values()];
|
|
94
60
|
}
|
|
95
|
-
|
|
96
|
-
hasActiveConnections(): boolean {
|
|
61
|
+
hasActiveConnections() {
|
|
97
62
|
return this.connections.size > 0;
|
|
98
63
|
}
|
|
99
|
-
|
|
100
|
-
getVisionPipeline(): VisionPipeline {
|
|
64
|
+
getVisionPipeline() {
|
|
101
65
|
return this.visionPipeline;
|
|
102
66
|
}
|
|
103
|
-
|
|
104
|
-
sendText(connectionId: string, text: string): void {
|
|
67
|
+
sendText(connectionId, text) {
|
|
105
68
|
const conn = this.connections.get(connectionId);
|
|
106
69
|
if (!conn || conn.ws.readyState !== conn.ws.OPEN) return;
|
|
107
70
|
conn.ws.send(JSON.stringify({ type: "agent_text", text }));
|
|
108
71
|
}
|
|
109
|
-
|
|
110
|
-
sendControl(connectionId: string, msg: XRServerControl): void {
|
|
72
|
+
sendControl(connectionId, msg) {
|
|
111
73
|
const conn = this.connections.get(connectionId);
|
|
112
74
|
if (!conn || conn.ws.readyState !== conn.ws.OPEN) return;
|
|
113
75
|
conn.ws.send(JSON.stringify(msg));
|
|
114
76
|
}
|
|
115
|
-
|
|
116
|
-
broadcastControl(msg: XRServerControl): void {
|
|
77
|
+
broadcastControl(msg) {
|
|
117
78
|
for (const conn of this.connections.values()) {
|
|
118
79
|
if (conn.ws.readyState === conn.ws.OPEN) {
|
|
119
80
|
conn.ws.send(JSON.stringify(msg));
|
|
120
81
|
}
|
|
121
82
|
}
|
|
122
83
|
}
|
|
123
|
-
|
|
124
|
-
openView(
|
|
125
|
-
connectionId: string,
|
|
126
|
-
viewId: string,
|
|
127
|
-
agentBaseUrl: string,
|
|
128
|
-
config?: XRPanelConfig,
|
|
129
|
-
): void {
|
|
84
|
+
openView(connectionId, viewId, agentBaseUrl, config) {
|
|
130
85
|
this.sendControl(connectionId, {
|
|
131
86
|
type: "view_open",
|
|
132
87
|
viewId,
|
|
133
88
|
agentBaseUrl,
|
|
134
|
-
config
|
|
89
|
+
config
|
|
135
90
|
});
|
|
136
91
|
}
|
|
137
|
-
|
|
138
|
-
closeView(connectionId: string, viewId: string): void {
|
|
92
|
+
closeView(connectionId, viewId) {
|
|
139
93
|
this.sendControl(connectionId, { type: "view_close", viewId });
|
|
140
94
|
}
|
|
141
|
-
|
|
142
|
-
switchView(connectionId: string, viewId: string): void {
|
|
95
|
+
switchView(connectionId, viewId) {
|
|
143
96
|
this.sendControl(connectionId, { type: "view_switch", viewId });
|
|
144
97
|
}
|
|
145
|
-
|
|
146
|
-
resizeView(
|
|
147
|
-
connectionId: string,
|
|
148
|
-
viewId: string,
|
|
149
|
-
config: XRPanelConfig,
|
|
150
|
-
): void {
|
|
98
|
+
resizeView(connectionId, viewId, config) {
|
|
151
99
|
this.sendControl(connectionId, { type: "view_resize", viewId, config });
|
|
152
100
|
}
|
|
153
|
-
|
|
154
|
-
sendViewsCatalog(
|
|
155
|
-
connectionId: string,
|
|
156
|
-
views: Array<{
|
|
157
|
-
id: string;
|
|
158
|
-
label: string;
|
|
159
|
-
icon?: string;
|
|
160
|
-
description?: string;
|
|
161
|
-
}>,
|
|
162
|
-
): void {
|
|
101
|
+
sendViewsCatalog(connectionId, views) {
|
|
163
102
|
this.sendControl(connectionId, { type: "views_catalog", views });
|
|
164
103
|
}
|
|
165
|
-
|
|
166
|
-
sendAudio(connectionId: string, audio: Buffer, sampleRate = 24000): void {
|
|
104
|
+
sendAudio(connectionId, audio, sampleRate = 24e3) {
|
|
167
105
|
const conn = this.connections.get(connectionId);
|
|
168
106
|
if (!conn || conn.ws.readyState !== conn.ws.OPEN) return;
|
|
169
|
-
const header
|
|
107
|
+
const header = {
|
|
170
108
|
type: "tts_audio",
|
|
171
109
|
sampleRate,
|
|
172
110
|
channels: 1,
|
|
173
|
-
encoding: "mp3"
|
|
111
|
+
encoding: "mp3"
|
|
174
112
|
};
|
|
175
113
|
conn.ws.send(encodeBinaryFrame(header, audio), { binary: true });
|
|
176
114
|
}
|
|
177
|
-
|
|
178
115
|
// ── WebSocket connection lifecycle ──────────────────────────────────────
|
|
179
|
-
|
|
180
|
-
private onConnect(runtime: IAgentRuntime, ws: WebSocket): void {
|
|
116
|
+
onConnect(runtime, ws) {
|
|
181
117
|
const connId = crypto.randomUUID();
|
|
182
|
-
|
|
183
|
-
ws.on("message", (data: unknown, isBinary: boolean) => {
|
|
118
|
+
ws.on("message", (data, isBinary) => {
|
|
184
119
|
try {
|
|
185
120
|
if (isBinary) {
|
|
186
|
-
this.handleBinaryMessage(connId, data
|
|
121
|
+
this.handleBinaryMessage(connId, data);
|
|
187
122
|
} else {
|
|
188
|
-
const raw =
|
|
189
|
-
typeof data === "string"
|
|
190
|
-
? data
|
|
191
|
-
: Buffer.isBuffer(data)
|
|
192
|
-
? data.toString("utf8")
|
|
193
|
-
: String(data);
|
|
123
|
+
const raw = typeof data === "string" ? data : Buffer.isBuffer(data) ? data.toString("utf8") : String(data);
|
|
194
124
|
this.handleTextMessage(runtime, connId, ws, raw);
|
|
195
125
|
}
|
|
196
126
|
} catch (err) {
|
|
197
127
|
console.error("[plugin-xr] message handler error:", err);
|
|
198
128
|
}
|
|
199
129
|
});
|
|
200
|
-
|
|
201
130
|
ws.on("close", () => {
|
|
202
131
|
this.audioPipeline.flush(connId);
|
|
203
132
|
this.audioPipeline.clear(connId);
|
|
@@ -205,30 +134,23 @@ export class XRSessionService extends Service {
|
|
|
205
134
|
this.connections.delete(connId);
|
|
206
135
|
console.info(`[plugin-xr] device disconnected: ${connId}`);
|
|
207
136
|
});
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
console.error(`[plugin-xr] ws error on ${connId}:`, err)
|
|
137
|
+
ws.on(
|
|
138
|
+
"error",
|
|
139
|
+
(err) => console.error(`[plugin-xr] ws error on ${connId}:`, err)
|
|
211
140
|
);
|
|
212
141
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
runtime: IAgentRuntime,
|
|
216
|
-
connId: string,
|
|
217
|
-
ws: WebSocket,
|
|
218
|
-
raw: string,
|
|
219
|
-
): void {
|
|
220
|
-
const msg = JSON.parse(raw) as XRClientControl;
|
|
221
|
-
|
|
142
|
+
handleTextMessage(runtime, connId, ws, raw) {
|
|
143
|
+
const msg = JSON.parse(raw);
|
|
222
144
|
if (msg.type === "hello") {
|
|
223
|
-
const entityId = crypto.randomUUID()
|
|
224
|
-
const roomId = crypto.randomUUID()
|
|
225
|
-
const conn
|
|
145
|
+
const entityId = crypto.randomUUID();
|
|
146
|
+
const roomId = crypto.randomUUID();
|
|
147
|
+
const conn = {
|
|
226
148
|
id: connId,
|
|
227
149
|
ws,
|
|
228
150
|
deviceType: msg.deviceType,
|
|
229
151
|
entityId,
|
|
230
152
|
roomId,
|
|
231
|
-
connectedAt: new Date()
|
|
153
|
+
connectedAt: /* @__PURE__ */ new Date()
|
|
232
154
|
};
|
|
233
155
|
this.connections.set(connId, conn);
|
|
234
156
|
ws.send(JSON.stringify({ type: "ready", sessionId: connId }));
|
|
@@ -236,78 +158,58 @@ export class XRSessionService extends Service {
|
|
|
236
158
|
console.info(`[plugin-xr] ${msg.deviceType} connected: ${connId}`);
|
|
237
159
|
return;
|
|
238
160
|
}
|
|
239
|
-
|
|
240
161
|
if (msg.type === "ping") {
|
|
241
162
|
ws.send(JSON.stringify({ type: "pong" }));
|
|
242
163
|
return;
|
|
243
164
|
}
|
|
244
|
-
|
|
245
165
|
if (msg.type === "view_ready") {
|
|
246
166
|
console.info(`[plugin-xr] view ready on ${connId}: ${msg.viewId}`);
|
|
247
167
|
return;
|
|
248
168
|
}
|
|
249
|
-
|
|
250
169
|
if (msg.type === "view_closed") {
|
|
251
170
|
console.info(`[plugin-xr] view closed on ${connId}: ${msg.viewId}`);
|
|
252
171
|
return;
|
|
253
172
|
}
|
|
254
|
-
|
|
255
173
|
if (msg.type === "view_event") {
|
|
256
174
|
console.info(
|
|
257
175
|
`[plugin-xr] view event on ${connId}:`,
|
|
258
176
|
msg.viewId,
|
|
259
|
-
msg.event
|
|
177
|
+
msg.event
|
|
260
178
|
);
|
|
261
179
|
return;
|
|
262
180
|
}
|
|
263
181
|
}
|
|
264
|
-
|
|
265
|
-
private handleBinaryMessage(connId: string, data: Buffer): void {
|
|
182
|
+
handleBinaryMessage(connId, data) {
|
|
266
183
|
const conn = this.connections.get(connId);
|
|
267
184
|
if (!conn) return;
|
|
268
|
-
|
|
269
185
|
const { header, payload } = decodeBinaryFrame(data);
|
|
270
|
-
|
|
271
186
|
if (header.type === "audio") {
|
|
272
187
|
this.audioPipeline.push(connId, header, payload);
|
|
273
188
|
return;
|
|
274
189
|
}
|
|
275
|
-
|
|
276
190
|
if (header.type === "frame") {
|
|
277
191
|
this.visionPipeline.storeFrame(connId, header, payload);
|
|
278
192
|
return;
|
|
279
193
|
}
|
|
280
194
|
}
|
|
281
|
-
|
|
282
195
|
// ── Message routing ─────────────────────────────────────────────────────
|
|
283
|
-
|
|
284
|
-
private async handleTranscript(
|
|
285
|
-
connectionId: string,
|
|
286
|
-
transcript: string,
|
|
287
|
-
): Promise<void> {
|
|
196
|
+
async handleTranscript(connectionId, transcript) {
|
|
288
197
|
const conn = this.connections.get(connectionId);
|
|
289
198
|
if (!conn) return;
|
|
290
199
|
const runtime = this.runtime;
|
|
291
|
-
|
|
292
|
-
// Echo transcript back so the UI can show it
|
|
293
200
|
conn.ws.send(
|
|
294
|
-
JSON.stringify({ type: "transcript", text: transcript, final: true })
|
|
201
|
+
JSON.stringify({ type: "transcript", text: transcript, final: true })
|
|
295
202
|
);
|
|
296
|
-
|
|
297
|
-
// Attach latest camera frame as image attachment if available
|
|
298
203
|
const latestFrame = this.visionPipeline.getLatestFrame(connectionId);
|
|
299
|
-
const attachments
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
]
|
|
309
|
-
: [];
|
|
310
|
-
|
|
204
|
+
const attachments = latestFrame ? [
|
|
205
|
+
{
|
|
206
|
+
id: crypto.randomUUID(),
|
|
207
|
+
url: `data:image/${latestFrame.header.format};base64,${latestFrame.data.toString("base64")}`,
|
|
208
|
+
title: "XR camera frame",
|
|
209
|
+
contentType: "image",
|
|
210
|
+
source: "xr-camera"
|
|
211
|
+
}
|
|
212
|
+
] : [];
|
|
311
213
|
const memory = createMessageMemory({
|
|
312
214
|
entityId: conn.entityId,
|
|
313
215
|
agentId: runtime.agentId,
|
|
@@ -315,69 +217,51 @@ export class XRSessionService extends Service {
|
|
|
315
217
|
content: {
|
|
316
218
|
text: transcript,
|
|
317
219
|
source: `xr-${conn.deviceType}`,
|
|
318
|
-
attachments
|
|
319
|
-
}
|
|
220
|
+
attachments
|
|
221
|
+
}
|
|
320
222
|
});
|
|
321
|
-
|
|
322
223
|
await runtime.createMemory(memory, "messages");
|
|
323
|
-
|
|
324
|
-
const callback: HandlerCallback = async (
|
|
325
|
-
response: Content,
|
|
326
|
-
): Promise<Memory[]> => {
|
|
224
|
+
const callback = async (response) => {
|
|
327
225
|
const text = response.text?.trim() ?? "";
|
|
328
226
|
if (text.length === 0) return [];
|
|
329
|
-
|
|
330
|
-
// Send text response immediately
|
|
331
227
|
conn.ws.send(JSON.stringify({ type: "agent_text", text }));
|
|
332
|
-
|
|
333
|
-
// Generate TTS and send audio
|
|
334
228
|
try {
|
|
335
229
|
const audio = await runtime.useModel(ModelType.TEXT_TO_SPEECH, text);
|
|
336
|
-
const audioBuf = Buffer.isBuffer(audio)
|
|
337
|
-
? audio
|
|
338
|
-
: Buffer.from(audio as ArrayBuffer);
|
|
230
|
+
const audioBuf = Buffer.isBuffer(audio) ? audio : Buffer.from(audio);
|
|
339
231
|
this.sendAudio(connectionId, audioBuf);
|
|
340
232
|
} catch (err) {
|
|
341
233
|
console.error("[plugin-xr] TTS error:", err);
|
|
342
234
|
}
|
|
343
|
-
|
|
344
|
-
// Persist agent response as memory
|
|
345
235
|
const responseMemory = createMessageMemory({
|
|
346
236
|
entityId: runtime.agentId,
|
|
347
237
|
agentId: runtime.agentId,
|
|
348
238
|
roomId: conn.roomId,
|
|
349
|
-
content: { text, source: `xr-agent`, inReplyTo: memory.id }
|
|
239
|
+
content: { text, source: `xr-agent`, inReplyTo: memory.id }
|
|
350
240
|
});
|
|
351
241
|
await runtime.createMemory(responseMemory, "messages");
|
|
352
242
|
return [responseMemory];
|
|
353
243
|
};
|
|
354
|
-
|
|
355
244
|
if (runtime.messageService) {
|
|
356
245
|
await runtime.messageService.handleMessage(runtime, memory, callback);
|
|
357
246
|
}
|
|
358
247
|
}
|
|
359
|
-
|
|
360
248
|
// ── Entity / room bootstrap ─────────────────────────────────────────────
|
|
361
|
-
|
|
362
|
-
private async ensureEntities(
|
|
363
|
-
runtime: IAgentRuntime,
|
|
364
|
-
conn: XRConnection,
|
|
365
|
-
): Promise<void> {
|
|
249
|
+
async ensureEntities(runtime, conn) {
|
|
366
250
|
try {
|
|
367
251
|
await runtime.createEntity({
|
|
368
252
|
id: conn.entityId,
|
|
369
253
|
agentId: runtime.agentId,
|
|
370
254
|
names: [`XR-${conn.deviceType}`],
|
|
371
|
-
metadata: { source: `xr-${conn.deviceType}` }
|
|
255
|
+
metadata: { source: `xr-${conn.deviceType}` }
|
|
372
256
|
});
|
|
373
257
|
await runtime.createRoom({
|
|
374
258
|
id: conn.roomId,
|
|
375
259
|
name: `XR session (${conn.deviceType} ${conn.id.slice(0, 8)})`,
|
|
376
260
|
source: "xr",
|
|
377
261
|
type: ChannelType.GROUP,
|
|
378
|
-
worldId:
|
|
379
|
-
channelId:
|
|
380
|
-
messageServerId:
|
|
262
|
+
worldId: void 0,
|
|
263
|
+
channelId: void 0,
|
|
264
|
+
messageServerId: void 0
|
|
381
265
|
});
|
|
382
266
|
await runtime.addParticipant(conn.entityId, conn.roomId);
|
|
383
267
|
await runtime.addParticipant(runtime.agentId, conn.roomId);
|
|
@@ -386,3 +270,10 @@ export class XRSessionService extends Service {
|
|
|
386
270
|
}
|
|
387
271
|
}
|
|
388
272
|
}
|
|
273
|
+
export {
|
|
274
|
+
XRSessionService,
|
|
275
|
+
XR_SERVICE_TYPE,
|
|
276
|
+
XR_WS_PORT_DEFAULT,
|
|
277
|
+
XR_WS_PORT_ENV
|
|
278
|
+
};
|
|
279
|
+
//# sourceMappingURL=xr-session-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/xr-session-service.ts"],"sourcesContent":["import type {\n Content,\n HandlerCallback,\n IAgentRuntime,\n Memory,\n UUID,\n} from \"@elizaos/core\";\nimport {\n ChannelType,\n createMessageMemory,\n ModelType,\n Service,\n} from \"@elizaos/core\";\nimport { type WebSocket, WebSocketServer } from \"ws\";\nimport {\n decodeBinaryFrame,\n encodeBinaryFrame,\n type XRClientControl,\n type XRDeviceType,\n type XRPanelConfig,\n type XRServerControl,\n type XRTTSAudioHeader,\n} from \"../protocol.js\";\nimport { AudioPipeline } from \"./audio-pipeline.js\";\nimport { VisionPipeline } from \"./vision-pipeline.js\";\n\nexport const XR_SERVICE_TYPE = \"xr-session\";\nexport const XR_WS_PORT_DEFAULT = 31338;\nexport const XR_WS_PORT_ENV = \"XR_WS_PORT\";\n\nexport interface XRConnection {\n id: string;\n ws: WebSocket;\n deviceType: XRDeviceType;\n entityId: UUID;\n roomId: UUID;\n connectedAt: Date;\n}\n\nexport class XRSessionService extends Service {\n static override serviceType = XR_SERVICE_TYPE;\n\n readonly capabilityDescription =\n \"Streams audio and camera from XR headsets (Quest 3, XReal) to the agent and returns voice responses.\";\n\n private wss!: WebSocketServer;\n private connections = new Map<string, XRConnection>();\n private audioPipeline!: AudioPipeline;\n private visionPipeline!: VisionPipeline;\n\n static override async start(runtime: IAgentRuntime): Promise<Service> {\n const svc = new XRSessionService(runtime);\n await svc.initialize(runtime);\n return svc;\n }\n\n private async initialize(runtime: IAgentRuntime): Promise<void> {\n this.visionPipeline = new VisionPipeline();\n this.audioPipeline = new AudioPipeline(\n runtime,\n (connectionId, transcript) =>\n this.handleTranscript(connectionId, transcript),\n );\n\n const port = Number(\n runtime.getSetting(XR_WS_PORT_ENV) ?? XR_WS_PORT_DEFAULT,\n );\n this.wss = new WebSocketServer({ port });\n\n this.wss.on(\"connection\", (ws: WebSocket) => this.onConnect(runtime, ws));\n this.wss.on(\"error\", (err: Error) =>\n console.error(\"[plugin-xr] WebSocket server error:\", err),\n );\n\n console.info(\n `[plugin-xr] WebSocket server listening on ws://localhost:${port}`,\n );\n }\n\n override async stop(): Promise<void> {\n for (const conn of this.connections.values()) {\n this.audioPipeline.clear(conn.id);\n this.visionPipeline.clear(conn.id);\n conn.ws.close();\n }\n this.connections.clear();\n await new Promise<void>((resolve) => this.wss.close(() => resolve()));\n }\n\n // ── Public accessors used by provider / action ──────────────────────────\n\n getConnections(): XRConnection[] {\n return [...this.connections.values()];\n }\n\n hasActiveConnections(): boolean {\n return this.connections.size > 0;\n }\n\n getVisionPipeline(): VisionPipeline {\n return this.visionPipeline;\n }\n\n sendText(connectionId: string, text: string): void {\n const conn = this.connections.get(connectionId);\n if (!conn || conn.ws.readyState !== conn.ws.OPEN) return;\n conn.ws.send(JSON.stringify({ type: \"agent_text\", text }));\n }\n\n sendControl(connectionId: string, msg: XRServerControl): void {\n const conn = this.connections.get(connectionId);\n if (!conn || conn.ws.readyState !== conn.ws.OPEN) return;\n conn.ws.send(JSON.stringify(msg));\n }\n\n broadcastControl(msg: XRServerControl): void {\n for (const conn of this.connections.values()) {\n if (conn.ws.readyState === conn.ws.OPEN) {\n conn.ws.send(JSON.stringify(msg));\n }\n }\n }\n\n openView(\n connectionId: string,\n viewId: string,\n agentBaseUrl: string,\n config?: XRPanelConfig,\n ): void {\n this.sendControl(connectionId, {\n type: \"view_open\",\n viewId,\n agentBaseUrl,\n config,\n });\n }\n\n closeView(connectionId: string, viewId: string): void {\n this.sendControl(connectionId, { type: \"view_close\", viewId });\n }\n\n switchView(connectionId: string, viewId: string): void {\n this.sendControl(connectionId, { type: \"view_switch\", viewId });\n }\n\n resizeView(\n connectionId: string,\n viewId: string,\n config: XRPanelConfig,\n ): void {\n this.sendControl(connectionId, { type: \"view_resize\", viewId, config });\n }\n\n sendViewsCatalog(\n connectionId: string,\n views: Array<{\n id: string;\n label: string;\n icon?: string;\n description?: string;\n }>,\n ): void {\n this.sendControl(connectionId, { type: \"views_catalog\", views });\n }\n\n sendAudio(connectionId: string, audio: Buffer, sampleRate = 24000): void {\n const conn = this.connections.get(connectionId);\n if (!conn || conn.ws.readyState !== conn.ws.OPEN) return;\n const header: XRTTSAudioHeader = {\n type: \"tts_audio\",\n sampleRate,\n channels: 1,\n encoding: \"mp3\",\n };\n conn.ws.send(encodeBinaryFrame(header, audio), { binary: true });\n }\n\n // ── WebSocket connection lifecycle ──────────────────────────────────────\n\n private onConnect(runtime: IAgentRuntime, ws: WebSocket): void {\n const connId = crypto.randomUUID();\n\n ws.on(\"message\", (data: unknown, isBinary: boolean) => {\n try {\n if (isBinary) {\n this.handleBinaryMessage(connId, data as Buffer);\n } else {\n const raw =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString(\"utf8\")\n : String(data);\n this.handleTextMessage(runtime, connId, ws, raw);\n }\n } catch (err) {\n console.error(\"[plugin-xr] message handler error:\", err);\n }\n });\n\n ws.on(\"close\", () => {\n this.audioPipeline.flush(connId);\n this.audioPipeline.clear(connId);\n this.visionPipeline.clear(connId);\n this.connections.delete(connId);\n console.info(`[plugin-xr] device disconnected: ${connId}`);\n });\n\n ws.on(\"error\", (err: Error) =>\n console.error(`[plugin-xr] ws error on ${connId}:`, err),\n );\n }\n\n private handleTextMessage(\n runtime: IAgentRuntime,\n connId: string,\n ws: WebSocket,\n raw: string,\n ): void {\n const msg = JSON.parse(raw) as XRClientControl;\n\n if (msg.type === \"hello\") {\n const entityId = crypto.randomUUID() as UUID;\n const roomId = crypto.randomUUID() as UUID;\n const conn: XRConnection = {\n id: connId,\n ws,\n deviceType: msg.deviceType,\n entityId,\n roomId,\n connectedAt: new Date(),\n };\n this.connections.set(connId, conn);\n ws.send(JSON.stringify({ type: \"ready\", sessionId: connId }));\n void this.ensureEntities(runtime, conn);\n console.info(`[plugin-xr] ${msg.deviceType} connected: ${connId}`);\n return;\n }\n\n if (msg.type === \"ping\") {\n ws.send(JSON.stringify({ type: \"pong\" }));\n return;\n }\n\n if (msg.type === \"view_ready\") {\n console.info(`[plugin-xr] view ready on ${connId}: ${msg.viewId}`);\n return;\n }\n\n if (msg.type === \"view_closed\") {\n console.info(`[plugin-xr] view closed on ${connId}: ${msg.viewId}`);\n return;\n }\n\n if (msg.type === \"view_event\") {\n console.info(\n `[plugin-xr] view event on ${connId}:`,\n msg.viewId,\n msg.event,\n );\n return;\n }\n }\n\n private handleBinaryMessage(connId: string, data: Buffer): void {\n const conn = this.connections.get(connId);\n if (!conn) return;\n\n const { header, payload } = decodeBinaryFrame(data);\n\n if (header.type === \"audio\") {\n this.audioPipeline.push(connId, header, payload);\n return;\n }\n\n if (header.type === \"frame\") {\n this.visionPipeline.storeFrame(connId, header, payload);\n return;\n }\n }\n\n // ── Message routing ─────────────────────────────────────────────────────\n\n private async handleTranscript(\n connectionId: string,\n transcript: string,\n ): Promise<void> {\n const conn = this.connections.get(connectionId);\n if (!conn) return;\n const runtime = this.runtime;\n\n // Echo transcript back so the UI can show it\n conn.ws.send(\n JSON.stringify({ type: \"transcript\", text: transcript, final: true }),\n );\n\n // Attach latest camera frame as image attachment if available\n const latestFrame = this.visionPipeline.getLatestFrame(connectionId);\n const attachments: Content[\"attachments\"] = latestFrame\n ? [\n {\n id: crypto.randomUUID(),\n url: `data:image/${latestFrame.header.format};base64,${latestFrame.data.toString(\"base64\")}`,\n title: \"XR camera frame\",\n contentType: \"image\",\n source: \"xr-camera\",\n },\n ]\n : [];\n\n const memory = createMessageMemory({\n entityId: conn.entityId,\n agentId: runtime.agentId,\n roomId: conn.roomId,\n content: {\n text: transcript,\n source: `xr-${conn.deviceType}`,\n attachments,\n },\n });\n\n await runtime.createMemory(memory, \"messages\");\n\n const callback: HandlerCallback = async (\n response: Content,\n ): Promise<Memory[]> => {\n const text = response.text?.trim() ?? \"\";\n if (text.length === 0) return [];\n\n // Send text response immediately\n conn.ws.send(JSON.stringify({ type: \"agent_text\", text }));\n\n // Generate TTS and send audio\n try {\n const audio = await runtime.useModel(ModelType.TEXT_TO_SPEECH, text);\n const audioBuf = Buffer.isBuffer(audio)\n ? audio\n : Buffer.from(audio as ArrayBuffer);\n this.sendAudio(connectionId, audioBuf);\n } catch (err) {\n console.error(\"[plugin-xr] TTS error:\", err);\n }\n\n // Persist agent response as memory\n const responseMemory = createMessageMemory({\n entityId: runtime.agentId,\n agentId: runtime.agentId,\n roomId: conn.roomId,\n content: { text, source: `xr-agent`, inReplyTo: memory.id },\n });\n await runtime.createMemory(responseMemory, \"messages\");\n return [responseMemory];\n };\n\n if (runtime.messageService) {\n await runtime.messageService.handleMessage(runtime, memory, callback);\n }\n }\n\n // ── Entity / room bootstrap ─────────────────────────────────────────────\n\n private async ensureEntities(\n runtime: IAgentRuntime,\n conn: XRConnection,\n ): Promise<void> {\n try {\n await runtime.createEntity({\n id: conn.entityId,\n agentId: runtime.agentId,\n names: [`XR-${conn.deviceType}`],\n metadata: { source: `xr-${conn.deviceType}` },\n });\n await runtime.createRoom({\n id: conn.roomId,\n name: `XR session (${conn.deviceType} ${conn.id.slice(0, 8)})`,\n source: \"xr\",\n type: ChannelType.GROUP,\n worldId: undefined,\n channelId: undefined,\n messageServerId: undefined,\n });\n await runtime.addParticipant(conn.entityId, conn.roomId);\n await runtime.addParticipant(runtime.agentId, conn.roomId);\n } catch (err) {\n console.error(\"[plugin-xr] entity setup error:\", err);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/plugin-xr",
|
|
3
|
-
"version": "2.0.3-beta.
|
|
3
|
+
"version": "2.0.3-beta.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "WebXR audio/video streaming for elizaOS — Quest 3 and XReal glasses",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
7
11
|
"exports": {
|
|
8
12
|
"./package.json": "./package.json",
|
|
9
13
|
".": {
|
|
@@ -22,6 +26,7 @@
|
|
|
22
26
|
"lint": "bunx @biomejs/biome check src",
|
|
23
27
|
"test": "bunx vitest run --config ./vitest.config.ts",
|
|
24
28
|
"build": "bun run build:js && bun run build:types",
|
|
29
|
+
"prepack": "bun run build",
|
|
25
30
|
"build:all": "bun run build && bun run simulator:build",
|
|
26
31
|
"clean": "node ../../packages/scripts/rm-path-recursive.mjs dist simulator/dist",
|
|
27
32
|
"build:js": "tsup --config ../tsup.plugin-packages.shared.ts",
|
|
@@ -30,8 +35,8 @@
|
|
|
30
35
|
"simulator:watch": "cd simulator && bun run build:watch"
|
|
31
36
|
},
|
|
32
37
|
"dependencies": {
|
|
33
|
-
"@elizaos/agent": "2.0.3-beta.
|
|
34
|
-
"@elizaos/core": "2.0.3-beta.
|
|
38
|
+
"@elizaos/agent": "2.0.3-beta.7",
|
|
39
|
+
"@elizaos/core": "2.0.3-beta.7",
|
|
35
40
|
"ws": "^8.18.0",
|
|
36
41
|
"zod": "^4.4.3"
|
|
37
42
|
},
|
|
@@ -53,5 +58,5 @@
|
|
|
53
58
|
"publishConfig": {
|
|
54
59
|
"access": "public"
|
|
55
60
|
},
|
|
56
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "61094f10458d11055c75b3dd0bae374e3f66bac5"
|
|
57
62
|
}
|