@jchaffin/voicekit 0.2.0
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/README.md +369 -0
- package/dist/adapters/deepgram.d.mts +43 -0
- package/dist/adapters/deepgram.d.ts +43 -0
- package/dist/adapters/deepgram.js +216 -0
- package/dist/adapters/deepgram.mjs +162 -0
- package/dist/adapters/elevenlabs.d.mts +41 -0
- package/dist/adapters/elevenlabs.d.ts +41 -0
- package/dist/adapters/elevenlabs.js +304 -0
- package/dist/adapters/elevenlabs.mjs +250 -0
- package/dist/adapters/livekit.d.mts +44 -0
- package/dist/adapters/livekit.d.ts +44 -0
- package/dist/adapters/livekit.js +225 -0
- package/dist/adapters/livekit.mjs +161 -0
- package/dist/adapters/openai.d.mts +41 -0
- package/dist/adapters/openai.d.ts +41 -0
- package/dist/adapters/openai.js +350 -0
- package/dist/adapters/openai.mjs +294 -0
- package/dist/chunk-22WLZIXO.mjs +33 -0
- package/dist/chunk-T3II3DRG.mjs +178 -0
- package/dist/chunk-UZ2VGPZD.mjs +33 -0
- package/dist/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/index.d.mts +693 -0
- package/dist/index.d.ts +693 -0
- package/dist/index.js +1838 -0
- package/dist/index.mjs +1593 -0
- package/dist/server.d.mts +80 -0
- package/dist/server.d.ts +80 -0
- package/dist/server.js +147 -0
- package/dist/server.mjs +119 -0
- package/dist/types-DY31oVB1.d.mts +150 -0
- package/dist/types-DY31oVB1.d.ts +150 -0
- package/dist/types-mThnXW9S.d.mts +150 -0
- package/dist/types-mThnXW9S.d.ts +150 -0
- package/dist/types-uLnzb8NE.d.mts +150 -0
- package/dist/types-uLnzb8NE.d.ts +150 -0
- package/package.json +100 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import {
|
|
2
|
+
emitToolResult
|
|
3
|
+
} from "../chunk-T3II3DRG.mjs";
|
|
4
|
+
import {
|
|
5
|
+
EventEmitter
|
|
6
|
+
} from "../chunk-22WLZIXO.mjs";
|
|
7
|
+
|
|
8
|
+
// src/adapters/openai.ts
|
|
9
|
+
import {
|
|
10
|
+
RealtimeSession,
|
|
11
|
+
RealtimeAgent,
|
|
12
|
+
OpenAIRealtimeWebRTC,
|
|
13
|
+
tool as sdkTool
|
|
14
|
+
} from "@openai/agents/realtime";
|
|
15
|
+
function convertTool(def) {
|
|
16
|
+
return sdkTool({
|
|
17
|
+
name: def.name,
|
|
18
|
+
description: def.description,
|
|
19
|
+
parameters: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: def.parameters.properties,
|
|
22
|
+
required: def.parameters.required || [],
|
|
23
|
+
additionalProperties: false
|
|
24
|
+
},
|
|
25
|
+
execute: async (input) => {
|
|
26
|
+
try {
|
|
27
|
+
const result = await def.execute(input);
|
|
28
|
+
emitToolResult(def.name, input, result);
|
|
29
|
+
return result;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
const errorResult = { success: false, error: String(error) };
|
|
32
|
+
emitToolResult(def.name, input, errorResult);
|
|
33
|
+
return errorResult;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
var OpenAISession = class extends EventEmitter {
|
|
39
|
+
constructor(agent, options) {
|
|
40
|
+
super();
|
|
41
|
+
this.session = null;
|
|
42
|
+
this.responseInFlight = false;
|
|
43
|
+
this.agent = agent;
|
|
44
|
+
this.options = options;
|
|
45
|
+
}
|
|
46
|
+
async connect(config) {
|
|
47
|
+
const audioElement = config.audioElement;
|
|
48
|
+
this.session = new RealtimeSession(this.agent, {
|
|
49
|
+
transport: new OpenAIRealtimeWebRTC({
|
|
50
|
+
audioElement,
|
|
51
|
+
...this.options.codec === "g711" && {
|
|
52
|
+
changePeerConnection: async (pc) => {
|
|
53
|
+
pc.getTransceivers().forEach((transceiver) => {
|
|
54
|
+
if (transceiver.sender.track?.kind === "audio") {
|
|
55
|
+
transceiver.setCodecPreferences([
|
|
56
|
+
{ mimeType: "audio/PCMU", clockRate: 8e3 },
|
|
57
|
+
{ mimeType: "audio/PCMA", clockRate: 8e3 }
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return pc;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}),
|
|
65
|
+
model: this.options.model || "gpt-realtime",
|
|
66
|
+
config: {
|
|
67
|
+
inputAudioFormat: this.options.codec === "g711" ? "g711_ulaw" : "pcm16",
|
|
68
|
+
outputAudioFormat: this.options.codec === "g711" ? "g711_ulaw" : "pcm16",
|
|
69
|
+
inputAudioTranscription: {
|
|
70
|
+
model: this.options.transcriptionModel || "gpt-4o-transcribe",
|
|
71
|
+
language: this.options.language || "en"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
outputGuardrails: config.outputGuardrails ?? [],
|
|
75
|
+
context: config.context ?? {}
|
|
76
|
+
});
|
|
77
|
+
this.wireEvents(this.session);
|
|
78
|
+
await this.session.connect({ apiKey: config.authToken });
|
|
79
|
+
this.emit("status_change", "CONNECTED");
|
|
80
|
+
}
|
|
81
|
+
async disconnect() {
|
|
82
|
+
if (this.session) {
|
|
83
|
+
try {
|
|
84
|
+
await this.session.close();
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
this.session = null;
|
|
88
|
+
}
|
|
89
|
+
this.removeAllListeners();
|
|
90
|
+
this.emit("status_change", "DISCONNECTED");
|
|
91
|
+
}
|
|
92
|
+
async sendMessage(text) {
|
|
93
|
+
if (!this.session) throw new Error("Session not connected");
|
|
94
|
+
if (this.responseInFlight) {
|
|
95
|
+
this.session.interrupt();
|
|
96
|
+
await new Promise((resolve) => {
|
|
97
|
+
const onDone = (event) => {
|
|
98
|
+
if (event.type === "response.done" || event.type === "response.cancelled") {
|
|
99
|
+
this.off("raw_event", onDone);
|
|
100
|
+
resolve();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
this.on("raw_event", onDone);
|
|
104
|
+
setTimeout(resolve, 1500);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
this.session.sendMessage(text);
|
|
108
|
+
}
|
|
109
|
+
interrupt() {
|
|
110
|
+
this.session?.interrupt();
|
|
111
|
+
}
|
|
112
|
+
mute(muted) {
|
|
113
|
+
this.session?.mute(muted);
|
|
114
|
+
}
|
|
115
|
+
sendRawEvent(event) {
|
|
116
|
+
this.session?.transport.sendEvent(event);
|
|
117
|
+
}
|
|
118
|
+
// Map OpenAI SDK events -> normalized SessionEvents
|
|
119
|
+
wireEvents(session) {
|
|
120
|
+
session.on("transport_event", (event) => {
|
|
121
|
+
const type = event.type;
|
|
122
|
+
switch (type) {
|
|
123
|
+
case "input_audio_buffer.speech_started":
|
|
124
|
+
this.emit("user_speech_started");
|
|
125
|
+
break;
|
|
126
|
+
case "conversation.item.input_audio_transcription.delta":
|
|
127
|
+
this.emit("user_transcript", {
|
|
128
|
+
itemId: event.item_id,
|
|
129
|
+
delta: event.delta || "",
|
|
130
|
+
isFinal: false
|
|
131
|
+
});
|
|
132
|
+
break;
|
|
133
|
+
case "conversation.item.input_audio_transcription.completed":
|
|
134
|
+
this.emit("user_transcript", {
|
|
135
|
+
itemId: event.item_id,
|
|
136
|
+
text: event.transcript || "",
|
|
137
|
+
isFinal: true
|
|
138
|
+
});
|
|
139
|
+
break;
|
|
140
|
+
case "response.audio_transcript.delta":
|
|
141
|
+
case "response.output_audio_transcript.delta":
|
|
142
|
+
this.emit("assistant_transcript", {
|
|
143
|
+
itemId: event.item_id,
|
|
144
|
+
delta: event.delta || "",
|
|
145
|
+
isFinal: false
|
|
146
|
+
});
|
|
147
|
+
break;
|
|
148
|
+
case "response.audio_transcript.done":
|
|
149
|
+
case "response.output_audio_transcript.done":
|
|
150
|
+
this.emit("assistant_transcript", {
|
|
151
|
+
itemId: event.item_id,
|
|
152
|
+
text: event.transcript || "",
|
|
153
|
+
isFinal: true
|
|
154
|
+
});
|
|
155
|
+
break;
|
|
156
|
+
case "response.audio.delta":
|
|
157
|
+
case "response.output_audio.delta":
|
|
158
|
+
this.emit("audio_delta", event.item_id, event.delta);
|
|
159
|
+
break;
|
|
160
|
+
case "response.created":
|
|
161
|
+
this.responseInFlight = true;
|
|
162
|
+
this.emit("raw_event", event);
|
|
163
|
+
break;
|
|
164
|
+
case "response.done":
|
|
165
|
+
this.responseInFlight = false;
|
|
166
|
+
this.emit("raw_event", event);
|
|
167
|
+
break;
|
|
168
|
+
case "conversation.item.truncated":
|
|
169
|
+
this.emit("raw_event", event);
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
this.emit("raw_event", event);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
session.on("agent_tool_start", ((...args) => {
|
|
177
|
+
const functionCall = args[2];
|
|
178
|
+
if (functionCall) {
|
|
179
|
+
this.emit("tool_call_start", functionCall.name, functionCall.arguments);
|
|
180
|
+
}
|
|
181
|
+
}));
|
|
182
|
+
session.on("agent_tool_end", ((...args) => {
|
|
183
|
+
const functionCall = args[2];
|
|
184
|
+
const result = args[3];
|
|
185
|
+
if (functionCall) {
|
|
186
|
+
this.emit("tool_call_end", functionCall.name, functionCall.arguments, result);
|
|
187
|
+
}
|
|
188
|
+
}));
|
|
189
|
+
session.on("agent_handoff", ((...args) => {
|
|
190
|
+
const item = args[0];
|
|
191
|
+
const context = item?.context;
|
|
192
|
+
const history = context?.history;
|
|
193
|
+
if (history?.length) {
|
|
194
|
+
const lastMessage = history[history.length - 1];
|
|
195
|
+
const agentName = (lastMessage.name || "").split("transfer_to_").pop() || "";
|
|
196
|
+
this.emit("agent_handoff", "", agentName);
|
|
197
|
+
}
|
|
198
|
+
}));
|
|
199
|
+
session.on("guardrail_tripped", ((...args) => {
|
|
200
|
+
this.emit("guardrail_tripped", args);
|
|
201
|
+
}));
|
|
202
|
+
session.on("history_updated", ((...args) => {
|
|
203
|
+
this.emit("raw_event", { type: "history_updated", items: args[0] });
|
|
204
|
+
}));
|
|
205
|
+
session.on("history_added", ((...args) => {
|
|
206
|
+
this.emit("raw_event", { type: "history_added", item: args[0] });
|
|
207
|
+
}));
|
|
208
|
+
session.on("error", (error) => {
|
|
209
|
+
if (error instanceof Error) {
|
|
210
|
+
this.emit("error", error);
|
|
211
|
+
} else if (error && typeof error === "object") {
|
|
212
|
+
const obj = error;
|
|
213
|
+
const msg = obj.message || obj.error?.message || JSON.stringify(error);
|
|
214
|
+
this.emit("error", new Error(msg));
|
|
215
|
+
} else {
|
|
216
|
+
this.emit("error", new Error(String(error)));
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
function openai(options = {}) {
|
|
222
|
+
return {
|
|
223
|
+
name: "openai",
|
|
224
|
+
createSession(agentConfig, sessionOpts) {
|
|
225
|
+
const merged = { ...options, ...sessionOpts };
|
|
226
|
+
const agent = buildRealtimeAgent(agentConfig);
|
|
227
|
+
return new OpenAISession(agent, merged);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function buildRealtimeAgent(config) {
|
|
232
|
+
const tools = (config.tools || []).map(convertTool);
|
|
233
|
+
return new RealtimeAgent({
|
|
234
|
+
name: config.name,
|
|
235
|
+
instructions: config.instructions,
|
|
236
|
+
tools
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function openaiServer(config = {}) {
|
|
240
|
+
const getSessionToken = async (overrides = {}) => {
|
|
241
|
+
const merged = { ...config, ...overrides };
|
|
242
|
+
const apiKey = merged.apiKey || process.env.OPENAI_API_KEY;
|
|
243
|
+
if (!apiKey) return { error: "OpenAI API key not configured" };
|
|
244
|
+
try {
|
|
245
|
+
const response = await fetch("https://api.openai.com/v1/realtime/client_secrets", {
|
|
246
|
+
method: "POST",
|
|
247
|
+
headers: {
|
|
248
|
+
Authorization: `Bearer ${apiKey}`,
|
|
249
|
+
"Content-Type": "application/json"
|
|
250
|
+
},
|
|
251
|
+
body: JSON.stringify({
|
|
252
|
+
expires_after: {
|
|
253
|
+
anchor: "created_at",
|
|
254
|
+
seconds: merged.expiresIn || 600
|
|
255
|
+
},
|
|
256
|
+
session: {
|
|
257
|
+
type: "realtime",
|
|
258
|
+
model: merged.model || "gpt-realtime",
|
|
259
|
+
...merged.voice && { audio: { output: { voice: merged.voice } } },
|
|
260
|
+
...merged.instructions && { instructions: merged.instructions }
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
});
|
|
264
|
+
if (!response.ok) {
|
|
265
|
+
const text = await response.text();
|
|
266
|
+
console.error("OpenAI client_secrets error:", text);
|
|
267
|
+
return { error: `OpenAI API error: ${response.status}` };
|
|
268
|
+
}
|
|
269
|
+
const data = await response.json();
|
|
270
|
+
if (!data.value) return { error: "Invalid response from OpenAI" };
|
|
271
|
+
return { token: data.value };
|
|
272
|
+
} catch (err) {
|
|
273
|
+
return { error: String(err) };
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
return {
|
|
277
|
+
getSessionToken,
|
|
278
|
+
createSessionHandler(overrides) {
|
|
279
|
+
return async (_request) => {
|
|
280
|
+
const result = await getSessionToken(overrides);
|
|
281
|
+
if (result.error) {
|
|
282
|
+
return Response.json({ error: result.error }, { status: 500 });
|
|
283
|
+
}
|
|
284
|
+
return Response.json({ ephemeralKey: result.token });
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
var openai_default = openai;
|
|
290
|
+
export {
|
|
291
|
+
openai_default as default,
|
|
292
|
+
openai,
|
|
293
|
+
openaiServer
|
|
294
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/core/EventEmitter.ts
|
|
2
|
+
var EventEmitter = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
5
|
+
}
|
|
6
|
+
on(event, handler) {
|
|
7
|
+
let set = this.handlers.get(event);
|
|
8
|
+
if (!set) {
|
|
9
|
+
set = /* @__PURE__ */ new Set();
|
|
10
|
+
this.handlers.set(event, set);
|
|
11
|
+
}
|
|
12
|
+
set.add(handler);
|
|
13
|
+
}
|
|
14
|
+
off(event, handler) {
|
|
15
|
+
this.handlers.get(event)?.delete(handler);
|
|
16
|
+
}
|
|
17
|
+
emit(event, ...args) {
|
|
18
|
+
this.handlers.get(event)?.forEach((fn) => {
|
|
19
|
+
try {
|
|
20
|
+
fn(...args);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
console.error(`EventEmitter error in "${event}":`, e);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
removeAllListeners() {
|
|
27
|
+
this.handlers.clear();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
EventEmitter
|
|
33
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// src/tools.ts
|
|
2
|
+
function defineTool(config) {
|
|
3
|
+
return {
|
|
4
|
+
name: config.name,
|
|
5
|
+
description: config.description,
|
|
6
|
+
parameters: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: config.parameters,
|
|
9
|
+
required: config.required
|
|
10
|
+
},
|
|
11
|
+
execute: config.execute
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function createNavigationTool(sections) {
|
|
15
|
+
return defineTool({
|
|
16
|
+
name: "navigate",
|
|
17
|
+
description: `Navigate to a section. Available: ${sections.join(", ")}`,
|
|
18
|
+
parameters: {
|
|
19
|
+
section: {
|
|
20
|
+
type: "string",
|
|
21
|
+
enum: sections,
|
|
22
|
+
description: "Section to scroll to"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
required: ["section"],
|
|
26
|
+
execute: ({ section }) => {
|
|
27
|
+
if (typeof window !== "undefined") {
|
|
28
|
+
const el = document.getElementById(section);
|
|
29
|
+
if (el) {
|
|
30
|
+
el.scrollIntoView({ behavior: "smooth" });
|
|
31
|
+
return { success: true, section };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { success: false, error: "Section not found" };
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function createEventTool(config) {
|
|
39
|
+
return defineTool({
|
|
40
|
+
name: config.name,
|
|
41
|
+
description: config.description,
|
|
42
|
+
parameters: config.parameters,
|
|
43
|
+
required: config.required,
|
|
44
|
+
execute: (params) => {
|
|
45
|
+
if (typeof window !== "undefined") {
|
|
46
|
+
window.dispatchEvent(new CustomEvent(config.eventType, {
|
|
47
|
+
detail: { toolName: config.name, params }
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
return { success: true, ...params };
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function createAPITool(config) {
|
|
55
|
+
return defineTool({
|
|
56
|
+
name: config.name,
|
|
57
|
+
description: config.description,
|
|
58
|
+
parameters: config.parameters,
|
|
59
|
+
required: config.required,
|
|
60
|
+
execute: async (params) => {
|
|
61
|
+
try {
|
|
62
|
+
const url = typeof config.endpoint === "function" ? config.endpoint(params) : config.endpoint;
|
|
63
|
+
const isPost = config.method === "POST";
|
|
64
|
+
const response = await fetch(url, {
|
|
65
|
+
method: config.method || "GET",
|
|
66
|
+
headers: {
|
|
67
|
+
...isPost ? { "Content-Type": "application/json" } : {},
|
|
68
|
+
...config.headers
|
|
69
|
+
},
|
|
70
|
+
body: isPost ? JSON.stringify(params) : void 0
|
|
71
|
+
});
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`HTTP ${response.status}`);
|
|
74
|
+
}
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
return config.transform ? config.transform(data) : data;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
return { success: false, error: String(error) };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function createSearchTool(config) {
|
|
84
|
+
const paramName = config.searchParam || "query";
|
|
85
|
+
return defineTool({
|
|
86
|
+
name: config.name,
|
|
87
|
+
description: config.description,
|
|
88
|
+
parameters: {
|
|
89
|
+
[paramName]: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description: `The ${paramName} to search for`
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
required: [paramName],
|
|
95
|
+
execute: async (params) => {
|
|
96
|
+
const query = params[paramName];
|
|
97
|
+
try {
|
|
98
|
+
let result;
|
|
99
|
+
if (config.fetch) {
|
|
100
|
+
result = await config.fetch(query);
|
|
101
|
+
} else if (config.endpoint) {
|
|
102
|
+
const res = await fetch(config.endpoint, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: { "Content-Type": "application/json" },
|
|
105
|
+
body: JSON.stringify({ query })
|
|
106
|
+
});
|
|
107
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
108
|
+
result = await res.json();
|
|
109
|
+
} else {
|
|
110
|
+
throw new Error("Must provide either endpoint or fetch function");
|
|
111
|
+
}
|
|
112
|
+
const finalResult = config.transform ? config.transform(result) : result;
|
|
113
|
+
if (config.eventType && typeof window !== "undefined") {
|
|
114
|
+
window.dispatchEvent(new CustomEvent(config.eventType, {
|
|
115
|
+
detail: { query, result: finalResult }
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
return finalResult;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
return { success: false, error: String(error) };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function createRAGTool(config) {
|
|
126
|
+
return defineTool({
|
|
127
|
+
name: config.name,
|
|
128
|
+
description: config.description,
|
|
129
|
+
parameters: {
|
|
130
|
+
query: { type: "string", description: "Search query" },
|
|
131
|
+
...config.repo ? {} : { repo: { type: "string", description: "Optional: filter by repository name" } }
|
|
132
|
+
},
|
|
133
|
+
required: ["query"],
|
|
134
|
+
execute: async (params) => {
|
|
135
|
+
const { query, repo } = params;
|
|
136
|
+
try {
|
|
137
|
+
const res = await fetch(config.endpoint, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: { "Content-Type": "application/json" },
|
|
140
|
+
body: JSON.stringify({
|
|
141
|
+
query,
|
|
142
|
+
repo: config.repo || repo,
|
|
143
|
+
limit: config.limit || 10
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
147
|
+
const result = await res.json();
|
|
148
|
+
if (config.eventType && typeof window !== "undefined") {
|
|
149
|
+
window.dispatchEvent(new CustomEvent(config.eventType, {
|
|
150
|
+
detail: { query, result }
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
} catch (error) {
|
|
155
|
+
return { success: false, error: String(error) };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
var TOOL_RESULT_EVENT = "voicekit:tool-result";
|
|
161
|
+
function emitToolResult(name, input, result) {
|
|
162
|
+
if (typeof window !== "undefined") {
|
|
163
|
+
window.dispatchEvent(new CustomEvent(TOOL_RESULT_EVENT, {
|
|
164
|
+
detail: { name, input, result, timestamp: Date.now() }
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export {
|
|
170
|
+
defineTool,
|
|
171
|
+
createNavigationTool,
|
|
172
|
+
createEventTool,
|
|
173
|
+
createAPITool,
|
|
174
|
+
createSearchTool,
|
|
175
|
+
createRAGTool,
|
|
176
|
+
TOOL_RESULT_EVENT,
|
|
177
|
+
emitToolResult
|
|
178
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/core/EventEmitter.ts
|
|
2
|
+
var EventEmitter = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
5
|
+
}
|
|
6
|
+
on(event, handler) {
|
|
7
|
+
let set = this.handlers.get(event);
|
|
8
|
+
if (!set) {
|
|
9
|
+
set = /* @__PURE__ */ new Set();
|
|
10
|
+
this.handlers.set(event, set);
|
|
11
|
+
}
|
|
12
|
+
set.add(handler);
|
|
13
|
+
}
|
|
14
|
+
off(event, handler) {
|
|
15
|
+
this.handlers.get(event)?.delete(handler);
|
|
16
|
+
}
|
|
17
|
+
emit(event, ...args) {
|
|
18
|
+
this.handlers.get(event)?.forEach((fn) => {
|
|
19
|
+
try {
|
|
20
|
+
fn(...args);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
console.error(`EventEmitter error in "${String(event)}":`, e);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
removeAllListeners() {
|
|
27
|
+
this.handlers.clear();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
EventEmitter
|
|
33
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
__require
|
|
10
|
+
};
|