@sprucelabs/sprucebot-llm 11.1.20 → 11.3.0

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.
@@ -7,6 +7,8 @@ export default class OpenAiMessageBuilder {
7
7
  buildMessages(): ChatCompletionMessageParam[];
8
8
  private buildChatHistoryMessages;
9
9
  private mapMessageToCompletion;
10
+ private maxCharsOfPastMessages;
11
+ private shouldRememberImages;
10
12
  private buildFirstMessage;
11
13
  private buildSkillMessages;
12
14
  private buildCallbacksMessage;
@@ -23,9 +23,10 @@ class OpenAiMessageBuilder {
23
23
  if (limit > 0) {
24
24
  messagesBeingConsidered = messages.slice(Math.max(messages.length - limit, 0));
25
25
  }
26
- return messagesBeingConsidered.map((message) => this.mapMessageToCompletion(message));
26
+ const total = messagesBeingConsidered.length;
27
+ return messagesBeingConsidered.map((message, idx) => this.mapMessageToCompletion(message, idx === total - 1));
27
28
  }
28
- mapMessageToCompletion(message) {
29
+ mapMessageToCompletion(message, isLast) {
29
30
  let content = message.message;
30
31
  let role = message.from === 'Me'
31
32
  ? 'user'
@@ -34,24 +35,45 @@ class OpenAiMessageBuilder {
34
35
  : 'developer';
35
36
  if (message.imageBase64) {
36
37
  role = 'user';
38
+ const shouldBeIncluded = this.shouldRememberImages() || isLast;
37
39
  content = [
38
40
  {
39
41
  type: 'text',
40
42
  text: message.message,
41
43
  },
42
- {
43
- type: 'image_url',
44
- image_url: {
45
- url: `data:image/png;base64,${message.imageBase64}`,
44
+ shouldBeIncluded
45
+ ? {
46
+ type: 'image_url',
47
+ image_url: {
48
+ url: `data:image/png;base64,${message.imageBase64}`,
49
+ },
50
+ }
51
+ : {
52
+ type: 'text',
53
+ text: '[Image omitted to save context]',
46
54
  },
47
- },
48
55
  ];
49
56
  }
57
+ const shouldTruncate = typeof content === 'string' &&
58
+ !isLast &&
59
+ this.maxCharsOfPastMessages() > 0 &&
60
+ content.length > this.maxCharsOfPastMessages();
61
+ if (shouldTruncate) {
62
+ content = `[omitted due to length]`;
63
+ }
50
64
  return {
51
65
  role,
52
66
  content,
53
67
  };
54
68
  }
69
+ maxCharsOfPastMessages() {
70
+ return process.env.OPENAI_PAST_MESSAGE_MAX_CHARS
71
+ ? parseInt(process.env.OPENAI_PAST_MESSAGE_MAX_CHARS ?? '1000', 10)
72
+ : -1;
73
+ }
74
+ shouldRememberImages() {
75
+ return process.env.OPENAI_SHOULD_REMEMBER_IMAGES !== 'false';
76
+ }
55
77
  buildFirstMessage(youAre) {
56
78
  return {
57
79
  role: 'developer',
@@ -131,7 +153,7 @@ class OpenAiMessageBuilder {
131
153
  buildStateMessage(state) {
132
154
  return {
133
155
  role: 'developer',
134
- content: `The current state of this conversation is:\n\n${JSON.stringify(state)}. As the state is being updated, send it back to me in json format (something in can JSON.parse()) at the end of each response (it's not meant for reading, but for parsing, so don't call it out, but send it as we progress), surrounded by a boundary, like this: ${templates_1.STATE_BOUNDARY} { "fieldName": "fieldValue" } ${templates_1.STATE_BOUNDARY}`,
156
+ content: `The current state of this conversation is:\n\n${JSON.stringify(state)}. As the state is being updated, send it back to me in json format (something in can JSON.parse()) at the end of each response (it's not meant for reading, but for parsing, so don't call it out, but send it as we progress), surrounded by the State Boundary (${templates_1.STATE_BOUNDARY}), like this:\n\n${templates_1.STATE_BOUNDARY} { "fieldName": "fieldValue" } ${templates_1.STATE_BOUNDARY}`,
135
157
  };
136
158
  }
137
159
  buildYourJobMessage(yourJob) {
@@ -1,4 +1,4 @@
1
- export declare const STATE_BOUNDARY = "*****";
1
+ export declare const STATE_BOUNDARY = "*** STATE BOUNDARY ***";
2
2
  export declare const DONE_TOKEN = "DONE_DONE_DONE";
3
3
  export declare const CALLBACK_BOUNDARY = "xxxxx";
4
4
  export declare const PROMPT_TEMPLATE: string;
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PROMPT_TEMPLATE = exports.CALLBACK_BOUNDARY = exports.DONE_TOKEN = exports.STATE_BOUNDARY = void 0;
7
7
  const renderPlaceholder_1 = __importDefault(require("../parsingResponses/renderPlaceholder"));
8
- exports.STATE_BOUNDARY = '*****';
8
+ exports.STATE_BOUNDARY = '*** STATE BOUNDARY ***';
9
9
  exports.DONE_TOKEN = `DONE_DONE_DONE`;
10
10
  exports.CALLBACK_BOUNDARY = 'xxxxx';
11
11
  exports.PROMPT_TEMPLATE = `You are <%= it.youAre %>
@@ -7,6 +7,8 @@ export default class OpenAiMessageBuilder {
7
7
  buildMessages(): ChatCompletionMessageParam[];
8
8
  private buildChatHistoryMessages;
9
9
  private mapMessageToCompletion;
10
+ private maxCharsOfPastMessages;
11
+ private shouldRememberImages;
10
12
  private buildFirstMessage;
11
13
  private buildSkillMessages;
12
14
  private buildCallbacksMessage;
@@ -22,9 +22,10 @@ export default class OpenAiMessageBuilder {
22
22
  if (limit > 0) {
23
23
  messagesBeingConsidered = messages.slice(Math.max(messages.length - limit, 0));
24
24
  }
25
- return messagesBeingConsidered.map((message) => this.mapMessageToCompletion(message));
25
+ const total = messagesBeingConsidered.length;
26
+ return messagesBeingConsidered.map((message, idx) => this.mapMessageToCompletion(message, idx === total - 1));
26
27
  }
27
- mapMessageToCompletion(message) {
28
+ mapMessageToCompletion(message, isLast) {
28
29
  let content = message.message;
29
30
  let role = message.from === 'Me'
30
31
  ? 'user'
@@ -33,24 +34,46 @@ export default class OpenAiMessageBuilder {
33
34
  : 'developer';
34
35
  if (message.imageBase64) {
35
36
  role = 'user';
37
+ const shouldBeIncluded = this.shouldRememberImages() || isLast;
36
38
  content = [
37
39
  {
38
40
  type: 'text',
39
41
  text: message.message,
40
42
  },
41
- {
42
- type: 'image_url',
43
- image_url: {
44
- url: `data:image/png;base64,${message.imageBase64}`,
43
+ shouldBeIncluded
44
+ ? {
45
+ type: 'image_url',
46
+ image_url: {
47
+ url: `data:image/png;base64,${message.imageBase64}`,
48
+ },
49
+ }
50
+ : {
51
+ type: 'text',
52
+ text: '[Image omitted to save context]',
45
53
  },
46
- },
47
54
  ];
48
55
  }
56
+ const shouldTruncate = typeof content === 'string' &&
57
+ !isLast &&
58
+ this.maxCharsOfPastMessages() > 0 &&
59
+ content.length > this.maxCharsOfPastMessages();
60
+ if (shouldTruncate) {
61
+ content = `[omitted due to length]`;
62
+ }
49
63
  return {
50
64
  role,
51
65
  content,
52
66
  };
53
67
  }
68
+ maxCharsOfPastMessages() {
69
+ var _a;
70
+ return process.env.OPENAI_PAST_MESSAGE_MAX_CHARS
71
+ ? parseInt((_a = process.env.OPENAI_PAST_MESSAGE_MAX_CHARS) !== null && _a !== void 0 ? _a : '1000', 10)
72
+ : -1;
73
+ }
74
+ shouldRememberImages() {
75
+ return process.env.OPENAI_SHOULD_REMEMBER_IMAGES !== 'false';
76
+ }
54
77
  buildFirstMessage(youAre) {
55
78
  return {
56
79
  role: 'developer',
@@ -130,7 +153,7 @@ export default class OpenAiMessageBuilder {
130
153
  buildStateMessage(state) {
131
154
  return {
132
155
  role: 'developer',
133
- content: `The current state of this conversation is:\n\n${JSON.stringify(state)}. As the state is being updated, send it back to me in json format (something in can JSON.parse()) at the end of each response (it's not meant for reading, but for parsing, so don't call it out, but send it as we progress), surrounded by a boundary, like this: ${STATE_BOUNDARY} { "fieldName": "fieldValue" } ${STATE_BOUNDARY}`,
156
+ content: `The current state of this conversation is:\n\n${JSON.stringify(state)}. As the state is being updated, send it back to me in json format (something in can JSON.parse()) at the end of each response (it's not meant for reading, but for parsing, so don't call it out, but send it as we progress), surrounded by the State Boundary (${STATE_BOUNDARY}), like this:\n\n${STATE_BOUNDARY} { "fieldName": "fieldValue" } ${STATE_BOUNDARY}`,
134
157
  };
135
158
  }
136
159
  buildYourJobMessage(yourJob) {
@@ -1,4 +1,4 @@
1
- export declare const STATE_BOUNDARY = "*****";
1
+ export declare const STATE_BOUNDARY = "*** STATE BOUNDARY ***";
2
2
  export declare const DONE_TOKEN = "DONE_DONE_DONE";
3
3
  export declare const CALLBACK_BOUNDARY = "xxxxx";
4
4
  export declare const PROMPT_TEMPLATE: string;
@@ -1,5 +1,5 @@
1
1
  import renderPlaceholder from '../parsingResponses/renderPlaceholder.js';
2
- export const STATE_BOUNDARY = '*****';
2
+ export const STATE_BOUNDARY = '*** STATE BOUNDARY ***';
3
3
  export const DONE_TOKEN = `DONE_DONE_DONE`;
4
4
  export const CALLBACK_BOUNDARY = 'xxxxx';
5
5
  export const PROMPT_TEMPLATE = `You are <%= it.youAre %>
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "eta"
9
9
  ]
10
10
  },
11
- "version": "11.1.20",
11
+ "version": "11.3.0",
12
12
  "files": [
13
13
  "build"
14
14
  ],