@cobrowser/chatgpt 0.7.37 → 0.7.39-beta.1

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/index.d.ts CHANGED
@@ -2,3 +2,4 @@ export * from './services/TranslationService/TranslationService';
2
2
  export * from './services/CopilotService/CopilotService';
3
3
  export * from './services/ChatService/ChatService';
4
4
  export * from './services/AssistantService/AssistantService';
5
+ export * from './services/ResponseService/ResponseService';
package/dist/index.js CHANGED
@@ -18,3 +18,4 @@ __exportStar(require("./services/TranslationService/TranslationService"), export
18
18
  __exportStar(require("./services/CopilotService/CopilotService"), exports);
19
19
  __exportStar(require("./services/ChatService/ChatService"), exports);
20
20
  __exportStar(require("./services/AssistantService/AssistantService"), exports);
21
+ __exportStar(require("./services/ResponseService/ResponseService"), exports);
@@ -68,7 +68,10 @@ class AssistantService extends BaseService_1.default {
68
68
  const openai = new openai_1.default({ apiKey: this.openaiApiKey });
69
69
  let run;
70
70
  if (runOptions.functionOutputs && this.runId) {
71
- run = yield openai.beta.threads.runs.submitToolOutputsAndPoll(this.threadId, this.runId, { tool_outputs: JSON.parse(runOptions.functionOutputs) });
71
+ run = yield openai.beta.threads.runs.submitToolOutputsAndPoll(this.runId, {
72
+ thread_id: this.threadId,
73
+ tool_outputs: JSON.parse(runOptions.functionOutputs)
74
+ });
72
75
  }
73
76
  else {
74
77
  const lastThreadMessasges = yield openai.beta.threads.messages.list(this.threadId, { order: "desc", limit: 2 }), isRepeatedMessage = lastThreadMessasges.data.find(msg => msg.content[0].type === 'text' && msg.content[0].text.value === message);
@@ -94,7 +97,7 @@ class AssistantService extends BaseService_1.default {
94
97
  }
95
98
  while (['queued', 'in_progress', 'cancelling'].includes(run.status)) {
96
99
  yield new Promise(resolve => setTimeout(resolve, 500));
97
- run = yield openai.beta.threads.runs.retrieve(run.thread_id, run.id);
100
+ run = yield openai.beta.threads.runs.retrieve(run.id, { thread_id: run.thread_id });
98
101
  }
99
102
  if (run.status === 'completed') {
100
103
  const { data } = yield openai.beta.threads.messages.list(run.thread_id, { order: 'desc', limit: 1 }), messages = data.flatMap((message) => message === null || message === void 0 ? void 0 : message.content.map((content) => ((content.type === 'text' && message.role === 'assistant') ? content.text : ''))), assistantMessages = messages.filter(message => typeof message === 'object' && 'value' in message && typeof message.value === 'string');
@@ -84,10 +84,14 @@ class BaseService {
84
84
  (methodName.startsWith('get') &&
85
85
  !methodName.startsWith('getReply') &&
86
86
  !methodName.startsWith('getAssist') &&
87
- !methodName.startsWith('getChat')) ||
87
+ !methodName.startsWith('getChat') &&
88
+ !methodName.startsWith('getPrompt')) ||
88
89
  methodName.startsWith('handle') ||
89
90
  methodName.includes('Sanitize') ||
90
- methodName.includes('sanitize')) {
91
+ methodName.includes('sanitize') ||
92
+ methodName.includes('createConversation') ||
93
+ methodName.includes('isAssistantIdFormat') ||
94
+ methodName.includes('isPromptIdFormat')) {
91
95
  continue;
92
96
  }
93
97
  const originalMethod = method.bind(this);
@@ -4,6 +4,7 @@ export declare class CopilotService extends BaseService {
4
4
  #private;
5
5
  assistantId: string | undefined;
6
6
  threadId: string | undefined;
7
+ conversationId: string | undefined;
7
8
  constructor(apiKey?: string, model?: string, assistantId?: string, threadId?: string, apiUrl?: string, maxNumberOfChoices?: number);
8
9
  /**
9
10
  * a method to be used to suggest some quick replies for the agent based on the conversation
@@ -30,4 +31,7 @@ export declare class CopilotService extends BaseService {
30
31
  * @param message
31
32
  */
32
33
  getAssistantSuggestions(conversation: string): Promise<ChatGPTResponse | undefined>;
34
+ private isAssistantIdFormat;
35
+ private isPromptIdFormat;
36
+ getPromptSuggestions(message: string): Promise<ChatGPTResponse | undefined>;
33
37
  }
@@ -39,6 +39,12 @@ class CopilotService extends BaseService_1.default {
39
39
  writable: true,
40
40
  value: void 0
41
41
  });
42
+ Object.defineProperty(this, "conversationId", {
43
+ enumerable: true,
44
+ configurable: true,
45
+ writable: true,
46
+ value: void 0
47
+ });
42
48
  this.assistantId = assistantId;
43
49
  this.threadId = threadId;
44
50
  }
@@ -62,7 +68,19 @@ class CopilotService extends BaseService_1.default {
62
68
  }
63
69
  try {
64
70
  if (this.assistantId) {
65
- return yield this.getAssistantSuggestions(conversation);
71
+ // Here we get the last customer message as we dont need the whole conversation
72
+ // as we are doing with the other approach
73
+ const conversationArray = conversation.split('\n');
74
+ const lastCustomerMessage = conversationArray.reverse().find(e => e.includes('customer:'));
75
+ if (!lastCustomerMessage) {
76
+ logger_1.default.error('last customer message not found');
77
+ return Promise.reject(new Error('last customer message not found'));
78
+ }
79
+ // Route based on id shape: asst_* => Assistant API, prompt_* => Responses API
80
+ if (yield this.isAssistantIdFormat(this.assistantId)) {
81
+ return yield this.getAssistantSuggestions(conversation);
82
+ }
83
+ return yield this.getPromptSuggestions(lastCustomerMessage);
66
84
  }
67
85
  return yield this.getChatCompletionSuggestions(conversation);
68
86
  }
@@ -176,7 +194,7 @@ class CopilotService extends BaseService_1.default {
176
194
  let currentRun = run;
177
195
  while (['queued', 'in_progress', 'cancelling'].includes(currentRun.status)) {
178
196
  yield new Promise(resolve => setTimeout(resolve, 500));
179
- currentRun = yield openai.beta.threads.runs.retrieve(currentRun.thread_id, currentRun.id);
197
+ currentRun = yield openai.beta.threads.runs.retrieve(currentRun.id, { thread_id: currentRun.thread_id });
180
198
  }
181
199
  if (currentRun.status === 'completed') {
182
200
  const { data } = yield openai.beta.threads.messages.list(currentRun.thread_id, { order: 'desc', limit: 1 }), messagesData = data.flatMap((message) => message === null || message === void 0 ? void 0 : message.content.map((content) => ((content.type === 'text' && message.role === 'assistant') ? content.text : ''))), assistantMessages = messagesData.filter(message => typeof message === 'object' && 'value' in message && typeof message.value === 'string');
@@ -192,6 +210,67 @@ class CopilotService extends BaseService_1.default {
192
210
  return undefined;
193
211
  });
194
212
  }
213
+ isAssistantIdFormat(id) {
214
+ return !!id && /^asst_[A-Za-z0-9]+$/.test(id);
215
+ }
216
+ isPromptIdFormat(id) {
217
+ return !!id && /^pmpt_[A-Za-z0-9]+$/.test(id);
218
+ }
219
+ getPromptSuggestions(message) {
220
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
221
+ return __awaiter(this, void 0, void 0, function* () {
222
+ const openai = new openai_1.default({ apiKey: this.openaiApiKey });
223
+ let conversationId = this.conversationId;
224
+ if (!conversationId) {
225
+ const conv = yield openai.conversations.create();
226
+ conversationId = conv.id;
227
+ }
228
+ const request = {
229
+ //model: this.chatGptModel || 'gpt-4o-mini',
230
+ input: message,
231
+ store: true,
232
+ conversation: { id: conversationId },
233
+ include: ['file_search_call.results'],
234
+ };
235
+ if (this.assistantId && (yield this.isPromptIdFormat(this.assistantId))) {
236
+ request.prompt = { id: this.assistantId };
237
+ }
238
+ const response = yield openai.responses.create(request);
239
+ response.output.forEach((item, index) => {
240
+ });
241
+ if ((_a = response.conversation) === null || _a === void 0 ? void 0 : _a.id) {
242
+ this.conversationId = response.conversation.id;
243
+ }
244
+ // Sometimes if the prompt needs a file search, the output will be an array of messages
245
+ // which includes multiple messages (some of them are not useful for the user, but the last one is)
246
+ const output = response.output || [];
247
+ const assistantMessages = output.filter((item) => item.type === 'message' && item.role === 'assistant');
248
+ if (assistantMessages.length) {
249
+ const text = assistantMessages.flatMap((m) => { var _a, _b; return ((_b = (_a = m.content) === null || _a === void 0 ? void 0 : _a.filter((c) => c.type === 'output_text')) === null || _b === void 0 ? void 0 : _b.map((c) => c.text)) || []; });
250
+ return {
251
+ data: [text.pop()],
252
+ threadId: this.conversationId,
253
+ usageTokens: {
254
+ prompt_tokens: Number((_c = ((_b = response.usage) === null || _b === void 0 ? void 0 : _b.prompt_tokens)) !== null && _c !== void 0 ? _c : 0),
255
+ completion_tokens: Number((_e = ((_d = response.usage) === null || _d === void 0 ? void 0 : _d.completion_tokens)) !== null && _e !== void 0 ? _e : 0),
256
+ total_tokens: Number((_g = ((_f = response.usage) === null || _f === void 0 ? void 0 : _f.total_tokens)) !== null && _g !== void 0 ? _g : 0),
257
+ },
258
+ };
259
+ }
260
+ if (response.output_text) {
261
+ return {
262
+ data: [response.output_text],
263
+ threadId: this.conversationId,
264
+ usageTokens: {
265
+ prompt_tokens: Number((_j = ((_h = response.usage) === null || _h === void 0 ? void 0 : _h.prompt_tokens)) !== null && _j !== void 0 ? _j : 0),
266
+ completion_tokens: Number((_l = ((_k = response.usage) === null || _k === void 0 ? void 0 : _k.completion_tokens)) !== null && _l !== void 0 ? _l : 0),
267
+ total_tokens: Number((_o = ((_m = response.usage) === null || _m === void 0 ? void 0 : _m.total_tokens)) !== null && _o !== void 0 ? _o : 0),
268
+ },
269
+ };
270
+ }
271
+ return undefined;
272
+ });
273
+ }
195
274
  }
