@yrpri/api 9.0.88 → 9.0.90

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.
@@ -419,6 +419,9 @@ var sendOneEmail = function (emailLocals, callback) {
419
419
  else {
420
420
  locale = "en";
421
421
  }
422
+ if (locale && typeof locale === 'string') {
423
+ locale = locale.toLowerCase();
424
+ }
422
425
  i18n.changeLanguage(locale, function (err, t) {
423
426
  seriesCallback(err);
424
427
  });
@@ -1,19 +1,13 @@
1
1
  import { OpenAI } from "openai";
2
2
  import { v4 as uuidv4 } from "uuid";
3
3
  import ioredis from "ioredis";
4
- let tlsConfig = {
5
- rejectUnauthorized: false,
6
- };
7
- if (!process.env.REDIS_URL || process.env.REDIS_URL.indexOf("localhost") > -1) {
8
- tlsConfig = undefined;
9
- }
10
4
  const DEBUG = false;
11
- //@ts-ignore
12
- const redis = new ioredis.default(process.env.REDIS_MEMORY_URL ||
5
+ const url = process.env.REDIS_MEMORY_URL ||
13
6
  process.env.REDIS_URL ||
14
- "redis://localhost:6379", {
15
- tls: tlsConfig,
16
- });
7
+ "redis://localhost:6379";
8
+ const tlsOptions = url.startsWith("rediss://")
9
+ ? { rejectUnauthorized: false }
10
+ : undefined;
17
11
  export class YpBaseChatBot {
18
12
  get redisKey() {
19
13
  return `${YpBaseChatBot.redisMemoryKeyPrefix}-${this.memoryId}`;
@@ -21,6 +15,12 @@ export class YpBaseChatBot {
21
15
  static loadMemoryFromRedis(memoryId) {
22
16
  return new Promise(async (resolve, reject) => {
23
17
  try {
18
+ //@ts-ignore
19
+ const redis = new ioredis.default(process.env.REDIS_MEMORY_URL ||
20
+ process.env.REDIS_URL ||
21
+ "redis://localhost:6379", {
22
+ tls: tlsOptions,
23
+ });
24
24
  const memoryString = await redis.get(`${YpBaseChatBot.redisMemoryKeyPrefix}-${memoryId}`);
25
25
  if (memoryString) {
26
26
  const memory = JSON.parse(memoryString);
@@ -42,7 +42,7 @@ export class YpBaseChatBot {
42
42
  loadMemory() {
43
43
  return new Promise(async (resolve, reject) => {
44
44
  try {
45
- const memoryString = await redis.get(this.redisKey);
45
+ const memoryString = await this.redis.get(this.redisKey);
46
46
  if (memoryString) {
47
47
  const memory = JSON.parse(memoryString);
48
48
  resolve(memory);
@@ -62,6 +62,12 @@ export class YpBaseChatBot {
62
62
  this.maxTokens = 16000;
63
63
  this.llmModel = "gpt-4o";
64
64
  this.persistMemory = false;
65
+ //@ts-ignore
66
+ this.redis = new ioredis.default(process.env.REDIS_MEMORY_URL ||
67
+ process.env.REDIS_URL ||
68
+ "redis://localhost:6379", {
69
+ tls: tlsOptions,
70
+ });
65
71
  this.wsClientId = wsClientId;
66
72
  this.wsClientSocket = wsClients.get(this.wsClientId);
67
73
  this.openaiClient = new OpenAI({
@@ -102,7 +108,7 @@ export class YpBaseChatBot {
102
108
  async saveMemory() {
103
109
  if (this.memory) {
104
110
  try {
105
- await redis.set(this.redisKey, JSON.stringify(this.memory));
111
+ await this.redis.set(this.redisKey, JSON.stringify(this.memory));
106
112
  console.log(`Saved memory to redis: ${this.redisKey}`);
107
113
  }
108
114
  catch (error) {
@@ -66,7 +66,7 @@ class YpQueue {
66
66
  }).on('completed', function (job, result) {
67
67
  log.info('JC', { id: job.id, name: job.name });
68
68
  }).on('failed', function (job, error) {
69
- log.error('Job Failed', { id: job.id, name: job.name, data: job.data, error });
69
+ log.error('Job Failed', { id: job ? job.id : null, name: job ? job.name : null, data: job ? job.data : null, error });
70
70
  }).on('resumed', function (job) {
71
71
  log.info('Job Removed', { id: job.id });
72
72
  }).on('waiting', function (jobId) {
@@ -21,26 +21,31 @@ export class YpBaseAssistant extends YpBaseChatBot {
21
21
  this.availableTools = new Map();
22
22
  this.toolCallTimeout = 30000; // 30 seconds
23
23
  this.maxModeTransitions = 10;
24
- this.modelName = "gpt-4o";
25
- this.defaultSystemPrompt = `# Basic instructions
24
+ this.modelName = process.env.OPENAI_STREAMING_MODEL_NAME || "gpt-4o-2024-11-20";
25
+ this.defaultSystemPrompt = `<coreImportantSystemInstructions>
26
26
  You are a helpful, witty, and friendly AI. Act like a human, but remember that you aren't a human and that you can't do human things in the real world.
27
27
  Your voice and personality should be warm and engaging, with a lively and playful tone. Talk quickly.
28
28
  If interacting in a non-English language, start by using the standard accent or dialect familiar to the user.
29
29
  You should always call a function/tool if you can to help the user with their request.
30
30
  Never try to start workflows without using functions/tools, using some tools will unlock other function/tools that might help the user with their request.
31
31
  Functions/tools will become available to you as the user progresses through the workflow.
32
- Make sure that the user is subscribed to the agent before you start a workflow.
32
+ Make sure that the user logged in and is subscribed to the agent before you start a workflow.
33
33
  Never list out the available agents using text or markdown, the user already sees the list of agents available for subscription in the UI.
34
- You will not be able to complete the request for the user except using tools/functions at each step.
34
+ You will not be able to start the workflow for the user except using tools/functions at each step.
35
+ Never engage in longish back and fourth conversations with the user if a workflow has not started, lead the user towards using the tools available as much as possible, politely.
36
+ Never engage in off topic conversations, always politely steer the conversation back to the workflow.
37
+ </coreImportantSystemInstructions>
35
38
 
36
- # Typical start of a user workflow is:
39
+ <typicalWorkflowStepsForStartingAnAgentWorkflow>
37
40
  1) The user chooses an agent to subscribe to using the direct connect to the agent the user chooses. It's only possible to subscribe to the agent after the user has connected directly to the agent.
38
41
  2) The agent offers to show the user a workflow overview, with a tool and then informs the user about the subscription process.
39
42
  3) The user logs in or creates an account, if not logged in.
40
43
  4) The user verbally confirms a subscription to the agent using a function/tool.
41
44
  5) The user fills out the configuration UI widget.
42
45
  6) The user submits from the configuration UI widget.
43
- 7) The user starts the workflow.`;
46
+ 7) The user starts the workflow run.
47
+ </typicalWorkflowStepsForStartingAnAgentWorkflow>
48
+ `;
44
49
  this.voiceEnabled = false;
45
50
  this.domainId = domainId;
46
51
  if (!domainId) {
@@ -479,7 +484,7 @@ You will not be able to complete the request for the user except using tools/fun
479
484
  console.error(`No current mode found: ${this.memory.currentMode}`);
480
485
  return this.defaultSystemPrompt;
481
486
  }
482
- return `${this.defaultSystemPrompt}\n\n# Current agent instructions:\n${currentMode.systemPrompt}`;
487
+ return `${this.defaultSystemPrompt}\n\n<furtherAgentInstructions>\n${currentMode.systemPrompt}\n</furtherAgentInstructions>`;
483
488
  }
484
489
  sendAvatarUrlChange(url, avatarName) {
485
490
  this.wsClientSocket.send(JSON.stringify({
@@ -3,6 +3,7 @@ import { YpSubscriptionPlan } from "../../../../models/subscriptionPlan.js";
3
3
  import { YpAgentProduct } from "../../../../models/agentProduct.js";
4
4
  import { YpAgentProductBundle } from "../../../../models/agentProductBundle.js";
5
5
  import { YpAgentProductRun } from "../../../../models/agentProductRun.js";
6
+ import { Op } from "sequelize";
6
7
  export class SubscriptionModels {
7
8
  constructor(assistant) {
8
9
  this.assistant = assistant;
@@ -18,7 +19,10 @@ export class SubscriptionModels {
18
19
  // Get all available subscription plans with their associated agent products
19
20
  const availablePlans = await YpSubscriptionPlan.findAll({
20
21
  where: {
21
- // status: 'active', // Only get active plans
22
+ id: {
23
+ [Op.in]: [1, 6],
24
+ },
25
+ // status: 'active', // Only get active plans
22
26
  },
23
27
  attributes: ['id', 'configuration', 'name', 'description'],
24
28
  include: [
@@ -1,7 +1,7 @@
1
1
  // commonTools.ts
2
- import { AgentModels } from './models/agents.js';
3
- import { SubscriptionModels } from './models/subscriptions.js';
4
- import { BaseAssistantTools } from './baseTools.js';
2
+ import { AgentModels } from "./models/agents.js";
3
+ import { SubscriptionModels } from "./models/subscriptions.js";
4
+ import { BaseAssistantTools } from "./baseTools.js";
5
5
  export class NavigationTools extends BaseAssistantTools {
6
6
  constructor(assistant) {
7
7
  super(assistant);
@@ -9,10 +9,10 @@ export class NavigationTools extends BaseAssistantTools {
9
9
  this.subscriptionModels = new SubscriptionModels(assistant);
10
10
  }
11
11
  async goBackToMainAssistant() {
12
- await this.assistant.handleModeSwitch('agent_selection_mode', 'User requested to return to the main assistant', {});
12
+ await this.assistant.handleModeSwitch("agent_selection_mode", "User requested to return to the main assistant", {});
13
13
  return {
14
14
  success: true,
15
- data: { message: 'Returned to main assistant' },
15
+ data: { message: "Returned to main assistant" },
16
16
  };
17
17
  }
18
18
  get connectDirectlyToAgent() {
@@ -36,12 +36,31 @@ export class NavigationTools extends BaseAssistantTools {
36
36
  params = this.assistant.getCleanedParams(params);
37
37
  console.log(`handler: connect_to_one_of_the_agents: ${JSON.stringify(params, null, 2)}`);
38
38
  try {
39
- const { plan, subscription } = await this.subscriptionModels.loadAgentProductPlanAndSubscription(params.subscriptionPlanId);
39
+ let { plan, subscription } = await this.subscriptionModels.loadAgentProductPlanAndSubscription(params.subscriptionPlanId);
40
40
  if (!plan?.AgentProduct) {
41
41
  throw new Error(`Agent product with id ${params.subscriptionPlanId} not found`);
42
42
  }
43
+ //TODO: Does not work as the user is not logged in. Lets figure it out.
44
+ /*if (plan.configuration.amount == 0) {
45
+ const result = await this.subscriptionModels.subscribeToAgentPlan(
46
+ plan.AgentProduct!.id,
47
+ plan.id
48
+ );
49
+
50
+ if (!result.success || !result.subscription || !result.plan) {
51
+ return {
52
+ success: false,
53
+ error: result.error || "Failed to subscribe to agent plan",
54
+ };
55
+ } else {
56
+ plan = result.plan;
57
+ subscription = result.subscription;
58
+ }
59
+ }*/
43
60
  console.log(`Loading: ${plan?.AgentProduct?.name} ${subscription?.id}`);
44
- await this.updateCurrentAgentProductPlan(plan, subscription, { sendEvent: false });
61
+ await this.updateCurrentAgentProductPlan(plan, subscription, {
62
+ sendEvent: false,
63
+ });
45
64
  await this.assistant.handleModeSwitch("agent_direct_connection_mode", `Directly connected to agent: ${plan?.AgentProduct?.name}`, params);
46
65
  const html = `<div class="agent-chips"><yp-agent-chip
47
66
  isSelected
@@ -61,9 +80,7 @@ export class NavigationTools extends BaseAssistantTools {
61
80
  };
62
81
  }
63
82
  catch (error) {
64
- const errorMessage = error instanceof Error
65
- ? error.message
66
- : "Failed to select agent";
83
+ const errorMessage = error instanceof Error ? error.message : "Failed to select agent";
67
84
  console.error(`Failed to select agent: ${errorMessage}`);
68
85
  return {
69
86
  success: false,
@@ -19,7 +19,7 @@ export class YpBaseChatBotWithVoice extends YpBaseChatBot {
19
19
  };
20
20
  // Default voice configuration
21
21
  this.voiceConfig = {
22
- model: "gpt-4o-realtime-preview-2024-12-17",
22
+ model: process.env.OPENAI_VOICE_MODEL_NAME || "gpt-4o-realtime-preview-2024-12-17",
23
23
  voice: "echo",
24
24
  modalities: ["text", "audio"],
25
25
  };