@inductiv/node-red-openai-api 1.103.0 → 6.22.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 +165 -95
- package/examples/responses/mcp.json +1 -1
- package/lib.js +7035 -13298
- package/locales/en-US/node.json +49 -1
- package/node.html +1526 -981
- package/node.js +194 -54
- package/package.json +8 -7
- package/src/assistants/help.html +1 -77
- package/src/audio/help.html +1 -37
- package/src/batch/help.html +3 -17
- package/src/chat/help.html +11 -89
- package/src/container-files/help.html +1 -27
- package/src/containers/help.html +8 -18
- package/src/conversations/help.html +135 -0
- package/src/conversations/methods.js +73 -0
- package/src/conversations/template.html +10 -0
- package/src/embeddings/help.html +1 -11
- package/src/evals/help.html +249 -0
- package/src/evals/methods.js +114 -0
- package/src/evals/template.html +14 -0
- package/src/files/help.html +4 -17
- package/src/fine-tuning/help.html +1 -35
- package/src/images/help.html +1 -45
- package/src/lib.js +53 -1
- package/src/messages/help.html +19 -39
- package/src/messages/methods.js +13 -0
- package/src/messages/template.html +7 -18
- package/src/models/help.html +1 -5
- package/src/moderations/help.html +1 -5
- package/src/node.html +126 -37
- package/src/realtime/help.html +129 -0
- package/src/realtime/methods.js +45 -0
- package/src/realtime/template.html +7 -0
- package/src/responses/help.html +203 -61
- package/src/responses/methods.js +49 -16
- package/src/responses/template.html +16 -1
- package/src/runs/help.html +1 -123
- package/src/skills/help.html +183 -0
- package/src/skills/methods.js +99 -0
- package/src/skills/template.html +13 -0
- package/src/threads/help.html +1 -15
- package/src/uploads/help.html +1 -21
- package/src/vector-store-file-batches/help.html +1 -27
- package/src/vector-store-file-batches/methods.js +5 -5
- package/src/vector-store-files/help.html +1 -25
- package/src/vector-store-files/methods.js +4 -7
- package/src/vector-stores/help.html +2 -31
- package/src/vector-stores/methods.js +5 -11
- package/src/vector-stores/template.html +7 -22
- package/src/videos/help.html +113 -0
- package/src/videos/methods.js +50 -0
- package/src/videos/template.html +8 -0
- package/src/webhooks/help.html +61 -0
- package/src/webhooks/methods.js +40 -0
- package/src/webhooks/template.html +4 -0
- package/test/openai-methods-mapping.test.js +1220 -0
- package/test/openai-node-auth-routing.test.js +203 -0
- package/test/service-host-editor-template.test.js +53 -0
- package/test/service-host-node.test.js +182 -0
- package/test/services.test.js +147 -0
- package/test/utils.test.js +75 -0
|
@@ -0,0 +1,1220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const assert = require("node:assert/strict");
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const test = require("node:test");
|
|
7
|
+
|
|
8
|
+
function withMockedOpenAI(FakeOpenAI, callback) {
|
|
9
|
+
const openaiModule = require("openai");
|
|
10
|
+
const originalDescriptor = Object.getOwnPropertyDescriptor(openaiModule, "OpenAI");
|
|
11
|
+
|
|
12
|
+
Object.defineProperty(openaiModule, "OpenAI", {
|
|
13
|
+
value: FakeOpenAI,
|
|
14
|
+
configurable: true,
|
|
15
|
+
enumerable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const run = async () => {
|
|
20
|
+
try {
|
|
21
|
+
return await callback();
|
|
22
|
+
} finally {
|
|
23
|
+
if (originalDescriptor) {
|
|
24
|
+
Object.defineProperty(openaiModule, "OpenAI", originalDescriptor);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return run();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
test("responses methods map delete/cancel/compact/input-items/input-tokens to OpenAI SDK", async () => {
|
|
33
|
+
const calls = [];
|
|
34
|
+
|
|
35
|
+
class FakeOpenAI {
|
|
36
|
+
constructor(clientParams) {
|
|
37
|
+
calls.push({ method: "ctor", clientParams });
|
|
38
|
+
this.responses = {
|
|
39
|
+
delete: async (responseId, options) => {
|
|
40
|
+
calls.push({ method: "responses.delete", responseId, options });
|
|
41
|
+
return { id: responseId, deleted: true };
|
|
42
|
+
},
|
|
43
|
+
cancel: async (responseId, options) => {
|
|
44
|
+
calls.push({ method: "responses.cancel", responseId, options });
|
|
45
|
+
return { id: responseId, status: "cancelled" };
|
|
46
|
+
},
|
|
47
|
+
compact: async (payload) => {
|
|
48
|
+
calls.push({ method: "responses.compact", payload });
|
|
49
|
+
return { id: "compaction_1", object: "response.compaction" };
|
|
50
|
+
},
|
|
51
|
+
inputItems: {
|
|
52
|
+
list: async (responseId, options) => {
|
|
53
|
+
calls.push({ method: "responses.inputItems.list", responseId, options });
|
|
54
|
+
return {
|
|
55
|
+
data: [{ id: "item_1" }, { id: "item_2" }],
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
inputTokens: {
|
|
60
|
+
count: async (payload) => {
|
|
61
|
+
calls.push({ method: "responses.inputTokens.count", payload });
|
|
62
|
+
return { object: "response.input_tokens", input_tokens: 42 };
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
70
|
+
const modulePath = require.resolve("../src/responses/methods.js");
|
|
71
|
+
delete require.cache[modulePath];
|
|
72
|
+
const responsesMethods = require("../src/responses/methods.js");
|
|
73
|
+
|
|
74
|
+
const clientContext = { clientParams: { apiKey: "sk-test", baseURL: "https://api.example.com/v1" } };
|
|
75
|
+
|
|
76
|
+
const deleteResponse = await responsesMethods.deleteModelResponse.call(clientContext, {
|
|
77
|
+
payload: {
|
|
78
|
+
response_id: "resp_123",
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
assert.deepEqual(deleteResponse, { id: "resp_123", deleted: true });
|
|
82
|
+
|
|
83
|
+
const cancelResponse = await responsesMethods.cancelModelResponse.call(clientContext, {
|
|
84
|
+
payload: {
|
|
85
|
+
response_id: "resp_123",
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
assert.deepEqual(cancelResponse, { id: "resp_123", status: "cancelled" });
|
|
89
|
+
|
|
90
|
+
const compactResponse = await responsesMethods.compactModelResponse.call(clientContext, {
|
|
91
|
+
payload: {
|
|
92
|
+
model: "gpt-5.2",
|
|
93
|
+
input: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
assert.deepEqual(compactResponse, {
|
|
97
|
+
id: "compaction_1",
|
|
98
|
+
object: "response.compaction",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const inputItems = await responsesMethods.listInputItems.call(clientContext, {
|
|
102
|
+
payload: {
|
|
103
|
+
response_id: "resp_123",
|
|
104
|
+
order: "desc",
|
|
105
|
+
include: ["message.input_image.image_url"],
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
assert.deepEqual(inputItems, [{ id: "item_1" }, { id: "item_2" }]);
|
|
109
|
+
|
|
110
|
+
const inputTokenCount = await responsesMethods.countInputTokens.call(clientContext, {
|
|
111
|
+
payload: {
|
|
112
|
+
model: "gpt-4.1-mini",
|
|
113
|
+
input: "hello",
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
assert.deepEqual(inputTokenCount, {
|
|
117
|
+
object: "response.input_tokens",
|
|
118
|
+
input_tokens: 42,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
delete require.cache[modulePath];
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const responseCalls = calls.filter((entry) => entry.method !== "ctor");
|
|
125
|
+
assert.deepEqual(responseCalls, [
|
|
126
|
+
{
|
|
127
|
+
method: "responses.delete",
|
|
128
|
+
responseId: "resp_123",
|
|
129
|
+
options: {},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
method: "responses.cancel",
|
|
133
|
+
responseId: "resp_123",
|
|
134
|
+
options: {},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
method: "responses.compact",
|
|
138
|
+
payload: {
|
|
139
|
+
model: "gpt-5.2",
|
|
140
|
+
input: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
method: "responses.inputItems.list",
|
|
145
|
+
responseId: "resp_123",
|
|
146
|
+
options: {
|
|
147
|
+
order: "desc",
|
|
148
|
+
include: ["message.input_image.image_url"],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
method: "responses.inputTokens.count",
|
|
153
|
+
payload: {
|
|
154
|
+
model: "gpt-4.1-mini",
|
|
155
|
+
input: "hello",
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
]);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("responses retrieve streams chunks when stream=true", async () => {
|
|
162
|
+
const calls = [];
|
|
163
|
+
|
|
164
|
+
async function* createFakeStream() {
|
|
165
|
+
yield { type: "response.in_progress", sequence_number: 1 };
|
|
166
|
+
yield { type: "response.completed", sequence_number: 2 };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class FakeOpenAI {
|
|
170
|
+
constructor(clientParams) {
|
|
171
|
+
calls.push({ method: "ctor", clientParams });
|
|
172
|
+
this.responses = {
|
|
173
|
+
retrieve: async (responseId, options) => {
|
|
174
|
+
calls.push({ method: "responses.retrieve", responseId, options });
|
|
175
|
+
if (options.stream) {
|
|
176
|
+
return createFakeStream();
|
|
177
|
+
}
|
|
178
|
+
return { id: responseId, status: "completed" };
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
185
|
+
const modulePath = require.resolve("../src/responses/methods.js");
|
|
186
|
+
delete require.cache[modulePath];
|
|
187
|
+
const responsesMethods = require("../src/responses/methods.js");
|
|
188
|
+
|
|
189
|
+
const sentMessages = [];
|
|
190
|
+
const statuses = [];
|
|
191
|
+
const node = {
|
|
192
|
+
send: (msg) => sentMessages.push(msg),
|
|
193
|
+
status: (status) => statuses.push(status),
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const clientContext = { clientParams: { apiKey: "sk-test" } };
|
|
197
|
+
|
|
198
|
+
const streamResult = await responsesMethods.getModelResponse.call(clientContext, {
|
|
199
|
+
_node: node,
|
|
200
|
+
msg: { topic: "t1" },
|
|
201
|
+
payload: {
|
|
202
|
+
response_id: "resp_stream",
|
|
203
|
+
stream: true,
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
assert.equal(streamResult, undefined);
|
|
207
|
+
|
|
208
|
+
assert.deepEqual(sentMessages, [
|
|
209
|
+
{
|
|
210
|
+
topic: "t1",
|
|
211
|
+
payload: { type: "response.in_progress", sequence_number: 1 },
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
topic: "t1",
|
|
215
|
+
payload: { type: "response.completed", sequence_number: 2 },
|
|
216
|
+
},
|
|
217
|
+
]);
|
|
218
|
+
|
|
219
|
+
assert.deepEqual(statuses, [
|
|
220
|
+
{
|
|
221
|
+
fill: "green",
|
|
222
|
+
shape: "dot",
|
|
223
|
+
text: "OpenaiApi.status.streaming",
|
|
224
|
+
},
|
|
225
|
+
{},
|
|
226
|
+
]);
|
|
227
|
+
|
|
228
|
+
const retrieveResponse = await responsesMethods.getModelResponse.call(clientContext, {
|
|
229
|
+
_node: node,
|
|
230
|
+
msg: { topic: "t1" },
|
|
231
|
+
payload: {
|
|
232
|
+
response_id: "resp_non_stream",
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
assert.deepEqual(retrieveResponse, { id: "resp_non_stream", status: "completed" });
|
|
236
|
+
|
|
237
|
+
delete require.cache[modulePath];
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const retrieveCalls = calls.filter((entry) => entry.method === "responses.retrieve");
|
|
241
|
+
assert.deepEqual(retrieveCalls, [
|
|
242
|
+
{
|
|
243
|
+
method: "responses.retrieve",
|
|
244
|
+
responseId: "resp_stream",
|
|
245
|
+
options: { stream: true },
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
method: "responses.retrieve",
|
|
249
|
+
responseId: "resp_non_stream",
|
|
250
|
+
options: {},
|
|
251
|
+
},
|
|
252
|
+
]);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("conversation methods map to OpenAI SDK conversations endpoints", async () => {
|
|
256
|
+
const calls = [];
|
|
257
|
+
|
|
258
|
+
class FakeOpenAI {
|
|
259
|
+
constructor(clientParams) {
|
|
260
|
+
calls.push({ method: "ctor", clientParams });
|
|
261
|
+
|
|
262
|
+
this.conversations = {
|
|
263
|
+
create: async (body) => {
|
|
264
|
+
calls.push({ method: "conversations.create", body });
|
|
265
|
+
return { id: "conv_new" };
|
|
266
|
+
},
|
|
267
|
+
retrieve: async (conversationId, options) => {
|
|
268
|
+
calls.push({ method: "conversations.retrieve", conversationId, options });
|
|
269
|
+
return { id: conversationId };
|
|
270
|
+
},
|
|
271
|
+
update: async (conversationId, body) => {
|
|
272
|
+
calls.push({ method: "conversations.update", conversationId, body });
|
|
273
|
+
return { id: conversationId, updated: true };
|
|
274
|
+
},
|
|
275
|
+
delete: async (conversationId, options) => {
|
|
276
|
+
calls.push({ method: "conversations.delete", conversationId, options });
|
|
277
|
+
return { id: conversationId, deleted: true };
|
|
278
|
+
},
|
|
279
|
+
items: {
|
|
280
|
+
create: async (conversationId, body) => {
|
|
281
|
+
calls.push({ method: "conversations.items.create", conversationId, body });
|
|
282
|
+
return { id: "item_new" };
|
|
283
|
+
},
|
|
284
|
+
retrieve: async (itemId, options) => {
|
|
285
|
+
calls.push({ method: "conversations.items.retrieve", itemId, options });
|
|
286
|
+
return { id: itemId };
|
|
287
|
+
},
|
|
288
|
+
list: async (conversationId, options) => {
|
|
289
|
+
calls.push({ method: "conversations.items.list", conversationId, options });
|
|
290
|
+
return { data: [{ id: "item_1" }, { id: "item_2" }] };
|
|
291
|
+
},
|
|
292
|
+
delete: async (itemId, options) => {
|
|
293
|
+
calls.push({ method: "conversations.items.delete", itemId, options });
|
|
294
|
+
return { id: itemId, deleted: true };
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
302
|
+
const modulePath = require.resolve("../src/conversations/methods.js");
|
|
303
|
+
delete require.cache[modulePath];
|
|
304
|
+
const conversationMethods = require("../src/conversations/methods.js");
|
|
305
|
+
|
|
306
|
+
const clientContext = { clientParams: { apiKey: "sk-test" } };
|
|
307
|
+
|
|
308
|
+
const created = await conversationMethods.createConversation.call(clientContext, {
|
|
309
|
+
payload: { metadata: { app: "node-red" } },
|
|
310
|
+
});
|
|
311
|
+
assert.deepEqual(created, { id: "conv_new" });
|
|
312
|
+
|
|
313
|
+
const fetched = await conversationMethods.getConversation.call(clientContext, {
|
|
314
|
+
payload: { conversation_id: "conv_1", include: ["items"] },
|
|
315
|
+
});
|
|
316
|
+
assert.deepEqual(fetched, { id: "conv_1" });
|
|
317
|
+
|
|
318
|
+
const updated = await conversationMethods.modifyConversation.call(clientContext, {
|
|
319
|
+
payload: { conversation_id: "conv_1", metadata: { env: "dev" } },
|
|
320
|
+
});
|
|
321
|
+
assert.deepEqual(updated, { id: "conv_1", updated: true });
|
|
322
|
+
|
|
323
|
+
const deleted = await conversationMethods.deleteConversation.call(clientContext, {
|
|
324
|
+
payload: { conversation_id: "conv_1" },
|
|
325
|
+
});
|
|
326
|
+
assert.deepEqual(deleted, { id: "conv_1", deleted: true });
|
|
327
|
+
|
|
328
|
+
const createdItem = await conversationMethods.createConversationItem.call(clientContext, {
|
|
329
|
+
payload: {
|
|
330
|
+
conversation_id: "conv_1",
|
|
331
|
+
item: { role: "user", content: [{ type: "text", text: "hello" }] },
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
assert.deepEqual(createdItem, { id: "item_new" });
|
|
335
|
+
|
|
336
|
+
const fetchedItem = await conversationMethods.getConversationItem.call(clientContext, {
|
|
337
|
+
payload: {
|
|
338
|
+
conversation_id: "conv_1",
|
|
339
|
+
item_id: "item_1",
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
assert.deepEqual(fetchedItem, { id: "item_1" });
|
|
343
|
+
|
|
344
|
+
const listedItems = await conversationMethods.listConversationItems.call(clientContext, {
|
|
345
|
+
payload: {
|
|
346
|
+
conversation_id: "conv_1",
|
|
347
|
+
limit: 2,
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
assert.deepEqual(listedItems, [{ id: "item_1" }, { id: "item_2" }]);
|
|
351
|
+
|
|
352
|
+
const deletedItem = await conversationMethods.deleteConversationItem.call(clientContext, {
|
|
353
|
+
payload: {
|
|
354
|
+
conversation_id: "conv_1",
|
|
355
|
+
item_id: "item_1",
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
assert.deepEqual(deletedItem, { id: "item_1", deleted: true });
|
|
359
|
+
|
|
360
|
+
delete require.cache[modulePath];
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
assert.equal(calls.some((entry) => entry.method === "conversations.create"), true);
|
|
364
|
+
assert.equal(calls.some((entry) => entry.method === "conversations.items.list"), true);
|
|
365
|
+
assert.equal(calls.some((entry) => entry.method === "conversations.items.delete"), true);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test("skills methods map to OpenAI SDK skills endpoints", async () => {
|
|
369
|
+
const calls = [];
|
|
370
|
+
|
|
371
|
+
class FakeOpenAI {
|
|
372
|
+
constructor(clientParams) {
|
|
373
|
+
calls.push({ method: "ctor", clientParams });
|
|
374
|
+
this.skills = {
|
|
375
|
+
create: async (body) => {
|
|
376
|
+
calls.push({ method: "skills.create", body });
|
|
377
|
+
return { id: "skill_new" };
|
|
378
|
+
},
|
|
379
|
+
retrieve: async (skillId, options) => {
|
|
380
|
+
calls.push({ method: "skills.retrieve", skillId, options });
|
|
381
|
+
return { id: skillId };
|
|
382
|
+
},
|
|
383
|
+
update: async (skillId, body) => {
|
|
384
|
+
calls.push({ method: "skills.update", skillId, body });
|
|
385
|
+
return { id: skillId, updated: true };
|
|
386
|
+
},
|
|
387
|
+
delete: async (skillId, options) => {
|
|
388
|
+
calls.push({ method: "skills.delete", skillId, options });
|
|
389
|
+
return { id: skillId, deleted: true };
|
|
390
|
+
},
|
|
391
|
+
list: async (options) => {
|
|
392
|
+
calls.push({ method: "skills.list", options });
|
|
393
|
+
return { data: [{ id: "skill_1" }, { id: "skill_2" }] };
|
|
394
|
+
},
|
|
395
|
+
content: {
|
|
396
|
+
retrieve: async (skillId, options) => {
|
|
397
|
+
calls.push({ method: "skills.content.retrieve", skillId, options });
|
|
398
|
+
return { id: skillId, object: "skill.content" };
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
versions: {
|
|
402
|
+
create: async (skillId, body) => {
|
|
403
|
+
calls.push({ method: "skills.versions.create", skillId, body });
|
|
404
|
+
return { id: "skill_version_new", skill_id: skillId };
|
|
405
|
+
},
|
|
406
|
+
retrieve: async (version, options) => {
|
|
407
|
+
calls.push({ method: "skills.versions.retrieve", version, options });
|
|
408
|
+
return { id: "skill_version_1", version };
|
|
409
|
+
},
|
|
410
|
+
list: async (skillId, options) => {
|
|
411
|
+
calls.push({ method: "skills.versions.list", skillId, options });
|
|
412
|
+
return { data: [{ id: "sv_1" }, { id: "sv_2" }] };
|
|
413
|
+
},
|
|
414
|
+
delete: async (version, options) => {
|
|
415
|
+
calls.push({ method: "skills.versions.delete", version, options });
|
|
416
|
+
return { deleted: true, version };
|
|
417
|
+
},
|
|
418
|
+
content: {
|
|
419
|
+
retrieve: async (version, options) => {
|
|
420
|
+
calls.push({ method: "skills.versions.content.retrieve", version, options });
|
|
421
|
+
return { object: "skill.version.content", version };
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
430
|
+
const modulePath = require.resolve("../src/skills/methods.js");
|
|
431
|
+
delete require.cache[modulePath];
|
|
432
|
+
const skillMethods = require("../src/skills/methods.js");
|
|
433
|
+
|
|
434
|
+
const clientContext = { clientParams: { apiKey: "sk-test" } };
|
|
435
|
+
|
|
436
|
+
const listed = await skillMethods.listSkills.call(clientContext, {
|
|
437
|
+
payload: { order: "desc", limit: 2 },
|
|
438
|
+
});
|
|
439
|
+
assert.deepEqual(listed, [{ id: "skill_1" }, { id: "skill_2" }]);
|
|
440
|
+
|
|
441
|
+
const created = await skillMethods.createSkill.call(clientContext, {
|
|
442
|
+
payload: { files: ["./skill.zip"] },
|
|
443
|
+
});
|
|
444
|
+
assert.deepEqual(created, { id: "skill_new" });
|
|
445
|
+
|
|
446
|
+
const fetched = await skillMethods.getSkill.call(clientContext, {
|
|
447
|
+
payload: { skill_id: "skill_1" },
|
|
448
|
+
});
|
|
449
|
+
assert.deepEqual(fetched, { id: "skill_1" });
|
|
450
|
+
|
|
451
|
+
const updated = await skillMethods.modifySkill.call(clientContext, {
|
|
452
|
+
payload: { skill_id: "skill_1", default_version: "2" },
|
|
453
|
+
});
|
|
454
|
+
assert.deepEqual(updated, { id: "skill_1", updated: true });
|
|
455
|
+
|
|
456
|
+
const deleted = await skillMethods.deleteSkill.call(clientContext, {
|
|
457
|
+
payload: { skill_id: "skill_1" },
|
|
458
|
+
});
|
|
459
|
+
assert.deepEqual(deleted, { id: "skill_1", deleted: true });
|
|
460
|
+
|
|
461
|
+
const content = await skillMethods.getSkillContent.call(clientContext, {
|
|
462
|
+
payload: { skill_id: "skill_1" },
|
|
463
|
+
});
|
|
464
|
+
assert.deepEqual(content, { id: "skill_1", object: "skill.content" });
|
|
465
|
+
|
|
466
|
+
const listedVersions = await skillMethods.listSkillVersions.call(clientContext, {
|
|
467
|
+
payload: { skill_id: "skill_1", order: "asc" },
|
|
468
|
+
});
|
|
469
|
+
assert.deepEqual(listedVersions, [{ id: "sv_1" }, { id: "sv_2" }]);
|
|
470
|
+
|
|
471
|
+
const createdVersion = await skillMethods.createSkillVersion.call(clientContext, {
|
|
472
|
+
payload: { skill_id: "skill_1", default: true, files: ["./v2.zip"] },
|
|
473
|
+
});
|
|
474
|
+
assert.deepEqual(createdVersion, { id: "skill_version_new", skill_id: "skill_1" });
|
|
475
|
+
|
|
476
|
+
const fetchedVersion = await skillMethods.getSkillVersion.call(clientContext, {
|
|
477
|
+
payload: { skill_id: "skill_1", version: "2" },
|
|
478
|
+
});
|
|
479
|
+
assert.deepEqual(fetchedVersion, { id: "skill_version_1", version: "2" });
|
|
480
|
+
|
|
481
|
+
const deletedVersion = await skillMethods.deleteSkillVersion.call(clientContext, {
|
|
482
|
+
payload: { skill_id: "skill_1", version: "2" },
|
|
483
|
+
});
|
|
484
|
+
assert.deepEqual(deletedVersion, { deleted: true, version: "2" });
|
|
485
|
+
|
|
486
|
+
const versionContent = await skillMethods.getSkillVersionContent.call(clientContext, {
|
|
487
|
+
payload: { skill_id: "skill_1", version: "2" },
|
|
488
|
+
});
|
|
489
|
+
assert.deepEqual(versionContent, { object: "skill.version.content", version: "2" });
|
|
490
|
+
|
|
491
|
+
delete require.cache[modulePath];
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
const skillCalls = calls.filter((entry) => entry.method !== "ctor");
|
|
495
|
+
assert.deepEqual(skillCalls, [
|
|
496
|
+
{
|
|
497
|
+
method: "skills.list",
|
|
498
|
+
options: { order: "desc", limit: 2 },
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
method: "skills.create",
|
|
502
|
+
body: { files: ["./skill.zip"] },
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
method: "skills.retrieve",
|
|
506
|
+
skillId: "skill_1",
|
|
507
|
+
options: {},
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
method: "skills.update",
|
|
511
|
+
skillId: "skill_1",
|
|
512
|
+
body: { default_version: "2" },
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
method: "skills.delete",
|
|
516
|
+
skillId: "skill_1",
|
|
517
|
+
options: {},
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
method: "skills.content.retrieve",
|
|
521
|
+
skillId: "skill_1",
|
|
522
|
+
options: {},
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
method: "skills.versions.list",
|
|
526
|
+
skillId: "skill_1",
|
|
527
|
+
options: { order: "asc" },
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
method: "skills.versions.create",
|
|
531
|
+
skillId: "skill_1",
|
|
532
|
+
body: { default: true, files: ["./v2.zip"] },
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
method: "skills.versions.retrieve",
|
|
536
|
+
version: "2",
|
|
537
|
+
options: { skill_id: "skill_1" },
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
method: "skills.versions.delete",
|
|
541
|
+
version: "2",
|
|
542
|
+
options: { skill_id: "skill_1" },
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
method: "skills.versions.content.retrieve",
|
|
546
|
+
version: "2",
|
|
547
|
+
options: { skill_id: "skill_1" },
|
|
548
|
+
},
|
|
549
|
+
]);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test("evals methods map to OpenAI SDK evals endpoints", async () => {
|
|
553
|
+
const calls = [];
|
|
554
|
+
|
|
555
|
+
class FakeOpenAI {
|
|
556
|
+
constructor(clientParams) {
|
|
557
|
+
calls.push({ method: "ctor", clientParams });
|
|
558
|
+
this.evals = {
|
|
559
|
+
create: async (body) => {
|
|
560
|
+
calls.push({ method: "evals.create", body });
|
|
561
|
+
return { id: "eval_new" };
|
|
562
|
+
},
|
|
563
|
+
retrieve: async (evalId, options) => {
|
|
564
|
+
calls.push({ method: "evals.retrieve", evalId, options });
|
|
565
|
+
return { id: evalId };
|
|
566
|
+
},
|
|
567
|
+
update: async (evalId, body) => {
|
|
568
|
+
calls.push({ method: "evals.update", evalId, body });
|
|
569
|
+
return { id: evalId, updated: true };
|
|
570
|
+
},
|
|
571
|
+
delete: async (evalId, options) => {
|
|
572
|
+
calls.push({ method: "evals.delete", evalId, options });
|
|
573
|
+
return { id: evalId, deleted: true };
|
|
574
|
+
},
|
|
575
|
+
list: async (options) => {
|
|
576
|
+
calls.push({ method: "evals.list", options });
|
|
577
|
+
return { data: [{ id: "eval_1" }, { id: "eval_2" }] };
|
|
578
|
+
},
|
|
579
|
+
runs: {
|
|
580
|
+
create: async (evalId, body) => {
|
|
581
|
+
calls.push({ method: "evals.runs.create", evalId, body });
|
|
582
|
+
return { id: "run_new", eval_id: evalId };
|
|
583
|
+
},
|
|
584
|
+
retrieve: async (runId, options) => {
|
|
585
|
+
calls.push({ method: "evals.runs.retrieve", runId, options });
|
|
586
|
+
return { id: runId };
|
|
587
|
+
},
|
|
588
|
+
list: async (evalId, options) => {
|
|
589
|
+
calls.push({ method: "evals.runs.list", evalId, options });
|
|
590
|
+
return { data: [{ id: "run_1" }, { id: "run_2" }] };
|
|
591
|
+
},
|
|
592
|
+
delete: async (runId, options) => {
|
|
593
|
+
calls.push({ method: "evals.runs.delete", runId, options });
|
|
594
|
+
return { id: runId, deleted: true };
|
|
595
|
+
},
|
|
596
|
+
cancel: async (runId, options) => {
|
|
597
|
+
calls.push({ method: "evals.runs.cancel", runId, options });
|
|
598
|
+
return { id: runId, status: "cancelled" };
|
|
599
|
+
},
|
|
600
|
+
outputItems: {
|
|
601
|
+
retrieve: async (outputItemId, options) => {
|
|
602
|
+
calls.push({
|
|
603
|
+
method: "evals.runs.outputItems.retrieve",
|
|
604
|
+
outputItemId,
|
|
605
|
+
options,
|
|
606
|
+
});
|
|
607
|
+
return { id: outputItemId };
|
|
608
|
+
},
|
|
609
|
+
list: async (runId, options) => {
|
|
610
|
+
calls.push({ method: "evals.runs.outputItems.list", runId, options });
|
|
611
|
+
return { data: [{ id: "out_1" }, { id: "out_2" }] };
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
620
|
+
const modulePath = require.resolve("../src/evals/methods.js");
|
|
621
|
+
delete require.cache[modulePath];
|
|
622
|
+
const evalMethods = require("../src/evals/methods.js");
|
|
623
|
+
|
|
624
|
+
const clientContext = { clientParams: { apiKey: "sk-test" } };
|
|
625
|
+
|
|
626
|
+
const listedEvals = await evalMethods.listEvals.call(clientContext, {
|
|
627
|
+
payload: { order: "desc", limit: 2 },
|
|
628
|
+
});
|
|
629
|
+
assert.deepEqual(listedEvals, [{ id: "eval_1" }, { id: "eval_2" }]);
|
|
630
|
+
|
|
631
|
+
const createdEval = await evalMethods.createEval.call(clientContext, {
|
|
632
|
+
payload: {
|
|
633
|
+
name: "Support quality eval",
|
|
634
|
+
data_source_config: { type: "custom", schema: { type: "object" } },
|
|
635
|
+
testing_criteria: [],
|
|
636
|
+
},
|
|
637
|
+
});
|
|
638
|
+
assert.deepEqual(createdEval, { id: "eval_new" });
|
|
639
|
+
|
|
640
|
+
const fetchedEval = await evalMethods.getEval.call(clientContext, {
|
|
641
|
+
payload: { eval_id: "eval_1" },
|
|
642
|
+
});
|
|
643
|
+
assert.deepEqual(fetchedEval, { id: "eval_1" });
|
|
644
|
+
|
|
645
|
+
const updatedEval = await evalMethods.modifyEval.call(clientContext, {
|
|
646
|
+
payload: { eval_id: "eval_1", name: "Updated eval" },
|
|
647
|
+
});
|
|
648
|
+
assert.deepEqual(updatedEval, { id: "eval_1", updated: true });
|
|
649
|
+
|
|
650
|
+
const deletedEval = await evalMethods.deleteEval.call(clientContext, {
|
|
651
|
+
payload: { eval_id: "eval_1" },
|
|
652
|
+
});
|
|
653
|
+
assert.deepEqual(deletedEval, { id: "eval_1", deleted: true });
|
|
654
|
+
|
|
655
|
+
const listedRuns = await evalMethods.listEvalRuns.call(clientContext, {
|
|
656
|
+
payload: { eval_id: "eval_1", limit: 2 },
|
|
657
|
+
});
|
|
658
|
+
assert.deepEqual(listedRuns, [{ id: "run_1" }, { id: "run_2" }]);
|
|
659
|
+
|
|
660
|
+
const createdRun = await evalMethods.createEvalRun.call(clientContext, {
|
|
661
|
+
payload: {
|
|
662
|
+
eval_id: "eval_1",
|
|
663
|
+
data_source: {
|
|
664
|
+
type: "jsonl",
|
|
665
|
+
source: { type: "file_id", id: "file_1" },
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
});
|
|
669
|
+
assert.deepEqual(createdRun, { id: "run_new", eval_id: "eval_1" });
|
|
670
|
+
|
|
671
|
+
const fetchedRun = await evalMethods.getEvalRun.call(clientContext, {
|
|
672
|
+
payload: { eval_id: "eval_1", run_id: "run_1" },
|
|
673
|
+
});
|
|
674
|
+
assert.deepEqual(fetchedRun, { id: "run_1" });
|
|
675
|
+
|
|
676
|
+
const cancelledRun = await evalMethods.cancelEvalRun.call(clientContext, {
|
|
677
|
+
payload: { eval_id: "eval_1", run_id: "run_1" },
|
|
678
|
+
});
|
|
679
|
+
assert.deepEqual(cancelledRun, { id: "run_1", status: "cancelled" });
|
|
680
|
+
|
|
681
|
+
const deletedRun = await evalMethods.deleteEvalRun.call(clientContext, {
|
|
682
|
+
payload: { eval_id: "eval_1", run_id: "run_1" },
|
|
683
|
+
});
|
|
684
|
+
assert.deepEqual(deletedRun, { id: "run_1", deleted: true });
|
|
685
|
+
|
|
686
|
+
const listedOutputItems = await evalMethods.listEvalRunOutputItems.call(clientContext, {
|
|
687
|
+
payload: { eval_id: "eval_1", run_id: "run_1", limit: 1 },
|
|
688
|
+
});
|
|
689
|
+
assert.deepEqual(listedOutputItems, [{ id: "out_1" }, { id: "out_2" }]);
|
|
690
|
+
|
|
691
|
+
const fetchedOutputItem = await evalMethods.getEvalRunOutputItem.call(clientContext, {
|
|
692
|
+
payload: { eval_id: "eval_1", run_id: "run_1", output_item_id: "out_1" },
|
|
693
|
+
});
|
|
694
|
+
assert.deepEqual(fetchedOutputItem, { id: "out_1" });
|
|
695
|
+
|
|
696
|
+
delete require.cache[modulePath];
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
const evalCalls = calls.filter((entry) => entry.method !== "ctor");
|
|
700
|
+
assert.deepEqual(evalCalls, [
|
|
701
|
+
{
|
|
702
|
+
method: "evals.list",
|
|
703
|
+
options: { order: "desc", limit: 2 },
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
method: "evals.create",
|
|
707
|
+
body: {
|
|
708
|
+
name: "Support quality eval",
|
|
709
|
+
data_source_config: { type: "custom", schema: { type: "object" } },
|
|
710
|
+
testing_criteria: [],
|
|
711
|
+
},
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
method: "evals.retrieve",
|
|
715
|
+
evalId: "eval_1",
|
|
716
|
+
options: {},
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
method: "evals.update",
|
|
720
|
+
evalId: "eval_1",
|
|
721
|
+
body: { name: "Updated eval" },
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
method: "evals.delete",
|
|
725
|
+
evalId: "eval_1",
|
|
726
|
+
options: {},
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
method: "evals.runs.list",
|
|
730
|
+
evalId: "eval_1",
|
|
731
|
+
options: { limit: 2 },
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
method: "evals.runs.create",
|
|
735
|
+
evalId: "eval_1",
|
|
736
|
+
body: {
|
|
737
|
+
data_source: {
|
|
738
|
+
type: "jsonl",
|
|
739
|
+
source: { type: "file_id", id: "file_1" },
|
|
740
|
+
},
|
|
741
|
+
},
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
method: "evals.runs.retrieve",
|
|
745
|
+
runId: "run_1",
|
|
746
|
+
options: { eval_id: "eval_1" },
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
method: "evals.runs.cancel",
|
|
750
|
+
runId: "run_1",
|
|
751
|
+
options: { eval_id: "eval_1" },
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
method: "evals.runs.delete",
|
|
755
|
+
runId: "run_1",
|
|
756
|
+
options: { eval_id: "eval_1" },
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
method: "evals.runs.outputItems.list",
|
|
760
|
+
runId: "run_1",
|
|
761
|
+
options: { eval_id: "eval_1", limit: 1 },
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
method: "evals.runs.outputItems.retrieve",
|
|
765
|
+
outputItemId: "out_1",
|
|
766
|
+
options: { eval_id: "eval_1", run_id: "run_1" },
|
|
767
|
+
},
|
|
768
|
+
]);
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
test("videos methods map to OpenAI SDK videos endpoints", async () => {
|
|
772
|
+
const calls = [];
|
|
773
|
+
|
|
774
|
+
class FakeOpenAI {
|
|
775
|
+
constructor(clientParams) {
|
|
776
|
+
calls.push({ method: "ctor", clientParams });
|
|
777
|
+
this.videos = {
|
|
778
|
+
create: async (body) => {
|
|
779
|
+
calls.push({ method: "videos.create", body });
|
|
780
|
+
return { id: "video_new" };
|
|
781
|
+
},
|
|
782
|
+
retrieve: async (videoId, options) => {
|
|
783
|
+
calls.push({ method: "videos.retrieve", videoId, options });
|
|
784
|
+
return { id: videoId };
|
|
785
|
+
},
|
|
786
|
+
list: async (options) => {
|
|
787
|
+
calls.push({ method: "videos.list", options });
|
|
788
|
+
return { data: [{ id: "video_1" }, { id: "video_2" }] };
|
|
789
|
+
},
|
|
790
|
+
delete: async (videoId, options) => {
|
|
791
|
+
calls.push({ method: "videos.delete", videoId, options });
|
|
792
|
+
return { id: videoId, deleted: true };
|
|
793
|
+
},
|
|
794
|
+
downloadContent: async (videoId, query) => {
|
|
795
|
+
calls.push({ method: "videos.downloadContent", videoId, query });
|
|
796
|
+
return { binary: true };
|
|
797
|
+
},
|
|
798
|
+
remix: async (videoId, body) => {
|
|
799
|
+
calls.push({ method: "videos.remix", videoId, body });
|
|
800
|
+
return { id: "video_remix" };
|
|
801
|
+
},
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
807
|
+
const modulePath = require.resolve("../src/videos/methods.js");
|
|
808
|
+
delete require.cache[modulePath];
|
|
809
|
+
const videoMethods = require("../src/videos/methods.js");
|
|
810
|
+
|
|
811
|
+
const clientContext = { clientParams: { apiKey: "sk-test" } };
|
|
812
|
+
|
|
813
|
+
const listedVideos = await videoMethods.listVideos.call(clientContext, {
|
|
814
|
+
payload: { order: "desc", limit: 1 },
|
|
815
|
+
});
|
|
816
|
+
assert.deepEqual(listedVideos, [{ id: "video_1" }, { id: "video_2" }]);
|
|
817
|
+
|
|
818
|
+
const createdVideo = await videoMethods.createVideo.call(clientContext, {
|
|
819
|
+
payload: { prompt: "A sunrise over mountains", model: "sora-2" },
|
|
820
|
+
});
|
|
821
|
+
assert.deepEqual(createdVideo, { id: "video_new" });
|
|
822
|
+
|
|
823
|
+
const fetchedVideo = await videoMethods.getVideo.call(clientContext, {
|
|
824
|
+
payload: { video_id: "video_1" },
|
|
825
|
+
});
|
|
826
|
+
assert.deepEqual(fetchedVideo, { id: "video_1" });
|
|
827
|
+
|
|
828
|
+
const deletedVideo = await videoMethods.deleteVideo.call(clientContext, {
|
|
829
|
+
payload: { video_id: "video_1" },
|
|
830
|
+
});
|
|
831
|
+
assert.deepEqual(deletedVideo, { id: "video_1", deleted: true });
|
|
832
|
+
|
|
833
|
+
const downloaded = await videoMethods.downloadVideoContent.call(clientContext, {
|
|
834
|
+
payload: { video_id: "video_1", variant: "thumbnail" },
|
|
835
|
+
});
|
|
836
|
+
assert.deepEqual(downloaded, { binary: true });
|
|
837
|
+
|
|
838
|
+
const remixed = await videoMethods.remixVideo.call(clientContext, {
|
|
839
|
+
payload: { video_id: "video_1", prompt: "Make it cinematic" },
|
|
840
|
+
});
|
|
841
|
+
assert.deepEqual(remixed, { id: "video_remix" });
|
|
842
|
+
|
|
843
|
+
delete require.cache[modulePath];
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
const videoCalls = calls.filter((entry) => entry.method !== "ctor");
|
|
847
|
+
assert.deepEqual(videoCalls, [
|
|
848
|
+
{
|
|
849
|
+
method: "videos.list",
|
|
850
|
+
options: { order: "desc", limit: 1 },
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
method: "videos.create",
|
|
854
|
+
body: { prompt: "A sunrise over mountains", model: "sora-2" },
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
method: "videos.retrieve",
|
|
858
|
+
videoId: "video_1",
|
|
859
|
+
options: {},
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
method: "videos.delete",
|
|
863
|
+
videoId: "video_1",
|
|
864
|
+
options: {},
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
method: "videos.downloadContent",
|
|
868
|
+
videoId: "video_1",
|
|
869
|
+
query: { variant: "thumbnail" },
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
method: "videos.remix",
|
|
873
|
+
videoId: "video_1",
|
|
874
|
+
body: { prompt: "Make it cinematic" },
|
|
875
|
+
},
|
|
876
|
+
]);
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
test("realtime methods map to OpenAI SDK realtime endpoints", async () => {
|
|
880
|
+
const calls = [];
|
|
881
|
+
|
|
882
|
+
class FakeOpenAI {
|
|
883
|
+
constructor(clientParams) {
|
|
884
|
+
calls.push({ method: "ctor", clientParams });
|
|
885
|
+
this.realtime = {
|
|
886
|
+
clientSecrets: {
|
|
887
|
+
create: async (body) => {
|
|
888
|
+
calls.push({ method: "realtime.clientSecrets.create", body });
|
|
889
|
+
return { client_secret: { value: "rt_secret_1", expires_at: 123 } };
|
|
890
|
+
},
|
|
891
|
+
},
|
|
892
|
+
calls: {
|
|
893
|
+
accept: async (callId, body) => {
|
|
894
|
+
calls.push({ method: "realtime.calls.accept", callId, body });
|
|
895
|
+
},
|
|
896
|
+
hangup: async (callId, options) => {
|
|
897
|
+
calls.push({ method: "realtime.calls.hangup", callId, options });
|
|
898
|
+
},
|
|
899
|
+
refer: async (callId, body) => {
|
|
900
|
+
calls.push({ method: "realtime.calls.refer", callId, body });
|
|
901
|
+
},
|
|
902
|
+
reject: async (callId, body) => {
|
|
903
|
+
calls.push({ method: "realtime.calls.reject", callId, body });
|
|
904
|
+
},
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
911
|
+
const modulePath = require.resolve("../src/realtime/methods.js");
|
|
912
|
+
delete require.cache[modulePath];
|
|
913
|
+
const realtimeMethods = require("../src/realtime/methods.js");
|
|
914
|
+
|
|
915
|
+
const clientContext = { clientParams: { apiKey: "sk-test" } };
|
|
916
|
+
|
|
917
|
+
const secret = await realtimeMethods.createRealtimeClientSecret.call(clientContext, {
|
|
918
|
+
payload: { model: "gpt-realtime" },
|
|
919
|
+
});
|
|
920
|
+
assert.deepEqual(secret, { client_secret: { value: "rt_secret_1", expires_at: 123 } });
|
|
921
|
+
|
|
922
|
+
const accepted = await realtimeMethods.acceptRealtimeCall.call(clientContext, {
|
|
923
|
+
payload: { call_id: "call_1", type: "realtime", model: "gpt-realtime" },
|
|
924
|
+
});
|
|
925
|
+
assert.deepEqual(accepted, { call_id: "call_1", status: "accepted" });
|
|
926
|
+
|
|
927
|
+
const hungUp = await realtimeMethods.hangupRealtimeCall.call(clientContext, {
|
|
928
|
+
payload: { call_id: "call_1" },
|
|
929
|
+
});
|
|
930
|
+
assert.deepEqual(hungUp, { call_id: "call_1", status: "hung_up" });
|
|
931
|
+
|
|
932
|
+
const referred = await realtimeMethods.referRealtimeCall.call(clientContext, {
|
|
933
|
+
payload: { call_id: "call_1", target_uri: "tel:+14155550123" },
|
|
934
|
+
});
|
|
935
|
+
assert.deepEqual(referred, { call_id: "call_1", status: "referred" });
|
|
936
|
+
|
|
937
|
+
const rejected = await realtimeMethods.rejectRealtimeCall.call(clientContext, {
|
|
938
|
+
payload: { call_id: "call_2", status_code: 486 },
|
|
939
|
+
});
|
|
940
|
+
assert.deepEqual(rejected, { call_id: "call_2", status: "rejected" });
|
|
941
|
+
|
|
942
|
+
delete require.cache[modulePath];
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
const realtimeCalls = calls.filter((entry) => entry.method !== "ctor");
|
|
946
|
+
assert.deepEqual(realtimeCalls, [
|
|
947
|
+
{
|
|
948
|
+
method: "realtime.clientSecrets.create",
|
|
949
|
+
body: { model: "gpt-realtime" },
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
method: "realtime.calls.accept",
|
|
953
|
+
callId: "call_1",
|
|
954
|
+
body: { type: "realtime", model: "gpt-realtime" },
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
method: "realtime.calls.hangup",
|
|
958
|
+
callId: "call_1",
|
|
959
|
+
options: {},
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
method: "realtime.calls.refer",
|
|
963
|
+
callId: "call_1",
|
|
964
|
+
body: { target_uri: "tel:+14155550123" },
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
method: "realtime.calls.reject",
|
|
968
|
+
callId: "call_2",
|
|
969
|
+
body: { status_code: 486 },
|
|
970
|
+
},
|
|
971
|
+
]);
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
test("webhooks methods map to OpenAI SDK webhooks utilities", async () => {
|
|
975
|
+
const calls = [];
|
|
976
|
+
|
|
977
|
+
class FakeOpenAI {
|
|
978
|
+
constructor(clientParams) {
|
|
979
|
+
calls.push({ method: "ctor", clientParams });
|
|
980
|
+
this.webhooks = {
|
|
981
|
+
unwrap: async (payload, headers, secret, tolerance) => {
|
|
982
|
+
calls.push({
|
|
983
|
+
method: "webhooks.unwrap",
|
|
984
|
+
payload,
|
|
985
|
+
headers,
|
|
986
|
+
secret,
|
|
987
|
+
tolerance,
|
|
988
|
+
});
|
|
989
|
+
return { id: "evt_1", type: "response.completed" };
|
|
990
|
+
},
|
|
991
|
+
verifySignature: async (payload, headers, secret, tolerance) => {
|
|
992
|
+
calls.push({
|
|
993
|
+
method: "webhooks.verifySignature",
|
|
994
|
+
payload,
|
|
995
|
+
headers,
|
|
996
|
+
secret,
|
|
997
|
+
tolerance,
|
|
998
|
+
});
|
|
999
|
+
},
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
await withMockedOpenAI(FakeOpenAI, async () => {
|
|
1005
|
+
const modulePath = require.resolve("../src/webhooks/methods.js");
|
|
1006
|
+
delete require.cache[modulePath];
|
|
1007
|
+
const webhookMethods = require("../src/webhooks/methods.js");
|
|
1008
|
+
|
|
1009
|
+
const clientContext = { clientParams: { apiKey: "sk-test" } };
|
|
1010
|
+
|
|
1011
|
+
const event = await webhookMethods.unwrapWebhookEvent.call(clientContext, {
|
|
1012
|
+
payload: {
|
|
1013
|
+
payload: "{\"id\":\"evt_1\"}",
|
|
1014
|
+
headers: {
|
|
1015
|
+
"webhook-id": "wh_1",
|
|
1016
|
+
"webhook-signature": "v1,abc",
|
|
1017
|
+
"webhook-timestamp": "123",
|
|
1018
|
+
},
|
|
1019
|
+
secret: "whsec_test",
|
|
1020
|
+
tolerance: 30,
|
|
1021
|
+
},
|
|
1022
|
+
});
|
|
1023
|
+
assert.deepEqual(event, { id: "evt_1", type: "response.completed" });
|
|
1024
|
+
|
|
1025
|
+
const verified = await webhookMethods.verifyWebhookSignature.call(clientContext, {
|
|
1026
|
+
payload: {
|
|
1027
|
+
payload: "{\"id\":\"evt_1\"}",
|
|
1028
|
+
headers: {
|
|
1029
|
+
"webhook-id": "wh_1",
|
|
1030
|
+
"webhook-signature": "v1,abc",
|
|
1031
|
+
"webhook-timestamp": "123",
|
|
1032
|
+
},
|
|
1033
|
+
secret: "whsec_test",
|
|
1034
|
+
tolerance: 30,
|
|
1035
|
+
},
|
|
1036
|
+
});
|
|
1037
|
+
assert.deepEqual(verified, { verified: true });
|
|
1038
|
+
|
|
1039
|
+
delete require.cache[modulePath];
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
const webhookCalls = calls.filter((entry) => entry.method !== "ctor");
|
|
1043
|
+
assert.deepEqual(webhookCalls, [
|
|
1044
|
+
{
|
|
1045
|
+
method: "webhooks.unwrap",
|
|
1046
|
+
payload: "{\"id\":\"evt_1\"}",
|
|
1047
|
+
headers: {
|
|
1048
|
+
"webhook-id": "wh_1",
|
|
1049
|
+
"webhook-signature": "v1,abc",
|
|
1050
|
+
"webhook-timestamp": "123",
|
|
1051
|
+
},
|
|
1052
|
+
secret: "whsec_test",
|
|
1053
|
+
tolerance: 30,
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
method: "webhooks.verifySignature",
|
|
1057
|
+
payload: "{\"id\":\"evt_1\"}",
|
|
1058
|
+
headers: {
|
|
1059
|
+
"webhook-id": "wh_1",
|
|
1060
|
+
"webhook-signature": "v1,abc",
|
|
1061
|
+
"webhook-timestamp": "123",
|
|
1062
|
+
},
|
|
1063
|
+
secret: "whsec_test",
|
|
1064
|
+
tolerance: 30,
|
|
1065
|
+
},
|
|
1066
|
+
]);
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
test("OpenaiApi prototype exposes latest methods", () => {
|
|
1070
|
+
const OpenaiApi = require("../src/lib.js");
|
|
1071
|
+
const client = new OpenaiApi("sk-test", "https://api.openai.com/v1", null);
|
|
1072
|
+
|
|
1073
|
+
assert.equal(typeof client.cancelModelResponse, "function");
|
|
1074
|
+
assert.equal(typeof client.compactModelResponse, "function");
|
|
1075
|
+
assert.equal(typeof client.countInputTokens, "function");
|
|
1076
|
+
assert.equal(typeof client.createConversation, "function");
|
|
1077
|
+
assert.equal(typeof client.listConversationItems, "function");
|
|
1078
|
+
assert.equal(typeof client.createEval, "function");
|
|
1079
|
+
assert.equal(typeof client.listEvalRunOutputItems, "function");
|
|
1080
|
+
assert.equal(typeof client.createRealtimeClientSecret, "function");
|
|
1081
|
+
assert.equal(typeof client.listSkills, "function");
|
|
1082
|
+
assert.equal(typeof client.getSkillVersionContent, "function");
|
|
1083
|
+
assert.equal(typeof client.createVideo, "function");
|
|
1084
|
+
assert.equal(typeof client.verifyWebhookSignature, "function");
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
test("editor templates and locale expose latest methods", () => {
|
|
1088
|
+
const responsesTemplate = fs.readFileSync(
|
|
1089
|
+
path.join(__dirname, "..", "src", "responses", "template.html"),
|
|
1090
|
+
"utf8"
|
|
1091
|
+
);
|
|
1092
|
+
const conversationsTemplate = fs.readFileSync(
|
|
1093
|
+
path.join(__dirname, "..", "src", "conversations", "template.html"),
|
|
1094
|
+
"utf8"
|
|
1095
|
+
);
|
|
1096
|
+
const skillsTemplate = fs.readFileSync(
|
|
1097
|
+
path.join(__dirname, "..", "src", "skills", "template.html"),
|
|
1098
|
+
"utf8"
|
|
1099
|
+
);
|
|
1100
|
+
const evalsTemplate = fs.readFileSync(
|
|
1101
|
+
path.join(__dirname, "..", "src", "evals", "template.html"),
|
|
1102
|
+
"utf8"
|
|
1103
|
+
);
|
|
1104
|
+
const realtimeTemplate = fs.readFileSync(
|
|
1105
|
+
path.join(__dirname, "..", "src", "realtime", "template.html"),
|
|
1106
|
+
"utf8"
|
|
1107
|
+
);
|
|
1108
|
+
const videosTemplate = fs.readFileSync(
|
|
1109
|
+
path.join(__dirname, "..", "src", "videos", "template.html"),
|
|
1110
|
+
"utf8"
|
|
1111
|
+
);
|
|
1112
|
+
const webhooksTemplate = fs.readFileSync(
|
|
1113
|
+
path.join(__dirname, "..", "src", "webhooks", "template.html"),
|
|
1114
|
+
"utf8"
|
|
1115
|
+
);
|
|
1116
|
+
const nodeTemplate = fs.readFileSync(
|
|
1117
|
+
path.join(__dirname, "..", "src", "node.html"),
|
|
1118
|
+
"utf8"
|
|
1119
|
+
);
|
|
1120
|
+
const responsesHelp = fs.readFileSync(
|
|
1121
|
+
path.join(__dirname, "..", "src", "responses", "help.html"),
|
|
1122
|
+
"utf8"
|
|
1123
|
+
);
|
|
1124
|
+
const skillsHelp = fs.readFileSync(
|
|
1125
|
+
path.join(__dirname, "..", "src", "skills", "help.html"),
|
|
1126
|
+
"utf8"
|
|
1127
|
+
);
|
|
1128
|
+
const evalsHelp = fs.readFileSync(
|
|
1129
|
+
path.join(__dirname, "..", "src", "evals", "help.html"),
|
|
1130
|
+
"utf8"
|
|
1131
|
+
);
|
|
1132
|
+
const realtimeHelp = fs.readFileSync(
|
|
1133
|
+
path.join(__dirname, "..", "src", "realtime", "help.html"),
|
|
1134
|
+
"utf8"
|
|
1135
|
+
);
|
|
1136
|
+
const videosHelp = fs.readFileSync(
|
|
1137
|
+
path.join(__dirname, "..", "src", "videos", "help.html"),
|
|
1138
|
+
"utf8"
|
|
1139
|
+
);
|
|
1140
|
+
const webhooksHelp = fs.readFileSync(
|
|
1141
|
+
path.join(__dirname, "..", "src", "webhooks", "help.html"),
|
|
1142
|
+
"utf8"
|
|
1143
|
+
);
|
|
1144
|
+
const locale = JSON.parse(
|
|
1145
|
+
fs.readFileSync(path.join(__dirname, "..", "locales", "en-US", "node.json"), "utf8")
|
|
1146
|
+
);
|
|
1147
|
+
|
|
1148
|
+
assert.match(responsesTemplate, /value="cancelModelResponse"/);
|
|
1149
|
+
assert.match(responsesTemplate, /value="compactModelResponse"/);
|
|
1150
|
+
assert.match(responsesTemplate, /value="countInputTokens"/);
|
|
1151
|
+
assert.match(conversationsTemplate, /value="createConversation"/);
|
|
1152
|
+
assert.match(conversationsTemplate, /value="listConversationItems"/);
|
|
1153
|
+
assert.match(skillsTemplate, /value="listSkills"/);
|
|
1154
|
+
assert.match(skillsTemplate, /value="getSkillVersionContent"/);
|
|
1155
|
+
assert.match(evalsTemplate, /value="createEval"/);
|
|
1156
|
+
assert.match(evalsTemplate, /value="listEvalRunOutputItems"/);
|
|
1157
|
+
assert.match(realtimeTemplate, /value="createRealtimeClientSecret"/);
|
|
1158
|
+
assert.match(realtimeTemplate, /value="rejectRealtimeCall"/);
|
|
1159
|
+
assert.match(videosTemplate, /value="downloadVideoContent"/);
|
|
1160
|
+
assert.match(webhooksTemplate, /value="verifyWebhookSignature"/);
|
|
1161
|
+
assert.match(nodeTemplate, /@@include\('\.\/conversations\/template\.html'\)/);
|
|
1162
|
+
assert.match(nodeTemplate, /@@include\('\.\/conversations\/help\.html'\)/);
|
|
1163
|
+
assert.match(nodeTemplate, /@@include\('\.\/evals\/template\.html'\)/);
|
|
1164
|
+
assert.match(nodeTemplate, /@@include\('\.\/evals\/help\.html'\)/);
|
|
1165
|
+
assert.match(nodeTemplate, /@@include\('\.\/realtime\/template\.html'\)/);
|
|
1166
|
+
assert.match(nodeTemplate, /@@include\('\.\/realtime\/help\.html'\)/);
|
|
1167
|
+
assert.match(nodeTemplate, /@@include\('\.\/skills\/template\.html'\)/);
|
|
1168
|
+
assert.match(nodeTemplate, /@@include\('\.\/skills\/help\.html'\)/);
|
|
1169
|
+
assert.match(nodeTemplate, /@@include\('\.\/videos\/template\.html'\)/);
|
|
1170
|
+
assert.match(nodeTemplate, /@@include\('\.\/videos\/help\.html'\)/);
|
|
1171
|
+
assert.match(nodeTemplate, /@@include\('\.\/webhooks\/template\.html'\)/);
|
|
1172
|
+
assert.match(nodeTemplate, /@@include\('\.\/webhooks\/help\.html'\)/);
|
|
1173
|
+
assert.match(responsesHelp, /⋙ Count Input Tokens/);
|
|
1174
|
+
assert.match(responsesHelp, /Default is <code>desc<\/code>/);
|
|
1175
|
+
assert.match(evalsHelp, /⋙ Create Eval/);
|
|
1176
|
+
assert.match(evalsHelp, /⋙ List Eval Run Output Items/);
|
|
1177
|
+
assert.match(realtimeHelp, /⋙ Create Realtime Client Secret/);
|
|
1178
|
+
assert.match(realtimeHelp, /⋙ Reject Realtime Call/);
|
|
1179
|
+
assert.match(skillsHelp, /⋙ Create Skill/);
|
|
1180
|
+
assert.match(skillsHelp, /⋙ List Skill Versions/);
|
|
1181
|
+
assert.match(videosHelp, /⋙ Download Video Content/);
|
|
1182
|
+
assert.match(webhooksHelp, /⋙ Verify Webhook Signature/);
|
|
1183
|
+
|
|
1184
|
+
assert.equal(
|
|
1185
|
+
locale.OpenaiApi.parameters.cancelModelResponse,
|
|
1186
|
+
"cancel model response"
|
|
1187
|
+
);
|
|
1188
|
+
assert.equal(
|
|
1189
|
+
locale.OpenaiApi.parameters.countInputTokens,
|
|
1190
|
+
"count input tokens"
|
|
1191
|
+
);
|
|
1192
|
+
assert.equal(
|
|
1193
|
+
locale.OpenaiApi.parameters.createConversation,
|
|
1194
|
+
"create conversation"
|
|
1195
|
+
);
|
|
1196
|
+
assert.equal(
|
|
1197
|
+
locale.OpenaiApi.parameters.listSkills,
|
|
1198
|
+
"list skills"
|
|
1199
|
+
);
|
|
1200
|
+
assert.equal(
|
|
1201
|
+
locale.OpenaiApi.parameters.getSkillVersion,
|
|
1202
|
+
"retrieve skill version"
|
|
1203
|
+
);
|
|
1204
|
+
assert.equal(
|
|
1205
|
+
locale.OpenaiApi.parameters.createEvalRun,
|
|
1206
|
+
"create eval run"
|
|
1207
|
+
);
|
|
1208
|
+
assert.equal(
|
|
1209
|
+
locale.OpenaiApi.parameters.acceptRealtimeCall,
|
|
1210
|
+
"accept realtime call"
|
|
1211
|
+
);
|
|
1212
|
+
assert.equal(
|
|
1213
|
+
locale.OpenaiApi.parameters.downloadVideoContent,
|
|
1214
|
+
"download video content"
|
|
1215
|
+
);
|
|
1216
|
+
assert.equal(
|
|
1217
|
+
locale.OpenaiApi.parameters.verifyWebhookSignature,
|
|
1218
|
+
"verify webhook signature"
|
|
1219
|
+
);
|
|
1220
|
+
});
|