196
275
  exports.CopilotService = CopilotService;
197
276
  _CopilotService_instances = new WeakSet(), _CopilotService_processSuggestions = function _CopilotService_processSuggestions(suggestions) {
@@ -0,0 +1,34 @@
1
+ import ChatGPTResponse from '../../models/ChatGPTResponse';
2
+ import BaseService from '../BaseService/BaseService';
3
+ interface ResponseServiceOptions {
4
+ instructions?: string;
5
+ tools?: any[];
6
+ functionOutputs?: string;
7
+ definedSchema?: any;
8
+ conversationId?: string;
9
+ }
10
+ export declare class ResponseService extends BaseService {
11
+ promptId: string | undefined;
12
+ conversationId: string | undefined;
13
+ lastResponseId: string | undefined;
14
+ constructor(apiKey?: string, promptId?: string, conversationId?: string);
15
+ /**
16
+ * Create a new conversation
17
+ */
18
+ createConversation(): Promise<string>;
19
+ /**
20
+ * Get the reply using the Response API
21
+ *
22
+ * @param message
23
+ * @param runOptions
24
+ */
25
+ getReply(message: string, runOptions?: ResponseServiceOptions): Promise<ChatGPTResponse | undefined>;
26
+ reset(): void;
27
+ getConversationId(): string | undefined;
28
+ getLastResponseId(): string | undefined;
29
+ getPromptId(): string | undefined;
30
+ setPromptId(promptId: string): void;
31
+ setConversationId(conversationId: string): void;
32
+ setLastResponseId(lastResponseId: string): void;
33
+ }
34
+ export {};
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ResponseService = void 0;
16
+ const logger_1 = __importDefault(require("../logger"));
17
+ const openai_1 = __importDefault(require("openai"));
18
+ const BaseService_1 = __importDefault(require("../BaseService/BaseService"));
19
+ class ResponseService extends BaseService_1.default {
20
+ constructor(apiKey, promptId, conversationId) {
21
+ super(apiKey);
22
+ Object.defineProperty(this, "promptId", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ Object.defineProperty(this, "conversationId", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: void 0
33
+ });
34
+ Object.defineProperty(this, "lastResponseId", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: void 0
39
+ });
40
+ this.promptId = promptId;
41
+ this.conversationId = conversationId;
42
+ }
43
+ /**
44
+ * Create a new conversation
45
+ */
46
+ createConversation() {
47
+ return __awaiter(this, void 0, void 0, function* () {
48
+ const openai = new openai_1.default({ apiKey: this.openaiApiKey });
49
+ const conversation = yield openai.conversations.create();
50
+ this.conversationId = conversation.id;
51
+ return this.conversationId;
52
+ });
53
+ }
54
+ /**
55
+ * Get the reply using the Response API
56
+ *
57
+ * @param message
58
+ * @param runOptions
59
+ */
60
+ getReply(message, runOptions = {}) {
61
+ var _a, _b;
62
+ return __awaiter(this, void 0, void 0, function* () {
63
+ if (!this.promptId) {
64
+ logger_1.default.error('Prompt ID is required for Response API');
65
+ return Promise.reject(new Error('Prompt ID is required for Response API'));
66
+ }
67
+ logger_1.default.info(`New response with message: ${message} & options: ${JSON.stringify(runOptions)}`);
68
+ const openai = new openai_1.default({ apiKey: this.openaiApiKey });
69
+ try {
70
+ const responseRequest = {
71
+ store: true,
72
+ };
73
+ // Handle function outputs
74
+ if (runOptions.functionOutputs) {
75
+ const toolOutputs = JSON.parse(runOptions.functionOutputs);
76
+ const formattedInputs = toolOutputs.map((output) => ({
77
+ type: 'function_call_output',
78
+ call_id: output.call_id,
79
+ output: output.output
80
+ }));
81
+ responseRequest.input = formattedInputs;
82
+ const conversationIdToUse = runOptions.conversationId || this.conversationId;
83
+ if (!conversationIdToUse) {
84
+ const createdId = yield this.createConversation();
85
+ this.conversationId = createdId;
86
+ }
87
+ responseRequest.conversation = runOptions.conversationId || this.conversationId;
88
+ }
89
+ else {
90
+ // Handle regular message
91
+ if (!runOptions.conversationId && !this.conversationId) {
92
+ const createdId = yield this.createConversation();
93
+ this.conversationId = createdId;
94
+ }
95
+ responseRequest.input = message;
96
+ responseRequest.include = ['file_search_call.results'];
97
+ if (runOptions.instructions) {
98
+ responseRequest.instructions = runOptions.instructions;
99
+ }
100
+ const conversationIdToUse = runOptions.conversationId || this.conversationId;
101
+ if (conversationIdToUse) {
102
+ responseRequest.conversation = conversationIdToUse;
103
+ }
104
+ if ((_a = runOptions.tools) === null || _a === void 0 ? void 0 : _a.length) {
105
+ responseRequest.tools = runOptions.tools;
106
+ }
107
+ if (runOptions.definedSchema) {
108
+ responseRequest.text = {
109
+ format: runOptions.definedSchema
110
+ };
111
+ }
112
+ }
113
+ if (this.promptId) {
114
+ responseRequest.prompt = {
115
+ id: this.promptId
116
+ };
117
+ }
118
+ const response = yield openai.responses.create(responseRequest);
119
+ this.lastResponseId = response.id;
120
+ if ((_b = response.conversation) === null || _b === void 0 ? void 0 : _b.id) {
121
+ this.conversationId = response.conversation.id;
122
+ }
123
+ else if (runOptions.conversationId) {
124
+ this.conversationId = runOptions.conversationId;
125
+ }
126
+ // Process response output
127
+ const output = response.output || [];
128
+ const assistantMessages = output.filter((item) => item.type === 'message' && item.role === 'assistant');
129
+ const functionCalls = output.filter((item) => item.type === 'function_call');
130
+ if (functionCalls.length > 0) {
131
+ return {
132
+ requiredActions: JSON.stringify(functionCalls),
133
+ threadId: this.conversationId,
134
+ usageTokens: response.usage,
135
+ };
136
+ }
137
+ if (assistantMessages.length > 0) {
138
+ const textContent = assistantMessages
139
+ .flatMap((msg) => msg.content || [])
140
+ .filter((content) => content.type === 'output_text' || content.type === 'text')
141
+ .map((content) => content.text || content.value)
142
+ .filter((text) => text);
143
+ if (textContent.length > 0) {
144
+ return {
145
+ data: textContent.pop(),
146
+ threadId: this.conversationId,
147
+ usageTokens: response.usage,
148
+ };
149
+ }
150
+ }
151
+ if (response.output_text) {
152
+ return {
153
+ data: response.output_text,
154
+ threadId: this.conversationId,
155
+ usageTokens: response.usage,
156
+ };
157
+ }
158
+ return {
159
+ data: undefined,
160
+ threadId: this.conversationId,
161
+ usageTokens: response.usage,
162
+ };
163
+ }
164
+ catch (error) {
165
+ logger_1.default.error('Error in ResponseService.getReply:', error);
166
+ return Promise.reject(error);
167
+ }
168
+ });
169
+ }
170
+ reset() {
171
+ this.lastResponseId = undefined;
172
+ this.conversationId = undefined;
173
+ }
174
+ getConversationId() {
175
+ return this.conversationId;
176
+ }
177
+ getLastResponseId() {
178
+ return this.lastResponseId;
179
+ }
180
+ getPromptId() {
181
+ return this.promptId;
182
+ }
183
+ setPromptId(promptId) {
184
+ this.promptId = promptId;
185
+ }
186
+ setConversationId(conversationId) {
187
+ this.conversationId = conversationId;
188
+ }
189
+ setLastResponseId(lastResponseId) {
190
+ this.lastResponseId = lastResponseId;
191
+ }
192
+ }
193
+ exports.ResponseService = ResponseService;
@@ -36,7 +36,7 @@ class TranslationService extends BaseService_1.default {
36
36
  return Promise.reject(new Error('Text must be provided'));
37
37
  }
