const assert = require("node:assert/strict"); const { EventEmitter } = require("node:events"); const test = require("node:test"); const { HardwareAgentClient, buildSessionUpdate, websocketSignature, } = require("./hardware-agent-client.cjs"); test("WebSocket signatures use the documented canonical field order", () => { const connection = websocketSignature({ authType: 1, deviceName: "device-1", randomNumber: 42, productKey: "product-1", timestamp: 1700000000, instanceID: "instance-1" }, "device-secret"); assert.equal(connection, "6OFE1DUZzRgNy0o5IzZSmqKw3SUP4s3GxK2YHe8phfo="); }); test("LLM session update uses the official Config/AgentConfig schema", () => { const update = buildSessionUpdate({ dialog_id: "conversation-1", system_prompt: "你是陪伴助手", persona_tone: "亲切", authorized_context: "只可使用已授权背景" }, "event-1"); assert.equal(update.type, "session.update"); assert.equal(update.session.object, "realtime.session"); assert.equal(update.session.input_audio_format, "pcm16"); assert.equal(update.session.output_audio_format, "pcm16"); assert.equal(update.session.config.ASRConfig.TurnDetectionMode, 0); assert.match(update.session.config.LLMConfig.SystemMessages[0], /只可使用已授权背景/); assert.match(update.session.config.LLMConfig.SystemMessages[0], /你是陪伴助手/); assert.match(update.session.config.LLMConfig.SystemMessages[0], /亲切/); assert.equal(update.session.agent_config.EnableConversationStateCallback, false); assert.equal("system_prompt" in update.session, false); }); test("S2S session update maps persona and dialog id to provider dialog config", () => { const update = buildSessionUpdate({ dialog_id: "conversation-2", system_prompt: "你是陪伴助手", persona_tone: "亲切自然", authorized_context: "只使用授权信息" }, "event-2", "s2s"); const dialog = update.session.config.S2SConfig.ProviderParams.dialog; assert.equal(dialog.dialog_id, "conversation-2"); assert.equal(dialog.speaking_style, "亲切自然"); assert.match(dialog.system_role, /只使用授权信息/); assert.match(dialog.system_role, /你是陪伴助手/); assert.equal("LLMConfig" in update.session.config, false); }); class FakeWebSocket extends EventEmitter { static OPEN = 1; constructor(url, options) { super(); this.url = url; this.options = options; this.readyState = 0; this.sent = []; FakeWebSocket.last = this; setImmediate(() => { this.readyState = FakeWebSocket.OPEN; this.emit("open"); this.emit("message", Buffer.from(JSON.stringify({ type: "session.created", event_id: "created-event", session: { id: "provider-session-1" } }))); }); } send(body) { const value = JSON.parse(body); this.sent.push(value); if (value.type === "session.update") { setImmediate(() => this.emit("message", Buffer.from(JSON.stringify({ type: "session.updated", event_id: "updated-event", session: { id: "provider-session-1" } })))); } } ping() {} close(code, reason) { this.readyState = 3; this.emit("close", code, Buffer.from(reason)); } } test("hardware client waits for dynamic config acknowledgement before becoming ready", async () => { const events = []; const client = new HardwareAgentClient({ WebSocketImpl: FakeWebSocket, gatewayURL: "ws://127.0.0.1:19090/v1/realtime", emit: (event) => events.push(event) }); const connected = await client.connect({ instanceID: "instance-1", productKey: "product-1", deviceName: "device-1", deviceSecret: "device-secret-with-at-least-32-characters", hardwareID: "windows-test", botID: "bot-1", sessionConfig: { dialog_id: "conversation-1", authorized_context: "authorized" }, }); assert.equal(connected.providerConnectionRef, "provider-session-1"); assert.match(FakeWebSocket.last.url, /bot=bot-1/); assert.equal(FakeWebSocket.last.options.headers["X-Product-Key"], "product-1"); assert.equal(FakeWebSocket.last.sent[0].type, "session.update"); client.sendAudio(Buffer.from([1, 2, 3, 4])); client.sendText("你好"); assert.equal(FakeWebSocket.last.sent[1].type, "input_audio_buffer.append"); assert.equal(FakeWebSocket.last.sent[2].type, "conversation.item.create"); assert.ok(events.some((event) => event.type === "session.created")); client.close(); }); test("hardware client sends session.update immediately when the WebSocket opens", async () => { const client = new HardwareAgentClient({ WebSocketImpl: FakeWebSocket, gatewayURL: "ws://127.0.0.1:19090/v1/realtime" }); await client.connect({ instanceID: "instance-1", productKey: "product-1", deviceName: "device-1", deviceSecret: "device-secret-with-at-least-32-characters", hardwareID: "windows-test", botID: "bot-1", sessionConfig: { dialog_id: "conversation-1", authorized_context: "authorized" }, }); assert.equal(FakeWebSocket.last.sent.filter((event) => event.type === "session.update").length, 1); client.close(); });