@crewdle/mist-connector-openai 1.0.12 → 1.0.14
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/models/OpenAIFileConnector.js +1 -1
- package/dist/models/OpenAIGenerativeAIWorkerConnector.js +154 -150
- package/dist/models/OpenAISpeechConnector.js +14 -1
- package/dist/types/models/OpenAIGenerativeAIWorkerConnector.d.ts +2 -2
- package/dist/types/models/OpenAISpeechConnector.d.ts +1 -1
- package/package.json +3 -3
|
@@ -50,33 +50,43 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
50
50
|
const responseFormat = this.getResponseFormat(parameters);
|
|
51
51
|
const tools = this.getTools(parameters);
|
|
52
52
|
const messages = this.getMessages(parameters);
|
|
53
|
-
let
|
|
54
|
-
let
|
|
55
|
-
let
|
|
53
|
+
let inputTokens = 0;
|
|
54
|
+
let outputTokens = 0;
|
|
55
|
+
let output = '';
|
|
56
56
|
while (true) {
|
|
57
|
-
const response = await this.client.
|
|
57
|
+
const response = await this.client.responses.create({
|
|
58
58
|
model: options.model.id,
|
|
59
|
-
messages,
|
|
60
|
-
|
|
59
|
+
input: messages,
|
|
60
|
+
max_output_tokens: parameters.maxTokens,
|
|
61
61
|
temperature: parameters.temperature,
|
|
62
|
-
|
|
62
|
+
text: responseFormat,
|
|
63
63
|
tools,
|
|
64
64
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
totalOutputTokens += response.usage?.completion_tokens ?? 0;
|
|
68
|
-
if (!message.tool_calls) {
|
|
69
|
-
accumulatedOutput += message.content ?? '';
|
|
70
|
-
return {
|
|
71
|
-
type: 'prompt',
|
|
72
|
-
output: accumulatedOutput,
|
|
73
|
-
inputTokens: totalInputTokens,
|
|
74
|
-
outputTokens: totalOutputTokens,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
65
|
+
inputTokens += response.usage?.input_tokens ?? 0;
|
|
66
|
+
outputTokens += response.usage?.output_tokens ?? 0;
|
|
77
67
|
const promises = [];
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
for (const content of response.output) {
|
|
69
|
+
if (content.type === 'message') {
|
|
70
|
+
for (const message of content.content) {
|
|
71
|
+
if (message.type === 'output_text') {
|
|
72
|
+
output += message.text;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (content.type === 'function_call') {
|
|
77
|
+
promises.push(this.processToolCall(parameters, messages, content.name, content.call_id, content.arguments));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (promises.length > 0) {
|
|
81
|
+
await Promise.all(promises);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
86
|
+
output,
|
|
87
|
+
inputTokens,
|
|
88
|
+
outputTokens,
|
|
89
|
+
};
|
|
80
90
|
}
|
|
81
91
|
}
|
|
82
92
|
async *processJobStream(parameters, options) {
|
|
@@ -90,134 +100,96 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
90
100
|
const tools = this.getTools(parameters);
|
|
91
101
|
const messages = this.getMessages(parameters);
|
|
92
102
|
while (true) {
|
|
93
|
-
const stream = await this.client.
|
|
103
|
+
const stream = await this.client.responses.create({
|
|
94
104
|
model: options.model.id,
|
|
95
|
-
messages,
|
|
96
|
-
|
|
105
|
+
input: messages,
|
|
106
|
+
max_output_tokens: parameters.maxTokens,
|
|
97
107
|
temperature: parameters.temperature,
|
|
98
|
-
|
|
99
|
-
stream_options: {
|
|
100
|
-
include_usage: true,
|
|
101
|
-
},
|
|
108
|
+
text: responseFormat,
|
|
102
109
|
tools,
|
|
103
|
-
|
|
110
|
+
stream: true,
|
|
104
111
|
});
|
|
105
|
-
|
|
112
|
+
const promises = [];
|
|
106
113
|
for await (const chunk of stream) {
|
|
107
|
-
if (chunk.
|
|
108
|
-
|
|
114
|
+
if (chunk.type === 'response.output_text.delta') {
|
|
115
|
+
yield {
|
|
116
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
117
|
+
output: chunk.delta,
|
|
118
|
+
inputTokens: 0,
|
|
119
|
+
outputTokens: 0,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (chunk.type === 'response.completed') {
|
|
123
|
+
yield {
|
|
124
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
125
|
+
output: '',
|
|
126
|
+
inputTokens: chunk.response.usage?.input_tokens ?? 0,
|
|
127
|
+
outputTokens: chunk.response.usage?.output_tokens ?? 0,
|
|
128
|
+
};
|
|
109
129
|
}
|
|
130
|
+
if (chunk.type === 'response.output_item.done') {
|
|
131
|
+
if (chunk.item.type === 'function_call') {
|
|
132
|
+
promises.push(this.processToolCall(parameters, messages, chunk.item.name, chunk.item.call_id, chunk.item.arguments));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (promises.length > 0) {
|
|
137
|
+
await Promise.all(promises);
|
|
110
138
|
yield {
|
|
111
|
-
type:
|
|
112
|
-
output:
|
|
113
|
-
inputTokens:
|
|
114
|
-
outputTokens:
|
|
139
|
+
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
140
|
+
output: '\n\n',
|
|
141
|
+
inputTokens: 0,
|
|
142
|
+
outputTokens: 0,
|
|
115
143
|
};
|
|
144
|
+
continue;
|
|
116
145
|
}
|
|
117
|
-
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
const promises = [];
|
|
121
|
-
this.processToolCalls(promises, message.tool_calls, messages, parameters.functions);
|
|
122
|
-
await Promise.all(promises);
|
|
123
|
-
yield {
|
|
124
|
-
type: "prompt" /* GenerativeAIJobType.Prompt */,
|
|
125
|
-
output: '\n\n',
|
|
126
|
-
inputTokens: 0,
|
|
127
|
-
outputTokens: 0,
|
|
128
|
-
};
|
|
146
|
+
break;
|
|
129
147
|
}
|
|
130
148
|
}
|
|
131
|
-
|
|
149
|
+
async processToolCall(parameters, messages, toolName, toolCallId, input) {
|
|
132
150
|
messages.push({
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
151
|
+
type: 'function_call',
|
|
152
|
+
arguments: input,
|
|
153
|
+
call_id: toolCallId,
|
|
154
|
+
name: toolName,
|
|
137
155
|
});
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
messages.push({
|
|
147
|
-
role: 'tool',
|
|
148
|
-
tool_call_id: toolCall.id,
|
|
149
|
-
content: res ?? 'Tool does not exist',
|
|
150
|
-
});
|
|
151
|
-
}));
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
messages.push({
|
|
155
|
-
role: 'tool',
|
|
156
|
-
tool_call_id: toolCall.id,
|
|
157
|
-
content: result ?? 'Tool does not exist',
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
messages.push({
|
|
163
|
-
role: 'tool',
|
|
164
|
-
tool_call_id: toolCall.id,
|
|
165
|
-
content: 'Tool does not exist',
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
catch (error) {
|
|
170
|
-
console.error('Error processing tool call', error);
|
|
171
|
-
messages.push({
|
|
172
|
-
role: 'tool',
|
|
173
|
-
tool_call_id: toolCall.id,
|
|
174
|
-
content: 'Error processing tool call',
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
156
|
+
const func = parameters.functions?.get(toolName);
|
|
157
|
+
if (!func) {
|
|
158
|
+
messages.push({
|
|
159
|
+
type: 'function_call_output',
|
|
160
|
+
call_id: toolCallId,
|
|
161
|
+
output: 'Tool not found',
|
|
162
|
+
});
|
|
163
|
+
return;
|
|
178
164
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
acc[key] = value;
|
|
198
|
-
}
|
|
199
|
-
else if (Array.isArray(acc[key]) && Array.isArray(value)) {
|
|
200
|
-
const accArray = acc[key];
|
|
201
|
-
for (let i = 0; i < value.length; i++) {
|
|
202
|
-
const { index, ...chunkTool } = value[i];
|
|
203
|
-
if (index - accArray.length > 1) {
|
|
204
|
-
throw new Error(`Error: An array has an empty value when tool_calls are constructed. tool_calls: ${accArray}; tool: ${value}`);
|
|
205
|
-
}
|
|
206
|
-
accArray[index] = reduce(accArray[index], chunkTool);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
else if (typeof acc[key] === 'object' && typeof value === 'object') {
|
|
210
|
-
acc[key] = reduce(acc[key], value);
|
|
211
|
-
}
|
|
165
|
+
try {
|
|
166
|
+
if (input === '') {
|
|
167
|
+
input = '{}';
|
|
168
|
+
}
|
|
169
|
+
const result = func.callback(JSON.parse(input));
|
|
170
|
+
if (result instanceof Promise) {
|
|
171
|
+
messages.push({
|
|
172
|
+
type: 'function_call_output',
|
|
173
|
+
call_id: toolCallId,
|
|
174
|
+
output: await result,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
messages.push({
|
|
179
|
+
type: 'function_call_output',
|
|
180
|
+
call_id: toolCallId,
|
|
181
|
+
output: result,
|
|
182
|
+
});
|
|
212
183
|
}
|
|
213
|
-
return acc;
|
|
214
|
-
};
|
|
215
|
-
const choice = item.choices[0];
|
|
216
|
-
if (!choice) {
|
|
217
|
-
// chunk contains information about usage and token counts
|
|
218
|
-
return previous;
|
|
219
184
|
}
|
|
220
|
-
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.error('Error processing tool call', error);
|
|
187
|
+
messages.push({
|
|
188
|
+
type: 'function_call_output',
|
|
189
|
+
call_id: toolCallId,
|
|
190
|
+
output: 'Error processing tool call',
|
|
191
|
+
});
|
|
192
|
+
}
|
|
221
193
|
}
|
|
222
194
|
getMessages(parameters) {
|
|
223
195
|
const messages = [];
|
|
@@ -237,31 +209,58 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
237
209
|
}
|
|
238
210
|
messages.push({
|
|
239
211
|
role: 'user',
|
|
240
|
-
content: parameters.prompt,
|
|
212
|
+
content: this.getInnerMessages(parameters.prompt),
|
|
241
213
|
});
|
|
242
214
|
return messages;
|
|
243
215
|
}
|
|
216
|
+
getInnerMessages(content) {
|
|
217
|
+
if (typeof content === 'string') {
|
|
218
|
+
return content;
|
|
219
|
+
}
|
|
220
|
+
return content.map((c) => {
|
|
221
|
+
if (c.type === 'text') {
|
|
222
|
+
return {
|
|
223
|
+
type: 'input_text',
|
|
224
|
+
text: c.text,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
if (c.type === 'file') {
|
|
228
|
+
return {
|
|
229
|
+
type: 'input_file',
|
|
230
|
+
filename: c.file.filename,
|
|
231
|
+
file_data: c.file.file_data,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (c.type === 'image_url') {
|
|
235
|
+
return {
|
|
236
|
+
type: 'input_image',
|
|
237
|
+
image_url: c.image_url.url,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
throw new Error('Invalid content type');
|
|
241
|
+
});
|
|
242
|
+
}
|
|
244
243
|
getTools(parameters) {
|
|
245
244
|
if (!parameters.functions || parameters.functions.size === 0) {
|
|
246
245
|
return undefined;
|
|
247
246
|
}
|
|
248
247
|
const tools = [];
|
|
249
248
|
for (const [name, func] of parameters.functions) {
|
|
250
|
-
let params;
|
|
249
|
+
let params = null;
|
|
251
250
|
if (func.params) {
|
|
252
251
|
params = {
|
|
253
252
|
type: 'object',
|
|
254
253
|
properties: func.params,
|
|
255
254
|
required: Object.keys(func.params),
|
|
255
|
+
additionalProperties: false,
|
|
256
256
|
};
|
|
257
257
|
}
|
|
258
258
|
tools.push({
|
|
259
259
|
type: 'function',
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
260
|
+
name,
|
|
261
|
+
description: func.description,
|
|
262
|
+
strict: true,
|
|
263
|
+
parameters: params,
|
|
265
264
|
});
|
|
266
265
|
}
|
|
267
266
|
return tools;
|
|
@@ -271,33 +270,38 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
271
270
|
return undefined;
|
|
272
271
|
}
|
|
273
272
|
if (parameters.grammar === 'json') {
|
|
274
|
-
return { type: 'json_object' };
|
|
273
|
+
return { format: { type: 'json_object' } };
|
|
275
274
|
}
|
|
276
275
|
if (parameters.grammar === 'if_else') {
|
|
277
276
|
return {
|
|
278
|
-
|
|
279
|
-
|
|
277
|
+
format: {
|
|
278
|
+
type: 'json_schema',
|
|
279
|
+
strict: true,
|
|
280
280
|
name: 'router_response',
|
|
281
281
|
schema: {
|
|
282
282
|
type: 'object',
|
|
283
283
|
properties: {
|
|
284
|
-
|
|
284
|
+
condition_result: {
|
|
285
285
|
type: 'boolean',
|
|
286
|
+
description: 'Indicates whether a certain condition is met.'
|
|
286
287
|
}
|
|
287
288
|
},
|
|
288
|
-
required: [
|
|
289
|
-
|
|
290
|
-
|
|
289
|
+
required: [
|
|
290
|
+
'condition_result'
|
|
291
|
+
],
|
|
292
|
+
additionalProperties: false
|
|
293
|
+
},
|
|
291
294
|
}
|
|
292
295
|
};
|
|
293
296
|
}
|
|
294
297
|
if (parameters.grammar !== 'default') {
|
|
295
298
|
return {
|
|
296
|
-
|
|
297
|
-
|
|
299
|
+
format: {
|
|
300
|
+
type: 'json_schema',
|
|
301
|
+
strict: true,
|
|
298
302
|
name: 'custom_response',
|
|
299
303
|
schema: parameters.grammar,
|
|
300
|
-
}
|
|
304
|
+
},
|
|
301
305
|
};
|
|
302
306
|
}
|
|
303
307
|
return undefined;
|
|
@@ -14,7 +14,20 @@ export class OpenAISpeechConnector {
|
|
|
14
14
|
instructions,
|
|
15
15
|
response_format: 'pcm',
|
|
16
16
|
});
|
|
17
|
-
|
|
17
|
+
if (!response.body) {
|
|
18
|
+
throw new Error('No response body');
|
|
19
|
+
}
|
|
20
|
+
if (response.body instanceof ReadableStream) {
|
|
21
|
+
return response.body;
|
|
22
|
+
}
|
|
23
|
+
const audio = response.body;
|
|
24
|
+
return new ReadableStream({
|
|
25
|
+
start(controller) {
|
|
26
|
+
audio.on('data', (chunk) => controller.enqueue(chunk));
|
|
27
|
+
audio.on('end', () => controller.close());
|
|
28
|
+
audio.on('error', (err) => controller.error(err));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
18
31
|
}
|
|
19
32
|
getEngineType() {
|
|
20
33
|
return 'openai';
|
|
@@ -9,9 +9,9 @@ export declare class OpenAIGenerativeAIWorkerConnector implements IGenerativeAIW
|
|
|
9
9
|
getEngineType(): GenerativeAIEngineType;
|
|
10
10
|
processJob(parameters: GenerativeAIWorkerConnectorParameters, options?: IGenerativeAIWorkerOptions): Promise<IGenerativeAIWorkerConnectorPromptResult>;
|
|
11
11
|
processJobStream(parameters: GenerativeAIWorkerConnectorParameters, options?: IGenerativeAIWorkerOptions): AsyncGenerator<IGenerativeAIWorkerConnectorPromptResult>;
|
|
12
|
-
private
|
|
13
|
-
private messageReducer;
|
|
12
|
+
private processToolCall;
|
|
14
13
|
private getMessages;
|
|
14
|
+
private getInnerMessages;
|
|
15
15
|
private getTools;
|
|
16
16
|
private getResponseFormat;
|
|
17
17
|
}
|
|
@@ -2,6 +2,6 @@ import { GenerativeAIEngineType, IGenerativeAISpeechConnector } from '@crewdle/w
|
|
|
2
2
|
export declare class OpenAISpeechConnector implements IGenerativeAISpeechConnector {
|
|
3
3
|
private client;
|
|
4
4
|
constructor(apiKey: string);
|
|
5
|
-
speak(model: string, text: string, voice: string, instructions?: string): Promise<
|
|
5
|
+
speak(model: string, text: string, voice: string, instructions?: string): Promise<ReadableStream>;
|
|
6
6
|
getEngineType(): GenerativeAIEngineType;
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewdle/mist-connector-openai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"dist/"
|
|
16
16
|
],
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@crewdle/web-sdk-types": "^1.0.
|
|
18
|
+
"@crewdle/web-sdk-types": "^1.0.46",
|
|
19
19
|
"@types/node": "^22.13.9",
|
|
20
20
|
"typescript": "^5.8.2"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"openai": "^
|
|
23
|
+
"openai": "^5.5.1"
|
|
24
24
|
}
|
|
25
25
|
}
|