38
38
  const translateText = `
39
- Translate the following text from ${fromLanguage} to ${toLanguage} if it's not already in ${toLanguage}: ${text}.
39
+ Translate the following text to ${toLanguage} if it's not already in ${toLanguage}: ${text}.
40
40
  `;
41
41
  const requestBody = {
42
42
  model: this.chatGPTModel,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cobrowser/chatgpt",
3
- "version": "0.7.37",
3
+ "version": "0.7.39-beta.1",
4
4
  "description": "chatgpt services to connect our projects with chatgpt api",
5
5
  "keywords": [
6
6
  "chatgpt",
@@ -25,7 +25,7 @@
25
25
  "@cobrowser/xss-validation": "^2.0.1",
26
26
  "axios": "^1.6.1",
27
27
  "axios-mock-adapter": "^1.22.0",
28
- "openai": "^4.86.2"
28
+ "openai": "^6.3.0"
29
29
  },
30
30
  "directories": {
31
31
  "dist": "dist"
@@ -40,5 +40,5 @@
40
40
  "bugs": {
41
41
  "url": "https://bitbucket.org/cobrowser/cb_utils/issues"
42
42
  },
43
- "gitHead": "b72f8b0bd24f523172f83cb4bc833ad605684565"
43
+ "gitHead": "d3086da041359550490fc14c143a3fc79ee7603e"
44
44
  }