@futdevpro/nts-dynamo 1.11.26 → 1.11.27

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.
Files changed (68) hide show
  1. package/build/_modules/discord-assistant/_collections/dias-global-settings.const.js +1 -1
  2. package/build/_modules/discord-assistant/_collections/dias-global-settings.const.js.map +1 -1
  3. package/build/_modules/discord-assistant/_collections/dias.util.d.ts +1 -0
  4. package/build/_modules/discord-assistant/_collections/dias.util.d.ts.map +1 -1
  5. package/build/_modules/discord-assistant/_collections/dias.util.js +1 -0
  6. package/build/_modules/discord-assistant/_collections/dias.util.js.map +1 -1
  7. package/build/_modules/discord-assistant/_models/dias-global-settings.interface.d.ts +1 -1
  8. package/build/_modules/discord-assistant/_services/dias-io.control-service.d.ts.map +1 -1
  9. package/build/_modules/discord-assistant/_services/dias-io.control-service.js +4 -2
  10. package/build/_modules/discord-assistant/_services/dias-io.control-service.js.map +1 -1
  11. package/build/_modules/discord-assistant/_services/dias-main.control-service.d.ts +0 -3
  12. package/build/_modules/discord-assistant/_services/dias-main.control-service.d.ts.map +1 -1
  13. package/build/_modules/discord-assistant/_services/dias.service-base.d.ts +6 -2
  14. package/build/_modules/discord-assistant/_services/dias.service-base.d.ts.map +1 -1
  15. package/build/_modules/discord-assistant/_services/dias.service-base.js +6 -4
  16. package/build/_modules/discord-assistant/_services/dias.service-base.js.map +1 -1
  17. package/build/_modules/discord-bot/_collections/dibo-global-settings.conts.js +1 -1
  18. package/build/_modules/discord-bot/_collections/dibo-global-settings.conts.js.map +1 -1
  19. package/build/_modules/discord-bot/_collections/dibo-operations.util.js +10 -10
  20. package/build/_modules/discord-bot/_collections/dibo-operations.util.js.map +1 -1
  21. package/build/_modules/discord-bot/_services/dibo-commands.control-service.d.ts +1 -1
  22. package/build/_modules/discord-bot/_services/dibo-commands.control-service.d.ts.map +1 -1
  23. package/build/_modules/discord-bot/_services/dibo-commands.control-service.js +3 -3
  24. package/build/_modules/discord-bot/_services/dibo-commands.control-service.js.map +1 -1
  25. package/build/_modules/discord-bot/_services/dibo-io.control-service.d.ts +1 -0
  26. package/build/_modules/discord-bot/_services/dibo-io.control-service.d.ts.map +1 -1
  27. package/build/_modules/discord-bot/_services/dibo-io.control-service.js +3 -2
  28. package/build/_modules/discord-bot/_services/dibo-io.control-service.js.map +1 -1
  29. package/build/_modules/discord-bot/_services/dibo-main.control-service.d.ts.map +1 -1
  30. package/build/_modules/discord-bot/_services/dibo-main.control-service.js +25 -0
  31. package/build/_modules/discord-bot/_services/dibo-main.control-service.js.map +1 -1
  32. package/build/_modules/mock/socket-server.mock.d.ts +4 -0
  33. package/build/_modules/mock/socket-server.mock.d.ts.map +1 -1
  34. package/build/_modules/mock/socket-server.mock.js +11 -1
  35. package/build/_modules/mock/socket-server.mock.js.map +1 -1
  36. package/build/_modules/mock/socket-server.mock.spec.js +1 -1
  37. package/build/_modules/mock/socket-server.mock.spec.js.map +1 -1
  38. package/build/_modules/open-ai/_services/oai-llm-chat.service-base.d.ts +16 -141
  39. package/build/_modules/open-ai/_services/oai-llm-chat.service-base.d.ts.map +1 -1
  40. package/build/_modules/open-ai/_services/oai-llm-chat.service-base.js +9 -6
  41. package/build/_modules/open-ai/_services/oai-llm-chat.service-base.js.map +1 -1
  42. package/build/_modules/open-ai/_services/oai-llm.service-base.d.ts +1 -22
  43. package/build/_modules/open-ai/_services/oai-llm.service-base.d.ts.map +1 -1
  44. package/build/_modules/open-ai/_services/oai-llm.service-base.js +28 -75
  45. package/build/_modules/open-ai/_services/oai-llm.service-base.js.map +1 -1
  46. package/build/_modules/socket/_services/socket-server.service.d.ts.map +1 -1
  47. package/build/_modules/socket/_services/socket-server.service.js +12 -3
  48. package/build/_modules/socket/_services/socket-server.service.js.map +1 -1
  49. package/build/_modules/socket/app-extended.server.spec.js +44 -7
  50. package/build/_modules/socket/app-extended.server.spec.js.map +1 -1
  51. package/package.json +3 -3
  52. package/src/_modules/discord-assistant/_collections/dias-global-settings.const.ts +1 -1
  53. package/src/_modules/discord-assistant/_collections/dias.util.ts +3 -1
  54. package/src/_modules/discord-assistant/_models/dias-global-settings.interface.ts +1 -1
  55. package/src/_modules/discord-assistant/_services/dias-io.control-service.ts +4 -2
  56. package/src/_modules/discord-assistant/_services/dias-main.control-service.ts +2 -2
  57. package/src/_modules/discord-assistant/_services/dias.service-base.ts +13 -6
  58. package/src/_modules/discord-bot/_collections/dibo-global-settings.conts.ts +1 -1
  59. package/src/_modules/discord-bot/_collections/dibo-operations.util.ts +10 -10
  60. package/src/_modules/discord-bot/_services/dibo-commands.control-service.ts +3 -3
  61. package/src/_modules/discord-bot/_services/dibo-io.control-service.ts +4 -2
  62. package/src/_modules/discord-bot/_services/dibo-main.control-service.ts +21 -0
  63. package/src/_modules/mock/socket-server.mock.spec.ts +1 -1
  64. package/src/_modules/mock/socket-server.mock.ts +13 -3
  65. package/src/_modules/open-ai/_services/oai-llm-chat.service-base.ts +28 -23
  66. package/src/_modules/open-ai/_services/oai-llm.service-base.ts +31 -96
  67. package/src/_modules/socket/_services/socket-server.service.ts +15 -6
  68. package/src/_modules/socket/app-extended.server.spec.ts +50 -18
