@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
- const stream = await this.client.chat.completions.create({
55
- model: options.model.id,
56
- messages: this.getMessages(parameters),
57
- max_completion_tokens: parameters.maxTokens,
58
- temperature: parameters.temperature,
59
- stream: true,
60
- stream_options: {
61
- include_usage: true,
62
- },
63
- });
64
- for await (const chunk of stream) {
65
- yield {
66
- type: 'prompt',
67
- output: chunk.choices[0].delta.content ?? '',
68
- inputTokens: chunk.usage?.prompt_tokens ?? 0,
69
- outputTokens: chunk.usage?.completion_tokens ?? 0,
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.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.33",
18
+ "@crewdle/web-sdk-types": "^1.0.34",
19
19
  "@types/node": "^22.13.9",
20
20
  "typescript": "^5.8.2"
21
21
  },