@jait/gateway 0.1.285 → 0.1.287
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/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -1
- package/dist/security/consent-executor.d.ts.map +1 -1
- package/dist/security/consent-executor.js +2 -1
- package/dist/security/consent-executor.js.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -0
- package/dist/server.js.map +1 -1
- package/dist/voice-assistant/service.d.ts +32 -0
- package/dist/voice-assistant/service.d.ts.map +1 -0
- package/dist/voice-assistant/service.js +334 -0
- package/dist/voice-assistant/service.js.map +1 -0
- package/dist/voice-assistant/tools.d.ts +43 -0
- package/dist/voice-assistant/tools.d.ts.map +1 -0
- package/dist/voice-assistant/tools.js +319 -0
- package/dist/voice-assistant/tools.js.map +1 -0
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +2 -0
- package/dist/ws.js.map +1 -1
- package/package.json +1 -1
- package/web-dist/assets/{_basePickBy-iKHSAv9J.js → _basePickBy-Cjxzc01J.js} +1 -1
- package/web-dist/assets/{_baseUniq-DMeT0pJj.js → _baseUniq-NbnbvTNe.js} +1 -1
- package/web-dist/assets/{arc-CGqtn5e9.js → arc-sjbQWpKN.js} +1 -1
- package/web-dist/assets/{architectureDiagram-2XIMDMQ5-CfDUNvKd.js → architectureDiagram-2XIMDMQ5-C59dkK7J.js} +1 -1
- package/web-dist/assets/{blockDiagram-WCTKOSBZ-DGTIDF2n.js → blockDiagram-WCTKOSBZ-Ch81z-ka.js} +1 -1
- package/web-dist/assets/{c4Diagram-IC4MRINW-DLJ_8zRP.js → c4Diagram-IC4MRINW-q-IBkAlF.js} +1 -1
- package/web-dist/assets/channel-CvsvZnto.js +1 -0
- package/web-dist/assets/{chunk-4BX2VUAB-B1XVFqID.js → chunk-4BX2VUAB-wMrDDNFp.js} +1 -1
- package/web-dist/assets/{chunk-55IACEB6-DPRSsuyS.js → chunk-55IACEB6-F0HKyV7v.js} +1 -1
- package/web-dist/assets/{chunk-FMBD7UC4-BYVMDPXy.js → chunk-FMBD7UC4-I65gRvS0.js} +1 -1
- package/web-dist/assets/{chunk-JSJVCQXG-Cw9QARvp.js → chunk-JSJVCQXG-DobmbqUN.js} +1 -1
- package/web-dist/assets/{chunk-KX2RTZJC-CdsXoqTv.js → chunk-KX2RTZJC-CsvYhT2y.js} +1 -1
- package/web-dist/assets/{chunk-NQ4KR5QH-B9TGfzNG.js → chunk-NQ4KR5QH-DT6T2b0X.js} +1 -1
- package/web-dist/assets/{chunk-QZHKN3VN-DnIelMmh.js → chunk-QZHKN3VN-DKN7qICz.js} +1 -1
- package/web-dist/assets/{chunk-WL4C6EOR-B7rDWqqK.js → chunk-WL4C6EOR-BznI3N4f.js} +1 -1
- package/web-dist/assets/classDiagram-VBA2DB6C-DWPdxtuK.js +1 -0
- package/web-dist/assets/classDiagram-v2-RAHNMMFH-DWPdxtuK.js +1 -0
- package/web-dist/assets/clone-BeLQd6cd.js +1 -0
- package/web-dist/assets/{cose-bilkent-S5V4N54A-CFZXcxJ8.js → cose-bilkent-S5V4N54A-BcKelYqc.js} +1 -1
- package/web-dist/assets/{dagre-KLK3FWXG-U3J3AQYl.js → dagre-KLK3FWXG-DqcsX5_X.js} +1 -1
- package/web-dist/assets/{diagram-E7M64L7V-B3xMDzyO.js → diagram-E7M64L7V-CwipS7AH.js} +1 -1
- package/web-dist/assets/{diagram-IFDJBPK2-DX6eykyv.js → diagram-IFDJBPK2-DAYNwdjc.js} +1 -1
- package/web-dist/assets/{diagram-P4PSJMXO-IYL1yCXF.js → diagram-P4PSJMXO-DViwUtvH.js} +1 -1
- package/web-dist/assets/{erDiagram-INFDFZHY-XAnpSjmF.js → erDiagram-INFDFZHY-DlAd7AQ0.js} +1 -1
- package/web-dist/assets/{flowDiagram-PKNHOUZH-DmIQjuwF.js → flowDiagram-PKNHOUZH-C2n7C8g1.js} +1 -1
- package/web-dist/assets/{ganttDiagram-A5KZAMGK-C0HvwzKb.js → ganttDiagram-A5KZAMGK-DmC1xSRo.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-K3NZZRJ6-C9fBjque.js → gitGraphDiagram-K3NZZRJ6-D4Pm2tXD.js} +1 -1
- package/web-dist/assets/{graph-BsUOCCiq.js → graph-UZ9pW7eu.js} +1 -1
- package/web-dist/assets/{index-CsxEtnuR.js → index-BhZLpix_.js} +677 -494
- package/web-dist/assets/index-Cp_4Lw_K.css +32 -0
- package/web-dist/assets/{infoDiagram-LFFYTUFH-Bgj0YmBs.js → infoDiagram-LFFYTUFH-BcvLSvXM.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-PHBUUO56-Bi4W8qsd.js → ishikawaDiagram-PHBUUO56-FEeReZlB.js} +1 -1
- package/web-dist/assets/{journeyDiagram-4ABVD52K-BOeR5DGC.js → journeyDiagram-4ABVD52K-C_Og_y9F.js} +1 -1
- package/web-dist/assets/{kanban-definition-K7BYSVSG-BZQAw3zY.js → kanban-definition-K7BYSVSG-CPxP6u5Y.js} +1 -1
- package/web-dist/assets/{layout-CV-vePE7.js → layout-DUk9sVmi.js} +1 -1
- package/web-dist/assets/{linear-cNCjBUyl.js → linear-CCXFG29Q.js} +1 -1
- package/web-dist/assets/{mindmap-definition-YRQLILUH-DgP0-yhh.js → mindmap-definition-YRQLILUH-DMFec7aM.js} +1 -1
- package/web-dist/assets/{pieDiagram-SKSYHLDU-3PQI6gKL.js → pieDiagram-SKSYHLDU-DeQxt4JU.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-337W2JSQ-wZBUcM9U.js → quadrantDiagram-337W2JSQ-hLwKNuCR.js} +1 -1
- package/web-dist/assets/{requirementDiagram-Z7DCOOCP-DsDylirs.js → requirementDiagram-Z7DCOOCP-cqA5lNGF.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-WA2Y5GQK-qSCxyZGK.js → sankeyDiagram-WA2Y5GQK-wicGzPcI.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-2WXFIKYE-W2UjBOuu.js → sequenceDiagram-2WXFIKYE-Co7HoPBu.js} +1 -1
- package/web-dist/assets/{stateDiagram-RAJIS63D-Bfy7DB0r.js → stateDiagram-RAJIS63D-_3VSf9_5.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-FVOUBMTO-CBL7Ut8d.js +1 -0
- package/web-dist/assets/{timeline-definition-YZTLITO2--CHHDyOZ.js → timeline-definition-YZTLITO2-CHAGimQb.js} +1 -1
- package/web-dist/assets/{treemap-KZPCXAKY-ZQLFTfSZ.js → treemap-KZPCXAKY-Chs6jXXs.js} +1 -1
- package/web-dist/assets/{vennDiagram-LZ73GAT5-Bh75zo1O.js → vennDiagram-LZ73GAT5-CeT-167L.js} +1 -1
- package/web-dist/assets/{xychartDiagram-JWTSCODW-CYXFCyTo.js → xychartDiagram-JWTSCODW-Bo64fvUB.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/channel-BI2fCn1L.js +0 -1
- package/web-dist/assets/classDiagram-VBA2DB6C-BirRGMr3.js +0 -1
- package/web-dist/assets/classDiagram-v2-RAHNMMFH-BirRGMr3.js +0 -1
- package/web-dist/assets/clone-CNBtoui7.js +0 -1
- package/web-dist/assets/index-DLnxug6y.css +0 -32
- package/web-dist/assets/stateDiagram-v2-FVOUBMTO-i02ov9wx.js +0 -1
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Voice-assistant service — bridges the browser to OpenAI's Realtime API.
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* Browser ←WebSocket→ Gateway ←WebSocket→ OpenAI Realtime API
|
|
6
|
+
*
|
|
7
|
+
* The gateway sits in the middle, relaying audio in both directions and
|
|
8
|
+
* intercepting function calls to execute them locally with full Jait access.
|
|
9
|
+
* This is a GLOBAL session — not tied to any workspace.
|
|
10
|
+
*/
|
|
11
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
12
|
+
import { getVoiceToolSchemas, executeVoiceTool } from "./tools.js";
|
|
13
|
+
export class VoiceAssistantService {
|
|
14
|
+
wss;
|
|
15
|
+
deps;
|
|
16
|
+
constructor(deps) {
|
|
17
|
+
this.deps = deps;
|
|
18
|
+
this.wss = new WebSocketServer({ noServer: true });
|
|
19
|
+
this.wss.on("connection", (ws, req) => {
|
|
20
|
+
this.handleConnection(ws, req).catch((err) => {
|
|
21
|
+
console.error("[voice-assistant] Connection handler error:", err);
|
|
22
|
+
try {
|
|
23
|
+
ws.close(1011, "Internal error");
|
|
24
|
+
}
|
|
25
|
+
catch { }
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/** Handle HTTP → WebSocket upgrade for the /ws/voice-assistant path. */
|
|
30
|
+
handleUpgrade(request, socket, head) {
|
|
31
|
+
this.wss.handleUpgrade(request, socket, head, (ws) => {
|
|
32
|
+
this.wss.emit("connection", ws, request);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async handleConnection(clientWs, req) {
|
|
36
|
+
// ── Auth ──────────────────────────────────────────────────
|
|
37
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
38
|
+
const token = url.searchParams.get("token") ?? "";
|
|
39
|
+
const user = await this.deps.verifyToken(token);
|
|
40
|
+
if (!user) {
|
|
41
|
+
send(clientWs, { type: "error", message: "Unauthorized" });
|
|
42
|
+
clientWs.close(4001, "Unauthorized");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// ── Resolve API key: user settings first, then server config ─
|
|
46
|
+
const userApiKeys = this.deps.getUserApiKeys?.(user.id) ?? {};
|
|
47
|
+
const apiKey = userApiKeys.OPENAI_API_KEY?.trim() || this.deps.config.openaiApiKey;
|
|
48
|
+
if (!apiKey) {
|
|
49
|
+
send(clientWs, { type: "error", message: "OpenAI API key not configured. Set it in Settings → API Keys." });
|
|
50
|
+
clientWs.close(4002, "Not configured");
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
console.log(`[voice-assistant] ${user.username} connected (key source: ${userApiKeys.OPENAI_API_KEY ? "user" : "server"})`);
|
|
54
|
+
// ── Connect to OpenAI Realtime API ───────────────────────
|
|
55
|
+
const model = this.deps.config.realtimeModel;
|
|
56
|
+
const openaiUrl = `wss://api.openai.com/v1/realtime?model=${encodeURIComponent(model)}`;
|
|
57
|
+
let openaiWs;
|
|
58
|
+
try {
|
|
59
|
+
openaiWs = new WebSocket(openaiUrl, {
|
|
60
|
+
headers: {
|
|
61
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
send(clientWs, { type: "error", message: `Failed to connect to OpenAI: ${err}` });
|
|
67
|
+
clientWs.close(4003, "OpenAI connection failed");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
let openaiReady = false;
|
|
71
|
+
let responseInProgress = false;
|
|
72
|
+
let pendingToolResponse = false;
|
|
73
|
+
// ── OpenAI → Gateway → Browser ───────────────────────────
|
|
74
|
+
openaiWs.on("open", () => {
|
|
75
|
+
openaiReady = true;
|
|
76
|
+
console.log(`[voice-assistant] OpenAI Realtime connected (model: ${model})`);
|
|
77
|
+
// Configure the session
|
|
78
|
+
const sessionUpdate = {
|
|
79
|
+
type: "session.update",
|
|
80
|
+
session: {
|
|
81
|
+
type: "realtime",
|
|
82
|
+
instructions: this.buildInstructions(user.username),
|
|
83
|
+
tools: getVoiceToolSchemas(),
|
|
84
|
+
tool_choice: "auto",
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
openaiWs.send(JSON.stringify(sessionUpdate));
|
|
88
|
+
send(clientWs, { type: "session.started" });
|
|
89
|
+
send(clientWs, { type: "status", status: "listening" });
|
|
90
|
+
});
|
|
91
|
+
openaiWs.on("message", async (raw) => {
|
|
92
|
+
let event;
|
|
93
|
+
try {
|
|
94
|
+
event = JSON.parse(typeof raw === "string" ? raw : raw.toString());
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Debug: log all events from OpenAI
|
|
100
|
+
if (event.type !== "response.audio.delta") {
|
|
101
|
+
console.log(`[voice-assistant] OpenAI event: ${event.type}`, event.type === "error" ? event.error : "");
|
|
102
|
+
}
|
|
103
|
+
switch (event.type) {
|
|
104
|
+
// ── Audio from assistant ──────────────────────────────
|
|
105
|
+
case "response.audio.delta":
|
|
106
|
+
case "response.output_audio.delta":
|
|
107
|
+
responseInProgress = true;
|
|
108
|
+
send(clientWs, { type: "audio", data: event.delta });
|
|
109
|
+
send(clientWs, { type: "status", status: "speaking" });
|
|
110
|
+
break;
|
|
111
|
+
case "response.audio.done":
|
|
112
|
+
case "response.output_audio.done":
|
|
113
|
+
responseInProgress = false;
|
|
114
|
+
send(clientWs, { type: "audio.done" });
|
|
115
|
+
send(clientWs, { type: "status", status: "listening" });
|
|
116
|
+
break;
|
|
117
|
+
// ── Transcription ────────────────────────────────────
|
|
118
|
+
case "conversation.item.input_audio_transcription.completed":
|
|
119
|
+
send(clientWs, { type: "transcript", role: "user", text: event.transcript ?? "", final: true });
|
|
120
|
+
break;
|
|
121
|
+
case "response.audio_transcript.delta":
|
|
122
|
+
case "response.output_audio_transcript.delta":
|
|
123
|
+
send(clientWs, { type: "transcript", role: "assistant", text: event.delta ?? "", final: false });
|
|
124
|
+
break;
|
|
125
|
+
case "response.audio_transcript.done":
|
|
126
|
+
case "response.output_audio_transcript.done":
|
|
127
|
+
send(clientWs, { type: "transcript", role: "assistant", text: event.transcript ?? "", final: true });
|
|
128
|
+
break;
|
|
129
|
+
// ── Function calls ───────────────────────────────────
|
|
130
|
+
case "response.function_call_arguments.done": {
|
|
131
|
+
const callId = event.call_id;
|
|
132
|
+
const fnName = event.name;
|
|
133
|
+
let fnArgs = {};
|
|
134
|
+
try {
|
|
135
|
+
fnArgs = JSON.parse(event.arguments ?? "{}");
|
|
136
|
+
}
|
|
137
|
+
catch { }
|
|
138
|
+
console.log(`[voice-assistant] Tool call: ${fnName}`, JSON.stringify(fnArgs));
|
|
139
|
+
send(clientWs, { type: "tool_call", name: fnName, status: "running" });
|
|
140
|
+
send(clientWs, { type: "status", status: "thinking" });
|
|
141
|
+
const connectionDeps = { ...this.deps, userApiKeys };
|
|
142
|
+
const result = await executeVoiceTool(fnName, fnArgs, connectionDeps);
|
|
143
|
+
// ── Handle stop_voice: say goodbye then close ──
|
|
144
|
+
if (result === "__STOP_VOICE__") {
|
|
145
|
+
send(clientWs, { type: "tool_call", name: fnName, status: "completed", result: "Ending session." });
|
|
146
|
+
send(clientWs, { type: "status", status: "disconnected" });
|
|
147
|
+
// Give the client a moment to process, then close
|
|
148
|
+
setTimeout(() => {
|
|
149
|
+
try {
|
|
150
|
+
openaiWs.close(1000, "Voice stopped by assistant");
|
|
151
|
+
}
|
|
152
|
+
catch { }
|
|
153
|
+
try {
|
|
154
|
+
clientWs.close(1000, "Voice stopped by assistant");
|
|
155
|
+
}
|
|
156
|
+
catch { }
|
|
157
|
+
}, 500);
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
send(clientWs, { type: "tool_call", name: fnName, status: "completed", result });
|
|
161
|
+
// Send function output back to OpenAI
|
|
162
|
+
if (openaiWs.readyState === WebSocket.OPEN) {
|
|
163
|
+
openaiWs.send(JSON.stringify({
|
|
164
|
+
type: "conversation.item.create",
|
|
165
|
+
item: {
|
|
166
|
+
type: "function_call_output",
|
|
167
|
+
call_id: callId,
|
|
168
|
+
output: result,
|
|
169
|
+
},
|
|
170
|
+
}));
|
|
171
|
+
// Only create a new response if none is in progress; otherwise defer
|
|
172
|
+
if (!responseInProgress) {
|
|
173
|
+
openaiWs.send(JSON.stringify({ type: "response.create" }));
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
pendingToolResponse = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
// ── Errors ───────────────────────────────────────────
|
|
182
|
+
case "error": {
|
|
183
|
+
const errMsg = event.error?.message ?? "OpenAI error";
|
|
184
|
+
// Suppress harmless "no active response" from cancel attempts
|
|
185
|
+
if (errMsg.includes("no active response"))
|
|
186
|
+
break;
|
|
187
|
+
console.error("[voice-assistant] OpenAI error:", event.error);
|
|
188
|
+
send(clientWs, { type: "error", message: errMsg });
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
// ── Interruption (server VAD detected user speech) ───
|
|
192
|
+
case "input_audio_buffer.speech_started":
|
|
193
|
+
// User started speaking — cancel only if assistant is actively responding
|
|
194
|
+
if (responseInProgress) {
|
|
195
|
+
openaiWs.send(JSON.stringify({ type: "response.cancel" }));
|
|
196
|
+
send(clientWs, { type: "audio.interrupt" });
|
|
197
|
+
responseInProgress = false;
|
|
198
|
+
}
|
|
199
|
+
send(clientWs, { type: "status", status: "listening" });
|
|
200
|
+
break;
|
|
201
|
+
case "conversation.item.truncated":
|
|
202
|
+
// Acknowledged by OpenAI after we sent conversation.item.truncate
|
|
203
|
+
break;
|
|
204
|
+
case "input_audio_buffer.speech_stopped":
|
|
205
|
+
// Server VAD detected end of speech — response will be created automatically
|
|
206
|
+
break;
|
|
207
|
+
case "response.cancelled":
|
|
208
|
+
responseInProgress = false;
|
|
209
|
+
send(clientWs, { type: "status", status: "listening" });
|
|
210
|
+
break;
|
|
211
|
+
case "response.done":
|
|
212
|
+
responseInProgress = false;
|
|
213
|
+
// If a tool result was submitted while a response was active, trigger now
|
|
214
|
+
if (pendingToolResponse) {
|
|
215
|
+
pendingToolResponse = false;
|
|
216
|
+
openaiWs.send(JSON.stringify({ type: "response.create" }));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
send(clientWs, { type: "status", status: "listening" });
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
default:
|
|
223
|
+
// Ignore other events (session.created, session.updated, etc.)
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
openaiWs.on("close", (code, reason) => {
|
|
228
|
+
console.log(`[voice-assistant] OpenAI disconnected: ${code} ${reason}`);
|
|
229
|
+
send(clientWs, { type: "error", message: "OpenAI session ended" });
|
|
230
|
+
clientWs.close(1000, "OpenAI disconnected");
|
|
231
|
+
});
|
|
232
|
+
openaiWs.on("error", (err) => {
|
|
233
|
+
console.error("[voice-assistant] OpenAI WS error:", err);
|
|
234
|
+
send(clientWs, { type: "error", message: `OpenAI connection error: ${err.message}` });
|
|
235
|
+
});
|
|
236
|
+
// ── Browser → Gateway → OpenAI ───────────────────────────
|
|
237
|
+
let audioChunkCount = 0;
|
|
238
|
+
clientWs.on("message", (raw) => {
|
|
239
|
+
if (!openaiReady)
|
|
240
|
+
return;
|
|
241
|
+
let msg;
|
|
242
|
+
try {
|
|
243
|
+
msg = JSON.parse(typeof raw === "string" ? raw : raw.toString());
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
switch (msg.type) {
|
|
249
|
+
case "audio":
|
|
250
|
+
audioChunkCount++;
|
|
251
|
+
if (audioChunkCount <= 3 || audioChunkCount % 50 === 0) {
|
|
252
|
+
console.log(`[voice-assistant] Audio chunk #${audioChunkCount} (${msg.data.length} base64 chars)`);
|
|
253
|
+
}
|
|
254
|
+
openaiWs.send(JSON.stringify({
|
|
255
|
+
type: "input_audio_buffer.append",
|
|
256
|
+
audio: msg.data,
|
|
257
|
+
}));
|
|
258
|
+
break;
|
|
259
|
+
case "commit":
|
|
260
|
+
openaiWs.send(JSON.stringify({ type: "input_audio_buffer.commit" }));
|
|
261
|
+
break;
|
|
262
|
+
case "stop":
|
|
263
|
+
openaiWs.send(JSON.stringify({ type: "input_audio_buffer.clear" }));
|
|
264
|
+
openaiWs.close(1000, "User ended session");
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
// ── Cleanup ──────────────────────────────────────────────
|
|
269
|
+
clientWs.on("close", () => {
|
|
270
|
+
console.log(`[voice-assistant] ${user.username} disconnected`);
|
|
271
|
+
if (openaiWs.readyState === WebSocket.OPEN || openaiWs.readyState === WebSocket.CONNECTING) {
|
|
272
|
+
openaiWs.close(1000, "Client disconnected");
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
clientWs.on("error", () => {
|
|
276
|
+
try {
|
|
277
|
+
openaiWs.close();
|
|
278
|
+
}
|
|
279
|
+
catch { }
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
buildInstructions(username) {
|
|
283
|
+
const locale = Intl.DateTimeFormat().resolvedOptions().locale || "en";
|
|
284
|
+
return `# Persona
|
|
285
|
+
You are Jait — a personal AI assistant modelled after JARVIS from Iron Man.
|
|
286
|
+
You are the voice interface for the Jait workspace management system.
|
|
287
|
+
The user's name is ${username}. Address them respectfully ("Sir", "Boss", etc.).
|
|
288
|
+
|
|
289
|
+
# Language
|
|
290
|
+
The user's system locale is "${locale}". Respond in the language matching that locale.
|
|
291
|
+
If the user speaks a different language, switch to match theirs.
|
|
292
|
+
Always respond in the same language the user is using.
|
|
293
|
+
|
|
294
|
+
# Voice Behavior
|
|
295
|
+
- Be a proactive, intelligent assistant like JARVIS. Anticipate needs.
|
|
296
|
+
- Keep responses SHORT and conversational — you're speaking out loud, not writing an essay.
|
|
297
|
+
- Use clear, natural sentences. Avoid bullet lists, markdown, or code blocks in speech.
|
|
298
|
+
- Be direct, efficient, witty, and slightly formal — the JARVIS personality.
|
|
299
|
+
- Greeting style: acknowledge the user, then briefly share something useful (e.g. a quick status update, current time, or an interesting fact from memory).
|
|
300
|
+
- For simple facts (time, weather), answer in one sentence.
|
|
301
|
+
- For complex tool results, summarise the key points.
|
|
302
|
+
|
|
303
|
+
# On Startup / First Message
|
|
304
|
+
When the user first speaks (or says "Hey Jait"), provide a concise Jarvis-style greeting:
|
|
305
|
+
1. Greet them by name in their language
|
|
306
|
+
2. Use search_memory to check for any relevant context about them
|
|
307
|
+
3. Proactively mention 1-2 useful things: system status, current time, or any interesting context from memory
|
|
308
|
+
|
|
309
|
+
# System Integration
|
|
310
|
+
You have direct access to the Jait system through function calls:
|
|
311
|
+
- jait_system_status — check what's active
|
|
312
|
+
- list_sessions, list_workspaces, list_threads — see what's open
|
|
313
|
+
- send_to_agent — delegate coding tasks to CLI agents
|
|
314
|
+
- search_memory, save_memory — recall and store information
|
|
315
|
+
- search_web — look up current events, news, facts
|
|
316
|
+
- get_weather — weather by city
|
|
317
|
+
- get_time_and_date — current time
|
|
318
|
+
- get_system_info — host computer resources
|
|
319
|
+
- stop_voice — end this voice session (when user says goodbye or asks you to stop)
|
|
320
|
+
|
|
321
|
+
# Tool Usage Rules
|
|
322
|
+
- For ANY factual question about current events, ALWAYS call search_web with a clear search query string.
|
|
323
|
+
- When calling search_web, the "query" parameter MUST be a non-empty descriptive search string.
|
|
324
|
+
- When the user tells you personal information, use save_memory to remember it.
|
|
325
|
+
- Before answering questions about past interactions, use search_memory.
|
|
326
|
+
- When the user asks you to code or fix something, use send_to_agent.`;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function send(ws, msg) {
|
|
330
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
331
|
+
ws.send(JSON.stringify(msg));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/voice-assistant/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Voice-assistant tool definitions for OpenAI Realtime API function calling.
|
|
3
|
+
*
|
|
4
|
+
* Each tool is defined as an OpenAI-compatible function schema plus a local
|
|
5
|
+
* executor that runs inside the gateway with full access to Jait services.
|
|
6
|
+
*/
|
|
7
|
+
import type { SessionService } from "../services/sessions.js";
|
|
8
|
+
import type { ThreadService } from "../services/threads.js";
|
|
9
|
+
import type { WorkspaceService } from "../services/workspaces.js";
|
|
10
|
+
import type { MemoryService } from "../memory/contracts.js";
|
|
11
|
+
import type { ToolRegistry } from "../tools/registry.js";
|
|
12
|
+
import type { ToolContext, ToolResult } from "../tools/contracts.js";
|
|
13
|
+
import type { ProviderRegistry } from "../providers/registry.js";
|
|
14
|
+
import type { AppConfig } from "../config.js";
|
|
15
|
+
export interface VoiceToolDeps {
|
|
16
|
+
config: AppConfig;
|
|
17
|
+
sessionService?: SessionService;
|
|
18
|
+
threadService?: ThreadService;
|
|
19
|
+
workspaceService?: WorkspaceService;
|
|
20
|
+
memoryService?: MemoryService;
|
|
21
|
+
toolRegistry?: ToolRegistry;
|
|
22
|
+
providerRegistry?: ProviderRegistry;
|
|
23
|
+
toolExecutor?: (name: string, input: unknown, ctx: ToolContext) => Promise<ToolResult>;
|
|
24
|
+
/** Per-connection user API keys (from user settings). */
|
|
25
|
+
userApiKeys?: Record<string, string>;
|
|
26
|
+
}
|
|
27
|
+
/** OpenAI function-calling tool schema */
|
|
28
|
+
export interface RealtimeToolDef {
|
|
29
|
+
type: "function";
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
parameters: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
/** A voice-assistant tool: schema + executor */
|
|
35
|
+
export interface VoiceTool {
|
|
36
|
+
schema: RealtimeToolDef;
|
|
37
|
+
execute: (args: Record<string, unknown>, deps: VoiceToolDeps) => Promise<string>;
|
|
38
|
+
}
|
|
39
|
+
/** Get all tool schemas (for session.update → tools). */
|
|
40
|
+
export declare function getVoiceToolSchemas(): RealtimeToolDef[];
|
|
41
|
+
/** Execute a tool by name. Returns the string result for the function_call_output. */
|
|
42
|
+
export declare function executeVoiceTool(name: string, args: Record<string, unknown>, deps: VoiceToolDeps): Promise<string>;
|
|
43
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/voice-assistant/tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG9C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,CAAC;IAClB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACvF,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,gDAAgD;AAChD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAClF;AA0SD,yDAAyD;AACzD,wBAAgB,mBAAmB,IAAI,eAAe,EAAE,CAEvD;AAED,sFAAsF;AACtF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,MAAM,CAAC,CAQjB"}
|