@crewdle/mist-connector-openai 1.0.0 → 1.0.2
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.
|
@@ -51,24 +51,148 @@ export class OpenAIGenerativeAIWorkerConnector {
|
|
|
51
51
|
if (!options || !this.models.has(options.model.id)) {
|
|
52
52
|
throw new Error('Model not initialized');
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
54
|
+
let tools;
|
|
55
|
+
if (parameters.functions && parameters.functions.size > 0) {
|
|
56
|
+
tools = [];
|
|
57
|
+
for (const [name, func] of parameters.functions) {
|
|
58
|
+
let params;
|
|
59
|
+
if (func.params) {
|
|
60
|
+
params = {
|
|
61
|
+
type: 'object',
|
|
62
|
+
properties: func.params,
|
|
63
|
+
required: Object.keys(func.params),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
tools.push({
|
|
67
|
+
type: 'function',
|
|
68
|
+
function: {
|
|
69
|
+
name,
|
|
70
|
+
description: func.description,
|
|
71
|
+
parameters: params,
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const messages = this.getMessages(parameters);
|
|
77
|
+
while (true) {
|
|
78
|
+
const stream = await this.client.chat.completions.create({
|
|
79
|
+
model: options.model.id,
|
|
80
|
+
messages,
|
|
81
|
+
max_completion_tokens: parameters.maxTokens,
|
|
82
|
+
temperature: parameters.temperature,
|
|
83
|
+
stream: true,
|
|
84
|
+
stream_options: {
|
|
85
|
+
include_usage: true,
|
|
86
|
+
},
|
|
87
|
+
tools,
|
|
88
|
+
});
|
|
89
|
+
let message = {};
|
|
90
|
+
for await (const chunk of stream) {
|
|
91
|
+
if (chunk.choices[0]?.delta?.tool_calls) {
|
|
92
|
+
message = this.messageReducer(message, chunk);
|
|
93
|
+
}
|
|
94
|
+
yield {
|
|
95
|
+
type: 'prompt',
|
|
96
|
+
output: chunk.choices[0]?.delta?.content ?? '',
|
|
97
|
+
inputTokens: chunk.usage?.prompt_tokens ?? 0,
|
|
98
|
+
outputTokens: chunk.usage?.completion_tokens ?? 0,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (!message.tool_calls) {
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
messages.push({
|
|
105
|
+
role: 'assistant',
|
|
106
|
+
content: null,
|
|
107
|
+
tool_calls: message.tool_calls,
|
|
108
|
+
refusal: null,
|
|
109
|
+
});
|
|
110
|
+
const promises = [];
|
|
111
|
+
for (const toolCall of message.tool_calls) {
|
|
112
|
+
if (toolCall?.function && parameters.functions) {
|
|
113
|
+
try {
|
|
114
|
+
const func = parameters.functions.get(toolCall.function.name);
|
|
115
|
+
if (func) {
|
|
116
|
+
const result = func.callback(JSON.parse(toolCall.function.arguments));
|
|
117
|
+
if (result instanceof Promise) {
|
|
118
|
+
promises.push(result.then((res) => {
|
|
119
|
+
messages.push({
|
|
120
|
+
role: 'tool',
|
|
121
|
+
tool_call_id: toolCall.id,
|
|
122
|
+
content: res ?? 'Tool does not exist',
|
|
123
|
+
});
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
messages.push({
|
|
128
|
+
role: 'tool',
|
|
129
|
+
tool_call_id: toolCall.id,
|
|
130
|
+
content: result ?? 'Tool does not exist',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
messages.push({
|
|
136
|
+
role: 'tool',
|
|
137
|
+
tool_call_id: toolCall.id,
|
|
138
|
+
content: 'Tool does not exist',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error('Error processing tool call', error);
|
|
144
|
+
messages.push({
|
|
145
|
+
role: 'tool',
|
|
146
|
+
tool_call_id: toolCall.id,
|
|
147
|
+
content: 'Error processing tool call',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
await Promise.all(promises);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
messageReducer(previous, item) {
|
|
156
|
+
const reduce = (acc, delta) => {
|
|
157
|
+
acc = { ...acc };
|
|
158
|
+
for (const [key, value] of Object.entries(delta)) {
|
|
159
|
+
if (acc[key] === undefined || acc[key] === null) {
|
|
160
|
+
acc[key] = value;
|
|
161
|
+
// OpenAI.Chat.Completions.ChatCompletionMessageToolCall does not have a key, .index
|
|
162
|
+
if (Array.isArray(acc[key])) {
|
|
163
|
+
for (const arr of acc[key]) {
|
|
164
|
+
delete arr.index;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (typeof acc[key] === 'string' && typeof value === 'string') {
|
|
169
|
+
acc[key] += value;
|
|
170
|
+
}
|
|
171
|
+
else if (typeof acc[key] === 'number' && typeof value === 'number') {
|
|
172
|
+
acc[key] = value;
|
|
173
|
+
}
|
|
174
|
+
else if (Array.isArray(acc[key]) && Array.isArray(value)) {
|
|
175
|
+
const accArray = acc[key];
|
|
176
|
+
for (let i = 0; i < value.length; i++) {
|
|
177
|
+
const { index, ...chunkTool } = value[i];
|
|
178
|
+
if (index - accArray.length > 1) {
|
|
179
|
+
throw new Error(`Error: An array has an empty value when tool_calls are constructed. tool_calls: ${accArray}; tool: ${value}`);
|
|
180
|
+
}
|
|
181
|
+
accArray[index] = reduce(accArray[index], chunkTool);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (typeof acc[key] === 'object' && typeof value === 'object') {
|
|
185
|
+
acc[key] = reduce(acc[key], value);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return acc;
|
|
189
|
+
};
|
|
190
|
+
const choice = item.choices[0];
|
|
191
|
+
if (!choice) {
|
|
192
|
+
// chunk contains information about usage and token counts
|
|
193
|
+
return previous;
|
|
71
194
|
}
|
|
195
|
+
return reduce(previous, choice.delta);
|
|
72
196
|
}
|
|
73
197
|
getMessages(parameters) {
|
|
74
198
|
const messages = [];
|
|
@@ -9,5 +9,6 @@ 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 messageReducer;
|
|
12
13
|
private getMessages;
|
|
13
14
|
}
|
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.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dist/"
|
|
16
16
|
],
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@crewdle/web-sdk-types": "^1.0.
|
|
18
|
+
"@crewdle/web-sdk-types": "^1.0.34",
|
|
19
19
|
"@types/node": "^22.13.9",
|
|
20
20
|
"typescript": "^5.8.2"
|
|
21
21
|
},
|