@sprucelabs/sprucebot-llm 15.1.1 → 15.1.3

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.
@@ -37,11 +37,26 @@ class AnthropicAdapter {
37
37
  async sendHandler(params, sendOptions) {
38
38
  const { messages: openAiMessages, model } = params;
39
39
  const messages = [];
40
+ const cacheMarkerIdx = openAiMessages.findIndex((msg) => msg.cache_marker);
40
41
  for (const msg of openAiMessages) {
41
- messages.push({
42
- role: msg.role === 'assistant' ? 'assistant' : 'user',
43
- content: msg.content,
44
- });
42
+ if (!msg.cache_marker) {
43
+ const m = msg;
44
+ messages.push({
45
+ role: m.role === 'assistant' ? 'assistant' : 'user',
46
+ content: m.content,
47
+ });
48
+ }
49
+ }
50
+ if (cacheMarkerIdx > -1) {
51
+ messages[cacheMarkerIdx - 1].content = [
52
+ {
53
+ type: 'text',
54
+ text: messages[cacheMarkerIdx - 1].content,
55
+ cache_control: {
56
+ type: 'ephemeral',
57
+ },
58
+ },
59
+ ];
45
60
  }
46
61
  const response = await this.api.messages.create({
47
62
  max_tokens: this.maxTokens,
@@ -6,7 +6,7 @@ export default class MessageBuilder {
6
6
  protected constructor(bot: SprucebotLlmBot, options?: BuildMessageOptions);
7
7
  static Builder(bot: SprucebotLlmBot, options?: BuildMessageOptions): MessageBuilder;
8
8
  private get parser();
9
- buildMessages(): ChatCompletionMessageParam[];
9
+ buildMessages(): MessageBuilderMessage[];
10
10
  private buildChatHistoryMessages;
11
11
  private mapMessageToCompletion;
12
12
  private maxCharsOfPastMessages;
@@ -23,4 +23,8 @@ export default class MessageBuilder {
23
23
  interface BuildMessageOptions {
24
24
  memoryLimit?: number;
25
25
  }
26
+ export interface MessageBuilderCacheMarker {
27
+ cache_marker: true;
28
+ }
29
+ export type MessageBuilderMessage = ChatCompletionMessageParam | MessageBuilderCacheMarker;
26
30
  export {};
@@ -26,6 +26,12 @@ class MessageBuilder {
26
26
  ...this.buildSkillMessages(values.skill),
27
27
  ...this.buildChatHistoryMessages(values.messages),
28
28
  ];
29
+ if (!values.skill) {
30
+ const first = allMessages[0];
31
+ allMessages.shift();
32
+ allMessages.unshift({ cache_marker: true });
33
+ allMessages.unshift(first);
34
+ }
29
35
  return allMessages;
30
36
  }
31
37
  buildChatHistoryMessages(messages) {
@@ -99,9 +105,6 @@ class MessageBuilder {
99
105
  if (skill.stateSchema) {
100
106
  messages.push(this.buildStateSchemaMessage(skill.stateSchema));
101
107
  }
102
- if (skill.state) {
103
- messages.push(this.buildStateMessage(skill.state));
104
- }
105
108
  if (skill.weAreDoneWhen) {
106
109
  messages.push(this.buildWeAreDoneWhenMessage(skill.weAreDoneWhen));
107
110
  }
@@ -111,6 +114,10 @@ class MessageBuilder {
111
114
  if (skill.pleaseKeepInMindThat) {
112
115
  messages.push(this.buildPleaseKeepInMindMessage(skill.pleaseKeepInMindThat));
113
116
  }
117
+ messages.push({ cache_marker: true });
118
+ if (skill.state) {
119
+ messages.push(this.buildStateMessage(skill.state));
120
+ }
114
121
  return messages;
115
122
  }
116
123
  buildCallbacksMessage(callbacks) {
@@ -1,8 +1,8 @@
1
1
  import { Log } from '@sprucelabs/spruce-skill-utils';
2
- import OpenAI from 'openai';
3
2
  import { RequestOptions } from 'openai/internal/request-options';
4
- import { ReasoningEffort, ChatCompletionCreateParamsNonStreaming } from 'openai/resources';
3
+ import { ReasoningEffort } from 'openai/resources';
5
4
  import { SprucebotLlmBot, SendMessageOptions } from '../../llm.types';
5
+ import { MessageBuilderMessage } from './MessageBuilder';
6
6
  export default class MessageSenderImpl implements MessageSender {
7
7
  static AbortController: {
8
8
  new (): AbortController;
@@ -18,12 +18,16 @@ export default class MessageSenderImpl implements MessageSender {
18
18
  private send;
19
19
  }
20
20
  export type MessageSenderSendOptions = SendMessageOptions & {
21
- messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[];
21
+ messages: MessageBuilderMessage[];
22
22
  reasoningEffort?: ReasoningEffort;
23
23
  model: string;
24
24
  abortController: AbortController;
25
25
  };
26
- export type MessageSenderSendHandler = (params: ChatCompletionCreateParamsNonStreaming, options: RequestOptions) => Promise<string | undefined>;
26
+ export interface MessageHandlerSendHandlerParams {
27
+ model: string;
28
+ messages: MessageBuilderMessage[];
29
+ }
30
+ export type MessageSenderSendHandler = (params: MessageHandlerSendHandlerParams, options: RequestOptions) => Promise<string | undefined>;
27
31
  export interface MessageSender {
28
32
  sendMessage(bot: SprucebotLlmBot, options: MessageSenderSendMessageOptions): Promise<string>;
29
33
  }
@@ -30,6 +30,8 @@ class OpenAiAdapter {
30
30
  });
31
31
  }
32
32
  async sendHandler(params, sendOptions) {
33
+ const { messages } = params;
34
+ params.messages = messages.filter((msg) => !msg.cache_marker);
33
35
  const response = await this.api.chat.completions.create(params, sendOptions);
34
36
  const responseMessage = response.choices?.[0]?.message?.content?.trim();
35
37
  return responseMessage;
@@ -42,11 +42,26 @@ class AnthropicAdapter {
42
42
  var _a, _b;
43
43
  const { messages: openAiMessages, model } = params;
44
44
  const messages = [];
45
+ const cacheMarkerIdx = openAiMessages.findIndex((msg) => msg.cache_marker);
45
46
  for (const msg of openAiMessages) {
46
- messages.push({
47
- role: msg.role === 'assistant' ? 'assistant' : 'user',
48
- content: msg.content,
49
- });
47
+ if (!msg.cache_marker) {
48
+ const m = msg;
49
+ messages.push({
50
+ role: m.role === 'assistant' ? 'assistant' : 'user',
51
+ content: m.content,
52
+ });
53
+ }
54
+ }
55
+ if (cacheMarkerIdx > -1) {
56
+ messages[cacheMarkerIdx - 1].content = [
57
+ {
58
+ type: 'text',
59
+ text: messages[cacheMarkerIdx - 1].content,
60
+ cache_control: {
61
+ type: 'ephemeral',
62
+ },
63
+ },
64
+ ];
50
65
  }
51
66
  const response = yield this.api.messages.create({
52
67
  max_tokens: this.maxTokens,
@@ -6,7 +6,7 @@ export default class MessageBuilder {
6
6
  protected constructor(bot: SprucebotLlmBot, options?: BuildMessageOptions);
7
7
  static Builder(bot: SprucebotLlmBot, options?: BuildMessageOptions): MessageBuilder;
8
8
  private get parser();
9
- buildMessages(): ChatCompletionMessageParam[];
9
+ buildMessages(): MessageBuilderMessage[];
10
10
  private buildChatHistoryMessages;
11
11
  private mapMessageToCompletion;
12
12
  private maxCharsOfPastMessages;
@@ -23,4 +23,8 @@ export default class MessageBuilder {
23
23
  interface BuildMessageOptions {
24
24
  memoryLimit?: number;
25
25
  }
26
+ export interface MessageBuilderCacheMarker {
27
+ cache_marker: true;
28
+ }
29
+ export type MessageBuilderMessage = ChatCompletionMessageParam | MessageBuilderCacheMarker;
26
30
  export {};
@@ -21,6 +21,12 @@ export default class MessageBuilder {
21
21
  ...this.buildSkillMessages(values.skill),
22
22
  ...this.buildChatHistoryMessages(values.messages),
23
23
  ];
24
+ if (!values.skill) {
25
+ const first = allMessages[0];
26
+ allMessages.shift();
27
+ allMessages.unshift({ cache_marker: true });
28
+ allMessages.unshift(first);
29
+ }
24
30
  return allMessages;
25
31
  }
26
32
  buildChatHistoryMessages(messages) {
@@ -95,9 +101,6 @@ export default class MessageBuilder {
95
101
  if (skill.stateSchema) {
96
102
  messages.push(this.buildStateSchemaMessage(skill.stateSchema));
97
103
  }
98
- if (skill.state) {
99
- messages.push(this.buildStateMessage(skill.state));
100
- }
101
104
  if (skill.weAreDoneWhen) {
102
105
  messages.push(this.buildWeAreDoneWhenMessage(skill.weAreDoneWhen));
103
106
  }
@@ -107,6 +110,10 @@ export default class MessageBuilder {
107
110
  if (skill.pleaseKeepInMindThat) {
108
111
  messages.push(this.buildPleaseKeepInMindMessage(skill.pleaseKeepInMindThat));
109
112
  }
113
+ messages.push({ cache_marker: true });
114
+ if (skill.state) {
115
+ messages.push(this.buildStateMessage(skill.state));
116
+ }
110
117
  return messages;
111
118
  }
112
119
  buildCallbacksMessage(callbacks) {
@@ -1,8 +1,8 @@
1
1
  import { Log } from '@sprucelabs/spruce-skill-utils';
2
- import OpenAI from 'openai';
3
2
  import { RequestOptions } from 'openai/internal/request-options';
4
- import { ReasoningEffort, ChatCompletionCreateParamsNonStreaming } from 'openai/resources';
3
+ import { ReasoningEffort } from 'openai/resources';
5
4
  import { SprucebotLlmBot, SendMessageOptions } from '../../llm.types';
5
+ import { MessageBuilderMessage } from './MessageBuilder';
6
6
  export default class MessageSenderImpl implements MessageSender {
7
7
  static AbortController: {
8
8
  new (): AbortController;
@@ -18,12 +18,16 @@ export default class MessageSenderImpl implements MessageSender {
18
18
  private send;
19
19
  }
20
20
  export type MessageSenderSendOptions = SendMessageOptions & {
21
- messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[];
21
+ messages: MessageBuilderMessage[];
22
22
  reasoningEffort?: ReasoningEffort;
23
23
  model: string;
24
24
  abortController: AbortController;
25
25
  };
26
- export type MessageSenderSendHandler = (params: ChatCompletionCreateParamsNonStreaming, options: RequestOptions) => Promise<string | undefined>;
26
+ export interface MessageHandlerSendHandlerParams {
27
+ model: string;
28
+ messages: MessageBuilderMessage[];
29
+ }
30
+ export type MessageSenderSendHandler = (params: MessageHandlerSendHandlerParams, options: RequestOptions) => Promise<string | undefined>;
27
31
  export interface MessageSender {
28
32
  sendMessage(bot: SprucebotLlmBot, options: MessageSenderSendMessageOptions): Promise<string>;
29
33
  }
@@ -33,6 +33,8 @@ class OpenAiAdapter {
33
33
  sendHandler(params, sendOptions) {
34
34
  return __awaiter(this, void 0, void 0, function* () {
35
35
  var _a, _b, _c, _d;
36
+ const { messages } = params;
37
+ params.messages = messages.filter((msg) => !msg.cache_marker);
36
38
  const response = yield this.api.chat.completions.create(params, sendOptions);
37
39
  const responseMessage = (_d = (_c = (_b = (_a = response.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.trim();
38
40
  return responseMessage;
@@ -98,6 +98,6 @@ export default class ResponseParserV2 {
98
98
  return 'Updating state works similar to all function calls. Use the following syntax:\n@updateState { "updates": "here" }\n. Make sure to json encode only the fields you want to change. You can update state once and do it at the end of any messages you send. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON.';
99
99
  }
100
100
  getFunctionCallInstructions() {
101
- return `A function call is done using the following syntax:\n@callback { "name": "callbackName", "options": {} }\nMake sure to json encode the options and include the name of the callback you want to call. You can call as many callbacks as you want in a single response by including multiple @callback lines. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON.`;
101
+ return `A function call is done using the following syntax:\n@callback { "name": "callbackName", "options": {} }\nMake sure to json encode the options and include the name of the callback you want to call. You can call as many callbacks as you want in a single response by including multiple @callback lines. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON. Also, do NOT call something like @myCallback. You would call it like this: @callback { "name": "myCallback", "options": {} }`;
102
102
  }
103
103
  }
@@ -90,7 +90,7 @@ class ResponseParserV2 {
90
90
  return 'Updating state works similar to all function calls. Use the following syntax:\n@updateState { "updates": "here" }\n. Make sure to json encode only the fields you want to change. You can update state once and do it at the end of any messages you send. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON.';
91
91
  }
92
92
  getFunctionCallInstructions() {
93
- return `A function call is done using the following syntax:\n@callback { "name": "callbackName", "options": {} }\nMake sure to json encode the options and include the name of the callback you want to call. You can call as many callbacks as you want in a single response by including multiple @callback lines. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON.`;
93
+ return `A function call is done using the following syntax:\n@callback { "name": "callbackName", "options": {} }\nMake sure to json encode the options and include the name of the callback you want to call. You can call as many callbacks as you want in a single response by including multiple @callback lines. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON. Also, do NOT call something like @myCallback. You would call it like this: @callback { "name": "myCallback", "options": {} }`;
94
94
  }
95
95
  }
96
96
  exports.default = ResponseParserV2;
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "eta"
9
9
  ]
10
10
  },
11
- "version": "15.1.1",
11
+ "version": "15.1.3",
12
12
  "files": [
13
13
  "build"
14
14
  ],