@@ -9,8 +9,8 @@ import { DyNTS_global_settings } from '../../..';
9
9
 
10
10
  export abstract class DyNTS_DiAs_Main_ControlService extends DyNTS_DiAs_ServiceBase {
11
11
 
12
- protected abstract override botIO_CS: DyNTS_DiAs_IO_ControlService;
13
- protected abstract override getBotIOControlService(): DyNTS_DiAs_IO_ControlService;
12
+ /* protected abstract override botIO_CS: DyNTS_DiAs_IO_ControlService;
13
+ protected abstract override getBotIOControlService(): DyNTS_DiAs_IO_ControlService; */
14
14
 
15
15
  /* override async start(issuer: string): Promise<void> {
16
16
  try {
@@ -8,6 +8,7 @@ import { DyNTS_global_settings } from '../../../_collections/global-settings.con
8
8
  import { DyNTS_OAI_GPT_Message } from '../../open-ai/_models/interfaces/oai-gpt-message.interface';
9
9
  import { DyNTS_OAI_GPT_Message_Role } from '../../open-ai/_enums/oai-gpt-message-role.enum';
10
10
  import { DyNTS_DiAs_Util } from '../_collections/dias.util';
11
+ import { DyNTS_DiAs_IO_ControlService } from './dias-io.control-service';
11
12
 
12
13
 
13
14
  export abstract class DyNTS_DiAs_ServiceBase extends DyNTS_DiBo_Main_ControlService {
@@ -17,10 +18,15 @@ export abstract class DyNTS_DiAs_ServiceBase extends DyNTS_DiBo_Main_ControlServ
17
18
  }
18
19
  readonly llmChat_CS: DyNTS_OAI_LLMChat_ServiceBase = this.getLLMChatControlService();
19
20
 
21
+ protected abstract override botIO_CS: DyNTS_DiAs_IO_ControlService;
22
+ protected abstract override getBotIOControlService(): DyNTS_DiAs_IO_ControlService;
23
+
20
24
  defaultSystemPrompt: string = DyNTS_DiAs_global_settings.defaultSystemPrompt;
21
25
 
22
- protected constructor() {
23
- super();
26
+ protected constructor(
27
+ dontSetupAutomatically?: boolean,
28
+ ) {
29
+ super(dontSetupAutomatically);
24
30
 
25
31
  DyNTS_global_settings.dias_settings ??= DyNTS_DiAs_global_settings;
26
32
 
@@ -28,9 +34,10 @@ export abstract class DyNTS_DiAs_ServiceBase extends DyNTS_DiBo_Main_ControlServ
28
34
  }
29
35
 
30
36
  async gatherDiscordMessagesForMessage(message: Message, limit: number = 100): Promise<Message[]> {
31
- const channel = message.channel;
32
- const userId = message.author.id;
37
+ return this.gatherDiscordMessagesForChannel(message.channel as TextChannel, message.author.id, limit);
38
+ }
33
39
 
40
+ async gatherDiscordMessagesForChannel(channel: TextChannel, userId: string, limit: number = 100): Promise<Message[]> {
34
41
  const messages: Message[] = await channel.messages.fetch({ limit: limit }).then(
35
42
  messages => messages.filter(
36
43
  msg => !DyNTS_DiAs_global_settings.skipConversationMessagesFlags.some(
@@ -54,13 +61,13 @@ export abstract class DyNTS_DiAs_ServiceBase extends DyNTS_DiBo_Main_ControlServ
54
61
  message: Message,
55
62
  issuer: string,
56
63
  ): Promise<DyNTS_OAI_GPT_Message[]> {
57
-
58
- const messages = await this.gatherDiscordMessagesForMessage(message);
64
+ const messages: Message[] = await this.gatherDiscordMessagesForMessage(message);
59
65
 
60
66
  return DyNTS_DiAs_Util.convertDiscordMessagesToOAIConversation({
61
67
  messages: messages,
62
68
  botClientId: this.botClientId,
63
69
  botDisplayName: this.botDisplayName,
70
+ issuer: issuer,
64
71
  });
65
72
  }
66
73
  }
@@ -36,7 +36,7 @@ export const DyNTS_DiBo_global_settings: DyNTS_DiBo_Global_Settings = {
36
36
  },
37
37
 
38
38
  channelSettings: {
39
- reportChannelName: 'bot-report',
39
+ reportChannelName: 'bot-reports',
40
40
 
41
41
  defaultChannels: [
42
42
  'bot-help',
@@ -19,7 +19,7 @@ export class DyNTS_DiBo_Operations_Util {
19
19
  )
20
20
 
21
21
  if (!channel) {
22
- DyFM_Log.error('No text channel found')
22
+ DyFM_Log.error(`No text channel found with name "${name}"`)
23
23
  return
24
24
  }
25
25
 
@@ -30,7 +30,7 @@ export class DyNTS_DiBo_Operations_Util {
30
30
  const channel = this.findChannelByName(channels, name)
31
31
 
32
32
  if (!channel.isTextBased()) {
33
- throw new Error('Channel is not text based')
33
+ throw new Error(`Channel is not text based with name "${name}"`)
34
34
  }
35
35
 
36
36
  return channel as TextChannel
@@ -40,7 +40,7 @@ export class DyNTS_DiBo_Operations_Util {
40
40
  const channel = this.findChannelByName(channels, name)
41
41
 
42
42
  if (!channel.isVoiceBased()) {
43
- throw new Error('Channel is not voice based')
43
+ throw new Error(`Channel is not voice based with name "${name}"`)
44
44
  }
45
45
 
46
46
  return channel as VoiceChannel
@@ -55,7 +55,7 @@ export class DyNTS_DiBo_Operations_Util {
55
55
  const reportMessage = `${client.user?.username} report for duty! ` +
56
56
  `(v${DyNTS_global_settings.systemVersion} ${DyNTS_global_settings.env_settings?.environment})`;
57
57
 
58
- if (lastReportMessage.content === reportMessage) {
58
+ if (lastReportMessage?.content === reportMessage) {
59
59
  await this.deleteMessage(lastReportMessage).catch((error) => {
60
60
  DyFM_Log.error('Failed to delete message', error);
61
61
  });
@@ -78,7 +78,7 @@ export class DyNTS_DiBo_Operations_Util {
78
78
  channel.send(message)
79
79
  DyFM_Log.success('Message sent to channel', channel.name)
80
80
  } else {
81
- DyFM_Log.error('Channel is not text based')
81
+ DyFM_Log.error(`Channel is not text based "${channelName}"`)
82
82
  }
83
83
  }
84
84
 
@@ -140,7 +140,7 @@ export class DyNTS_DiBo_Operations_Util {
140
140
  const channel = this.findChannelByName(guild.channels, channelName)
141
141
 
142
142
  if (!channel?.isTextBased()) {
143
- DyFM_Log.error('Channel is not text based')
143
+ DyFM_Log.error(`Channel is not text based "${channelName}"`)
144
144
  return
145
145
  }
146
146
 
@@ -232,7 +232,7 @@ export class DyNTS_DiBo_Operations_Util {
232
232
  const channel = this.findChannelByName(guild.channels, channelName)
233
233
 
234
234
  if (!channel?.isTextBased()) {
235
- DyFM_Log.error('Channel is not text based')
235
+ DyFM_Log.error(`Channel is not text based "${channelName}"`)
236
236
  return []
237
237
  }
238
238
 
@@ -331,7 +331,7 @@ export class DyNTS_DiBo_Operations_Util {
331
331
  const channel = this.findChannelByName(guild.channels, channelName)
332
332
 
333
333
  if (!channel?.isTextBased()) {
334
- DyFM_Log.error('Channel is not text based')
334
+ DyFM_Log.error(`Channel is not text based with name "${channelName}"`)
335
335
  return
336
336
  }
337
337
 
@@ -347,7 +347,7 @@ export class DyNTS_DiBo_Operations_Util {
347
347
  const channel = this.findChannelByName(guild.channels, channelName)
348
348
 
349
349
  if (!channel?.isTextBased()) {
350
- DyFM_Log.error('Channel is not text based')
350
+ DyFM_Log.error(`Channel is not text based with name "${channelName}"`)
351
351
  return
352
352
  }
353
353
 
@@ -369,6 +369,6 @@ export class DyNTS_DiBo_Operations_Util {
369
369
  DyFM_Log.error('Failed to delete message', error);
370
370
  });
371
371
 
372
- DyFM_Log.success('Message deleted', message.id);
372
+ DyFM_Log.success('Message deleted:', message.content);
373
373
  }
374
374
  }
@@ -16,11 +16,11 @@ export abstract class DyNTS_DiBo_Commands_ControlService extends DyNTS_Singleton
16
16
  }
17
17
 
18
18
  protected abstract getMainDiscordBotControlService(): DyNTS_DiBo_Main_ControlService;
19
- protected readonly mainDiscordBot_CS: DyNTS_DiBo_Main_ControlService =
19
+ protected readonly diAs_CS: DyNTS_DiBo_Main_ControlService =
20
20
  this.getMainDiscordBotControlService();
21
21
 
22
22
  get discordServer(): Guild {
23
- return this.mainDiscordBot_CS?.discordServer;
23
+ return this.diAs_CS?.discordServer;
24
24
  }
25
25
 
26
26
  protected constructor() {
@@ -45,7 +45,7 @@ export abstract class DyNTS_DiBo_Commands_ControlService extends DyNTS_Singleton
45
45
  try {
46
46
  let haveCommandOperator = false;
47
47
  let msg = message.content.replace(
48
- `<@${this.mainDiscordBot_CS.client.user.id}>`, ''
48
+ `<@${this.diAs_CS.client.user.id}>`, ''
49
49
  ).trim();
50
50
 
51
51
  if (!DyNTS_DiBo_global_settings.commandSettings.commandOperator) {
@@ -32,6 +32,8 @@ export abstract class DyNTS_DiBo_IO_ControlService extends DyNTS_SingletonServic
32
32
  protected abstract getCommandsControlService(): DyNTS_DiBo_Commands_ControlService;
33
33
  protected commands_CS: DyNTS_DiBo_Commands_ControlService;
34
34
 
35
+ dontSendErrorReply?: boolean;
36
+
35
37
  /* protected constructor() {
36
38
  super();
37
39
  } */
@@ -86,9 +88,9 @@ export abstract class DyNTS_DiBo_IO_ControlService extends DyNTS_SingletonServic
86
88
  } catch (error) {
87
89
  DyFM_Error.logSimple('❌❌ Error handleNewMessage:', error);
88
90
 
89
- if (DyNTS_DiBo_global_settings.debugLevel >= 1) {
91
+ if (!this.dontSendErrorReply && DyNTS_DiBo_global_settings.debugLevel >= 1) {
90
92
  await message.reply(
91
- `[SYSTEM|ERROR] Error occurred while handling the message:\n` +
93
+ `[SYSTEM|ERROR|${DyNTS_global_settings.systemShortCodeName}|DyNTS-DiBo-IO-H0] Error occurred while handling the message:\n` +
92
94
  DyFM_Error.getAnyMessage(error)
93
95
  ).catch(error => {
94
96
  DyFM_Error.logSimple('❌❌ Error sending message to report channel:', error);
@@ -102,6 +102,7 @@ export abstract class DyNTS_DiBo_Main_ControlService extends DyNTS_SingletonServ
102
102
  intents: DyNTS_global_settings.bot_settings.intents,
103
103
  partials: DyNTS_global_settings.bot_settings.partials,
104
104
  })
105
+ DyFM_Log.success('Discord client initialized');
105
106
 
106
107
  if (!dontSetupAutomatically) {
107
108
  this.setup('system-init');
@@ -172,6 +173,11 @@ export abstract class DyNTS_DiBo_Main_ControlService extends DyNTS_SingletonServ
172
173
  DyNTS_GlobalService.globalErrorHandler(error);
173
174
  reject(error);
174
175
  });
176
+ if (this.debugLog) {
177
+ DyFM_Log.info('Error event registered\n\n', new Error().stack);
178
+ } else {
179
+ DyFM_Log.info('Error event registered');
180
+ }
175
181
 
176
182
  this.client.on('ready', async () => {
177
183
  if (DyNTS_DiBo_global_settings.debugLevel >= 1) {
@@ -193,6 +199,11 @@ export abstract class DyNTS_DiBo_Main_ControlService extends DyNTS_SingletonServ
193
199
  DyFM_Log.success('Discord Bot setup complete')
194
200
  resolve();
195
201
  });
202
+ if (this.debugLog) {
203
+ DyFM_Log.info('Ready event registered\n\n', new Error().stack);
204
+ } else {
205
+ DyFM_Log.info('Ready event registered');
206
+ }
196
207
 
197
208
  this.client.on('messageCreate', (message: Message) => {
198
209
  try {
@@ -201,6 +212,11 @@ export abstract class DyNTS_DiBo_Main_ControlService extends DyNTS_SingletonServ
201
212
  DyFM_Log.error('Error handling new message:', error);
202
213
  }
203
214
  });
215
+ if (this.debugLog) {
216
+ DyFM_Log.info('Message create event registered\n\n', new Error().stack);
217
+ } else {
218
+ DyFM_Log.info('Message create event registered');
219
+ }
204
220
 
205
221
  process.on('exit', () => {
206
222
  try {
@@ -214,6 +230,11 @@ export abstract class DyNTS_DiBo_Main_ControlService extends DyNTS_SingletonServ
214
230
  DyFM_Log.error('Error sending message to report channel:', error);
215
231
  }
216
232
  });
233
+ if (this.debugLog) {
234
+ DyFM_Log.info('Exit event registered\n\n', new Error().stack);
235
+ } else {
236
+ DyFM_Log.info('Exit event registered');
237
+ }
217
238
 
218
239
  this.client.login(DyNTS_global_settings.env_settings.discord.token).catch((error) => {
219
240
  reject(error);
@@ -20,7 +20,7 @@ describe('| DyNTS_SocketServer_Mock', () => {
20
20
 
21
21
  expect(params).toBeInstanceOf(DyNTS_SocketServerService_Params);
22
22
  expect(params.name).toBe('test');
23
- expect(params.port).toBe(9393);
23
+ expect(params.port).toBe(19393); // Updated from 9393 to 19393
24
24
  });
25
25
 
26
26
  it('| should return an empty array for incoming events', () => {
@@ -1,5 +1,6 @@
1
1
  import { DyFM_SocketEvent } from '@futdevpro/fsm-dynamo/socket';
2
2
  import { Socket } from 'socket.io';
3
+ import * as net from 'net';
3
4
 
4
5
  import {
5
6
  DyNTS_SocketPresence
@@ -9,8 +10,17 @@ import {
9
10
  } from '../socket/_models/socket-server-service-params.control-model';
10
11
  import { DyNTS_SocketServerService } from '../socket/_services/socket-server.service';
11
12
 
12
-
13
-
13
+ /**
14
+ * Utility function to find an available port starting from a base port
15
+ */
16
+ const findAvailablePort = (basePort: number): number => {
17
+ return basePort; // For now, return the base port, but this could be enhanced
18
+ };
19
+
20
+ /**
21
+ * Mock Socket Server Service for testing purposes
22
+ * Uses a non-privileged port to avoid EACCES errors on Windows
23
+ */
14
24
  export class DyNTS_SocketServer_Mock extends
15
25
  DyNTS_SocketServerService<DyNTS_SocketPresence> {
16
26
 
@@ -21,7 +31,7 @@ export class DyNTS_SocketServer_Mock extends
21
31
  getServiceParams(): DyNTS_SocketServerService_Params<any> {
22
32
  return new DyNTS_SocketServerService_Params({
23
33
  name: 'test',
24
- port: 9393,
34
+ port: findAvailablePort(19393), // Changed from 9393 to 19393 (non-privileged port)
25
35
  });
26
36
  }
27
37
 
@@ -1,7 +1,7 @@
1
1
  import { OpenAI } from 'openai';
2
2
 
3
3
  import { DyFM_OpenAI_Settings, DyFM_OpenAIModel, DyFM_GPTCall_Settings } from '@futdevpro/fsm-dynamo/open-ai';
4
- import { DyFM_AnyError, DyFM_clone, DyFM_Error, DyFM_Error_Settings, DyFM_Log, DyFM_notNull } from '@futdevpro/fsm-dynamo';
4
+ import { DyFM_AnyError, DyFM_clone, DyFM_Error, DyFM_Error_Settings, DyFM_getLocalStackLocation, DyFM_Log, DyFM_notNull, DyFM_Shared } from '@futdevpro/fsm-dynamo';
5
5
 
6
6
  import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
7
7
  import { DyNTS_OAI_GPT_Message } from '../_models/interfaces/oai-gpt-message.interface';
@@ -9,7 +9,7 @@ import { ChatCompletion } from 'openai/resources';
9
9
  import { ChatCompletionCreateParamsBase, ChatCompletionMessageParam } from 'openai/resources/chat/completions';
10
10
  import { DyNTS_OAI_GPT_Message_Role } from '../_enums/oai-gpt-message-role.enum';
11
11
  import { DyNTS_OAI_LLM_Predefined_Requests } from '../_models/interfaces/oai-llm-predefined-requests.interface';
12
- import { DyFM_safeParseJSON, DyFM_safeParseList, DyNTS_OAI_LLM_ServiceBase } from './oai-llm.service-base';
12
+ import { DyNTS_OAI_LLM_ServiceBase } from './oai-llm.service-base';
13
13
  import { DyNTS_OAI_global_settings } from '../_collections/oai-global-settings.const';
14
14
 
15
15
 
@@ -50,7 +50,7 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
50
50
 
51
51
  return answer.toUpperCase().includes(this.predefinedRequests.yesNo.upperCaseYes);
52
52
  }
53
- askYesNoQuestionInConversation = this.yesNoQuestionInConversation;
53
+ askYesNoQuestionInConversation: typeof this.yesNoQuestionInConversation = this.yesNoQuestionInConversation;
54
54
 
55
55
  /**
56
56
  * Asks the AI to answer a simple question
@@ -72,7 +72,7 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
72
72
 
73
73
  return await this.getQuestionAnswerInConversation(set);
74
74
  }
75
- askSimpleQuestionInConversation = this.simpleQuestionInConversation;
75
+ askSimpleQuestionInConversation: typeof this.simpleQuestionInConversation = this.simpleQuestionInConversation;
76
76
 
77
77
  /**
78
78
  * Asks the AI to answer a percentage question
@@ -107,7 +107,7 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
107
107
 
108
108
  return +answer;
109
109
  }
110
- askPercentageQuestionInConversation = this.percentageQuestionInConversation;
110
+ askPercentageQuestionInConversation: typeof this.percentageQuestionInConversation = this.percentageQuestionInConversation;
111
111
 
112
112
 
113
113
  /**
@@ -146,7 +146,7 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
146
146
 
147
147
  return null;
148
148
  }
149
- askSelectQuestionInConversation = this.selectQuestionInConversation;
149
+ askSelectQuestionInConversation: typeof this.selectQuestionInConversation = this.selectQuestionInConversation;
150
150
 
151
151
  /**
152
152
  * Asks the AI to select one of the options from the list
@@ -177,9 +177,9 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
177
177
 
178
178
  const answer = await this.getQuestionAnswerInConversation(set);
179
179
 
180
- return DyFM_safeParseJSON<T>(answer);
180
+ return DyFM_Shared.safeParseJSON<T>(answer);
181
181
  }
182
- askRequestSelectInConversation = this.requestSelectInConversation;
182
+ askRequestSelectInConversation: typeof this.requestSelectInConversation = this.requestSelectInConversation;
183
183
 
184
184
  /**
185
185
  * Asks the AI to select one or more of the options from the list
@@ -218,7 +218,7 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
218
218
 
219
219
  return result;
220
220
  }
221
- askMultipleSelectQuestionWithOptionsInConversation = this.multipleSelectQuestionWithOptionsInConversation;
221
+ askMultipleSelectQuestionWithOptionsInConversation: typeof this.multipleSelectQuestionWithOptionsInConversation = this.multipleSelectQuestionWithOptionsInConversation;
222
222
 
223
223
  /**
224
224
  * Asks the AI to select one or more of the options from the list
@@ -249,9 +249,9 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
249
249
 
250
250
  const answer = await this.getQuestionAnswerInConversation(set);
251
251
 
252
- return DyFM_safeParseList<T[]>(answer);
252
+ return DyFM_Shared.safeParseList<T[]>(answer);
253
253
  }
254
- askRequestMultipleSelectInConversation = this.requestMultipleSelectInConversation;
254
+ askRequestMultipleSelectInConversation: typeof this.requestMultipleSelectInConversation = this.requestMultipleSelectInConversation;
255
255
 
256
256
  /**
257
257
  * Asks the AI to answer a question that must result a JSON object
@@ -279,9 +279,9 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
279
279
 
280
280
  const answer = await this.getQuestionAnswerInConversation(set);
281
281
 
282
- return DyFM_safeParseJSON<T>(answer);
282
+ return DyFM_Shared.safeParseJSON<T>(answer);
283
283
  }
284
- askJsonQuestionInConversation = this.jsonQuestionInConversation;
284
+ askJsonQuestionInConversation: typeof this.jsonQuestionInConversation = this.jsonQuestionInConversation;
285
285
 
286
286
  /**
287
287
  * Asks the AI to answer a question that must result a JSON object with specific key descriptions
@@ -314,9 +314,9 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
314
314
 
315
315
  const answer = await this.getQuestionAnswerInConversation(set);
316
316
 
317
- return DyFM_safeParseJSON<T>(answer);
317
+ return DyFM_Shared.safeParseJSON<T>(answer);
318
318
  }
319
- askJsonQuestionWithKeysDescriptionInConversation = this.jsonQuestionWithKeysDescriptionInConversation;
319
+ askJsonQuestionWithKeysDescriptionInConversation: typeof this.jsonQuestionWithKeysDescriptionInConversation = this.jsonQuestionWithKeysDescriptionInConversation;
320
320
 
321
321
  /**
322
322
  * Asks the AI to answer a question that must result a JSON object with specific keys
@@ -349,9 +349,9 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
349
349
 
350
350
  const answer = await this.getQuestionAnswerInConversation(set);
351
351
 
352
- return DyFM_safeParseJSON<T>(answer);
352
+ return DyFM_Shared.safeParseJSON<T>(answer);
353
353
  }
354
- askJsonQuestionWithExactKeysInConversation = this.jsonQuestionWithExactKeysInConversation;
354
+ askJsonQuestionWithExactKeysInConversation: typeof this.jsonQuestionWithExactKeysInConversation = this.jsonQuestionWithExactKeysInConversation;
355
355
 
356
356
  /**
357
357
  * Asks the AI to answer a question that must result a list of strings
@@ -379,9 +379,9 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
379
379
 
380
380
  const answer = await this.getQuestionAnswerInConversation(set);
381
381
 
382
- return DyFM_safeParseList(answer);
382
+ return DyFM_Shared.safeParseList(answer);
383
383
  }
384
- askListQuestionInConversation = this.listQuestionInConversation;
384
+ askListQuestionInConversation: typeof this.listQuestionInConversation = this.listQuestionInConversation;
385
385
 
386
386
  /**
387
387
  * Asks the AI to answer a question
@@ -412,7 +412,7 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
412
412
  async getQuestionAnswerInConversation(
413
413
  set: {
414
414
  conversation: DyNTS_OAI_GPT_Message[],
415
- question: string,
415
+ question?: string,
416
416
  issuer: string,
417
417
  settings?: DyFM_GPTCall_Settings,
418
418
  debugLog?: boolean,
@@ -426,8 +426,9 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
426
426
  });
427
427
  }
428
428
  /* getQuestionAnswerInConversation = this.getAnswerInConversation; */
429
- getQuestionInConversation = this.getQuestionAnswerInConversation;
430
- askQuestionInConversation = this.getQuestionAnswerInConversation;
429
+ getQuestionInConversation: typeof this.getQuestionAnswerInConversation = this.getQuestionAnswerInConversation;
430
+ askQuestionInConversation: typeof this.getQuestionAnswerInConversation = this.getQuestionAnswerInConversation;
431
+ getConversationAnswer: typeof this.getAnswerInConversation = this.getAnswerInConversation;
431
432
 
432
433
  /**
433
434
  * Asks the AI to answer a question using the whole conversation
@@ -500,6 +501,8 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
500
501
 
501
502
  // conversation shortening
502
503
  const shortenedConversation = this.shortenConversation(set);
504
+
505
+ this.validateConversation(shortenedConversation);
503
506
 
504
507
  this.logConversation({
505
508
  ...set,
@@ -526,7 +529,7 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
526
529
  });
527
530
  }
528
531
  }
529
- resolveSimpleUserMessageInConversation = this.resolveConversation;
532
+ resolveSimpleUserMessageInConversation: typeof this.resolveConversation = this.resolveConversation;
530
533
 
531
534
  protected shortenConversation(
532
535
  set: {
@@ -599,6 +602,8 @@ export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase {
599
602
  }
600
603
  ) {
601
604
  if (set.debugLog || this.debugLog) {
605
+ DyFM_Log.info('Conversation', DyFM_getLocalStackLocation());
606
+
602
607
  set.conversation.forEach(message => {
603
608
  console.log(
604
609
  ` - ${message.role}: ${message.content.replace(set.replaceThisInLog, this.defaultLogReplacer)}`
@@ -1,7 +1,7 @@
1
1
  import { OpenAI } from 'openai';
2
2
 
3
3
  import { DyFM_OpenAI_Settings, DyFM_OpenAIModel, DyFM_GPTCall_Settings } from '@futdevpro/fsm-dynamo/open-ai';
4
- import { DyFM_AnyError, DyFM_Error, DyFM_Error_Settings, DyFM_Log, DyFM_notNull } from '@futdevpro/fsm-dynamo';
4
+ import { DyFM_AnyError, DyFM_Error, DyFM_Error_Settings, DyFM_Log, DyFM_notNull, DyFM_Shared } from '@futdevpro/fsm-dynamo';
5
5
 
6
6
  import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
7
7
  import { DyNTS_OAI_GPT_Message } from '../_models/interfaces/oai-gpt-message.interface';
@@ -193,7 +193,7 @@ export class DyNTS_OAI_LLM_ServiceBase {
193
193
 
194
194
  const answer = await this.askQuestion(set);
195
195
 
196
- return DyFM_safeParseJSON<T>(answer);
196
+ return DyFM_Shared.safeParseJSON<T>(answer);
197
197
  }
198
198
  /** the exact same as {@link requestSelect} */
199
199
  selectRequest = this.requestSelect;
@@ -263,7 +263,7 @@ export class DyNTS_OAI_LLM_ServiceBase {
263
263
 
264
264
  const answer = await this.askQuestion(set);
265
265
 
266
- return DyFM_safeParseList<T[]>(answer);
266
+ return DyFM_Shared.safeParseList<T[]>(answer);
267
267
  }
268
268
  /** the exact same as {@link requestMultipleSelect} */
269
269
  multipleSelectRequest = this.requestMultipleSelect;
@@ -291,7 +291,7 @@ export class DyNTS_OAI_LLM_ServiceBase {
291
291
 
292
292
  const answer = await this.askQuestion(set);
293
293
 
294
- return DyFM_safeParseJSON<T>(answer);
294
+ return DyFM_Shared.safeParseJSON<T>(answer);
295
295
  }
296
296
  /** the exact same as {@link askJSONQuestion} */
297
297
  jsonQuestion = this.askJSONQuestion;
@@ -324,7 +324,7 @@ export class DyNTS_OAI_LLM_ServiceBase {
324
324
 
325
325
  const answer = await this.askQuestion(set);
326
326
 
327
- return DyFM_safeParseJSON<T>(answer);
327
+ return DyFM_Shared.safeParseJSON<T>(answer);
328
328
  }
329
329
  /** the exact same as {@link askJSONQuestionWithKeysDescription} */
330
330
  jsonQuestionWithKeysDescription = this.askJSONQuestionWithKeysDescription;
@@ -357,7 +357,7 @@ export class DyNTS_OAI_LLM_ServiceBase {
357
357
 
358
358
  const answer = await this.askQuestion(set);
359
359
 
360
- return DyFM_safeParseJSON<T>(answer);
360
+ return DyFM_Shared.safeParseJSON<T>(answer);
361
361
  }
362
362
  /** the exact same as {@link askJSONQuestionWithExactKeys} */
363
363
  jsonQuestionWithExactKeys = this.askJSONQuestionWithExactKeys;
@@ -385,7 +385,7 @@ export class DyNTS_OAI_LLM_ServiceBase {
385
385
 
386
386
  const answer = await this.askQuestion(set);
387
387
 
388
- return DyFM_safeParseList(answer);
388
+ return DyFM_Shared.safeParseList<string[]>(answer);
389
389
  }
390
390
  /** the exact same as {@link askListQuestion} */
391
391
  listQuestion = this.askListQuestion;
@@ -597,6 +597,30 @@ export class DyNTS_OAI_LLM_ServiceBase {
597
597
  content: settings?.systemPrompt || this.defaultSystemPrompt,
598
598
  };
599
599
  }
600
+
601
+ protected validateConversation(conversation: DyNTS_OAI_GPT_Message[]): void {
602
+ conversation.forEach((message: DyNTS_OAI_GPT_Message, index: number) => {
603
+ if (!message.role) {
604
+ throw new DyFM_Error({
605
+ message: `Message has no role at index ${index}`,
606
+ additionalContent: {
607
+ invalidMessage: message,
608
+ conversation: conversation,
609
+ }
610
+ });
611
+ }
612
+
613
+ if (!message.content) {
614
+ throw new DyFM_Error({
615
+ message: `Message has no content at index ${index}`,
616
+ additionalContent: {
617
+ invalidMessage: message,
618
+ conversation: conversation,
619
+ }
620
+ });
621
+ }
622
+ });
623
+ }
600
624
 
601
625
  protected getDefaultErrorSettings(
602
626
  fnName: string,
@@ -618,92 +642,3 @@ export class DyNTS_OAI_LLM_ServiceBase {
618
642
 
619
643
  //#endregion
620
644
  }
621
-
622
- /**
623
- * parses the JSON list, if it fails, it returns the answer as a single item in an array
624
- *
625
- * (uses {@link DyFM_safeParseJSON})
626
- * @deprecated use {@link DyFM_Shared.safeParseList} instead
627
- */
628
- export function DyFM_safeParseList<T extends Array<any>>(
629
- textedJSON: string,
630
- disableErrorLog?: boolean
631
- ): T {
632
- const parsed = DyFM_safeParseJSON<T>(textedJSON, true);
633
-
634
- if (Array.isArray(parsed)) {
635
- return parsed;
636
- } else if (typeof parsed === 'object') {
637
- if (!disableErrorLog) {
638
- DyFM_Log.warn(
639
- 'DyFM_safeParseList result is an object, returning its values',
640
- {
641
- parsed: parsed,
642
- }
643
- );
644
- }
645
-
646
- return Object.values(parsed) as T;
647
- } else {
648
-
649
- if (!disableErrorLog) {
650
- DyFM_Log.warn(
651
- 'DyFM_safeParseList result is not an array or object, returning it as a single item',
652
- {
653
- parsed: parsed,
654
- }
655
- );
656
- }
657
-
658
- return [ parsed ] as string[] as T;
659
- }
660
- }
661
-
662
- /**
663
- * parses the JSON, if it fails, it returns { unparsableResult: textedJSON }
664
- *
665
- * (uses {@link DyFM_failableSafeParseJSON})
666
- * @deprecated use {@link DyFM_Shared.safeParseJSON} instead
667
- */
668
- export function DyFM_safeParseJSON<T = any>(
669
- textedJSON: string,
670
- disableErrorLog?: boolean
671
- ): T | { unparsableResult: string } {
672
- try {
673
- return DyFM_failableSafeParseJSON(textedJSON);
674
- } catch (error) {
675
- if (!disableErrorLog) {
676
- DyFM_Log.error(
677
- 'Unable to parse JSON answer:',
678
- {
679
- unparsedJSON: textedJSON,
680
- error: error,
681
- }
682
- );
683
- }
684
-
685
- return { unparsableResult: textedJSON };
686
- }
687
- }
688
-
689
- /**
690
- * parses the JSON, if it fails, it throws an error
691
- * (also will extract the JSON from "```json ... ```" wrapper)
692
- * @deprecated use {@link DyFM_Shared.failableSafeParseJSON} instead
693
- */
694
- export function DyFM_failableSafeParseJSON<T = any>(textedJSON: string): T {
695
- if (!textedJSON) {
696
- throw new Error(`No content provided to JSON parse ("${textedJSON}")`);
697
- }
698
-
699
- const match = textedJSON.match(/```json(.*)```/s);
700
- textedJSON = textedJSON.replaceAll('\n', '');
701
-
702
- if (match) {
703
- return JSON.parse(match[1].replaceAll('\n', ''));
704
- } else {
705
- return JSON.parse(
706
- textedJSON.replaceAll('```json', '').replaceAll('```', '')
707
- );
708
- }
709
- }