@sprucelabs/sprucebot-llm 15.1.11 → 15.1.12

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.
@@ -13,6 +13,7 @@ export default class MessageBuilder {
13
13
  private shouldRememberImages;
14
14
  private buildFirstMessage;
15
15
  private buildSkillMessages;
16
+ private buildFunctionSyntaxMessage;
16
17
  private buildCallbacksMessage;
17
18
  private buildPleaseKeepInMindMessage;
18
19
  private buildStateMessage;
@@ -102,6 +102,9 @@ class MessageBuilder {
102
102
  }
103
103
  const messages = [];
104
104
  messages.push(this.buildYourJobMessage(skill.yourJobIfYouChooseToAcceptItIs));
105
+ if (skill.callbacks || skill.state || skill.stateSchema) {
106
+ messages.push(this.buildFunctionSyntaxMessage());
107
+ }
105
108
  if (skill.stateSchema) {
106
109
  messages.push(this.buildStateSchemaMessage(skill.stateSchema));
107
110
  }
@@ -120,6 +123,12 @@ class MessageBuilder {
120
123
  }
121
124
  return messages;
122
125
  }
126
+ buildFunctionSyntaxMessage() {
127
+ return {
128
+ role: 'system',
129
+ content: `Throughout this conversation, all function calls and state updates use JavaScript-style syntax: @functionName({ "key": "value" }). The function name follows the @ symbol, and the single argument is a JSON object wrapped in parentheses. All JSON must be on a single line.`,
130
+ };
131
+ }
123
132
  buildCallbacksMessage(callbacks) {
124
133
  const keys = Object.keys(callbacks);
125
134
  const descriptions = [];
@@ -13,6 +13,7 @@ export default class MessageBuilder {
13
13
  private shouldRememberImages;
14
14
  private buildFirstMessage;
15
15
  private buildSkillMessages;
16
+ private buildFunctionSyntaxMessage;
16
17
  private buildCallbacksMessage;
17
18
  private buildPleaseKeepInMindMessage;
18
19
  private buildStateMessage;
@@ -98,6 +98,9 @@ export default class MessageBuilder {
98
98
  }
99
99
  const messages = [];
100
100
  messages.push(this.buildYourJobMessage(skill.yourJobIfYouChooseToAcceptItIs));
101
+ if (skill.callbacks || skill.state || skill.stateSchema) {
102
+ messages.push(this.buildFunctionSyntaxMessage());
103
+ }
101
104
  if (skill.stateSchema) {
102
105
  messages.push(this.buildStateSchemaMessage(skill.stateSchema));
103
106
  }
@@ -116,6 +119,12 @@ export default class MessageBuilder {
116
119
  }
117
120
  return messages;
118
121
  }
122
+ buildFunctionSyntaxMessage() {
123
+ return {
124
+ role: 'system',
125
+ content: `Throughout this conversation, all function calls and state updates use JavaScript-style syntax: @functionName({ "key": "value" }). The function name follows the @ symbol, and the single argument is a JSON object wrapped in parentheses. All JSON must be on a single line.`,
126
+ };
127
+ }
119
128
  buildCallbacksMessage(callbacks) {
120
129
  const keys = Object.keys(callbacks);
121
130
  const descriptions = [];
@@ -15,9 +15,8 @@ export default class ResponseParserV2 {
15
15
  let message = response.replace(DONE_TOKEN, '').trim();
16
16
  let state = undefined;
17
17
  let callbackResults = undefined;
18
- const hasCallbacks = message.includes('@callback') ||
19
- (callbacks != null &&
20
- Object.keys(callbacks).some((name) => message.includes(`@${name}`)));
18
+ const hasCallbacks = callbacks != null &&
19
+ Object.keys(callbacks).some((name) => message.includes(`@${name}(`));
21
20
  if (hasCallbacks) {
22
21
  const { callbackResults: c, message: m } = yield this.invokeCallbacks(message, callbacks);
23
22
  callbackResults = c;
@@ -26,7 +25,7 @@ export default class ResponseParserV2 {
26
25
  const hasState = response.includes('@updateState');
27
26
  if (hasState && message) {
28
27
  const stateMatches = [
29
- ...message.matchAll(/@updateState\s+({[\s\S]*?})\n?/g),
28
+ ...message.matchAll(/@updateState\(({[\s\S]*?})\)\n?/g),
30
29
  ];
31
30
  for (const stateMatch of stateMatches) {
32
31
  try {
@@ -57,17 +56,16 @@ export default class ResponseParserV2 {
57
56
  let callbackStrippedMessage = message;
58
57
  let callbackResults = '';
59
58
  const reserved = new Set(['updateState', 'results']);
60
- const matches = [...message.matchAll(/^@(\w+)\s+({.*})$/gm)];
59
+ const matches = [...message.matchAll(/^@(\w+)\(({.*})\)$/gm)];
61
60
  for (const match of matches) {
62
61
  if (reserved.has(match[1])) {
63
62
  continue;
64
63
  }
65
64
  const parsed = JSON.parse(match[2]);
66
- const isCanonical = match[1] === 'callback';
67
- const name = isCanonical ? parsed.name : match[1];
68
- const options = isCanonical ? parsed.options : parsed;
65
+ const name = match[1];
66
+ const options = parsed;
69
67
  const callback = callbacks === null || callbacks === void 0 ? void 0 : callbacks[name];
70
- if (!isCanonical && !callback) {
68
+ if (!callback) {
71
69
  continue;
72
70
  }
73
71
  const parts = callbackStrippedMessage.split(match[0]);
@@ -103,32 +101,31 @@ export default class ResponseParserV2 {
103
101
  }
104
102
  getStateUpdateInstructions() {
105
103
  return `Updating state works similar to all function calls. Use the following syntax:
106
- @updateState { "field1": "value1", "field2": "value2" }
104
+ @updateState({ "field1": "value1", "field2": "value2" })
107
105
  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.
108
106
  Your user-facing message is always sent to the user, even if @updateState fails. If @updateState fails later, do not repeat the same message. Only send the specific @updateState needed to fix the missing state change.
109
107
  Good example:
110
- @updateState { "favoriteColor": "blue", "firstName": "Taylor" }
108
+ @updateState({ "favoriteColor": "blue", "firstName": "Taylor" })
111
109
  Bad examples:
112
110
  @updateState
113
111
  { "favoriteColor": "blue" }
114
- @updateState {
112
+ @updateState({
115
113
  "favoriteColor": "blue"
116
- }
117
- @updateState { favoriteColor: "blue" }`;
114
+ })
115
+ @updateState({ favoriteColor: "blue" })`;
118
116
  }
119
117
  getFunctionCallInstructions() {
120
118
  return `A function call is done using the following syntax:
121
- @callback { "name": "callbackName", "options": {} }
122
- Make 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": {} }
119
+ @callbackName({ "key": "value" })
120
+ Make sure to json encode the options. You can call as many callbacks as you want in a single response by including multiple @functionName() lines. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON.
123
121
  Your user-facing message is always sent to the user, even if a callback fails. Successful callbacks have already run successfully. If a callback fails later, do not repeat the same message and do not repeat successful callbacks. Only call the specific callback needed to fix the failed gap.
124
122
  Good example:
125
- @callback { "name": "lookupWeather", "options": { "zip": "80524" } }
123
+ @lookupWeather({ "zip": "80524" })
126
124
  Bad examples:
127
125
  @lookupWeather { "zip": "80524" }
128
- @callback
129
- { "name": "lookupWeather", "options": { "zip": "80524" } }
130
- @callback { "name": "lookupWeather", "options": {
131
- "zip": "80524"
132
- } }`;
126
+ @lookupWeather(
127
+ { "zip": "80524" }
128
+ )
129
+ @lookupWeather({ zip: "80524" })`;
133
130
  }
134
131
  }
@@ -10,9 +10,8 @@ class ResponseParserV2 {
10
10
  let message = response.replace(templates_1.DONE_TOKEN, '').trim();
11
11
  let state = undefined;
12
12
  let callbackResults = undefined;
13
- const hasCallbacks = message.includes('@callback') ||
14
- (callbacks != null &&
15
- Object.keys(callbacks).some((name) => message.includes(`@${name}`)));
13
+ const hasCallbacks = callbacks != null &&
14
+ Object.keys(callbacks).some((name) => message.includes(`@${name}(`));
16
15
  if (hasCallbacks) {
17
16
  const { callbackResults: c, message: m } = await this.invokeCallbacks(message, callbacks);
18
17
  callbackResults = c;
@@ -21,7 +20,7 @@ class ResponseParserV2 {
21
20
  const hasState = response.includes('@updateState');
22
21
  if (hasState && message) {
23
22
  const stateMatches = [
24
- ...message.matchAll(/@updateState\s+({[\s\S]*?})\n?/g),
23
+ ...message.matchAll(/@updateState\(({[\s\S]*?})\)\n?/g),
25
24
  ];
26
25
  for (const stateMatch of stateMatches) {
27
26
  try {
@@ -50,17 +49,16 @@ class ResponseParserV2 {
50
49
  let callbackStrippedMessage = message;
51
50
  let callbackResults = '';
52
51
  const reserved = new Set(['updateState', 'results']);
53
- const matches = [...message.matchAll(/^@(\w+)\s+({.*})$/gm)];
52
+ const matches = [...message.matchAll(/^@(\w+)\(({.*})\)$/gm)];
54
53
  for (const match of matches) {
55
54
  if (reserved.has(match[1])) {
56
55
  continue;
57
56
  }
58
57
  const parsed = JSON.parse(match[2]);
59
- const isCanonical = match[1] === 'callback';
60
- const name = isCanonical ? parsed.name : match[1];
61
- const options = isCanonical ? parsed.options : parsed;
58
+ const name = match[1];
59
+ const options = parsed;
62
60
  const callback = callbacks?.[name];
63
- if (!isCanonical && !callback) {
61
+ if (!callback) {
64
62
  continue;
65
63
  }
66
64
  const parts = callbackStrippedMessage.split(match[0]);
@@ -95,33 +93,32 @@ class ResponseParserV2 {
95
93
  }
96
94
  getStateUpdateInstructions() {
97
95
  return `Updating state works similar to all function calls. Use the following syntax:
98
- @updateState { "field1": "value1", "field2": "value2" }
96
+ @updateState({ "field1": "value1", "field2": "value2" })
99
97
  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.
100
98
  Your user-facing message is always sent to the user, even if @updateState fails. If @updateState fails later, do not repeat the same message. Only send the specific @updateState needed to fix the missing state change.
101
99
  Good example:
102
- @updateState { "favoriteColor": "blue", "firstName": "Taylor" }
100
+ @updateState({ "favoriteColor": "blue", "firstName": "Taylor" })
103
101
  Bad examples:
104
102
  @updateState
105
103
  { "favoriteColor": "blue" }
106
- @updateState {
104
+ @updateState({
107
105
  "favoriteColor": "blue"
108
- }
109
- @updateState { favoriteColor: "blue" }`;
106
+ })
107
+ @updateState({ favoriteColor: "blue" })`;
110
108
  }
111
109
  getFunctionCallInstructions() {
112
110
  return `A function call is done using the following syntax:
113
- @callback { "name": "callbackName", "options": {} }
114
- Make 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": {} }
111
+ @callbackName({ "key": "value" })
112
+ Make sure to json encode the options. You can call as many callbacks as you want in a single response by including multiple @functionName() lines. IMPORTANT: JSON must be on a single line. Do NOT use multi-line or formatted JSON.
115
113
  Your user-facing message is always sent to the user, even if a callback fails. Successful callbacks have already run successfully. If a callback fails later, do not repeat the same message and do not repeat successful callbacks. Only call the specific callback needed to fix the failed gap.
116
114
  Good example:
117
- @callback { "name": "lookupWeather", "options": { "zip": "80524" } }
115
+ @lookupWeather({ "zip": "80524" })
118
116
  Bad examples:
119
117
  @lookupWeather { "zip": "80524" }
120
- @callback
121
- { "name": "lookupWeather", "options": { "zip": "80524" } }
122
- @callback { "name": "lookupWeather", "options": {
123
- "zip": "80524"
124
- } }`;
118
+ @lookupWeather(
119
+ { "zip": "80524" }
120
+ )
121
+ @lookupWeather({ zip: "80524" })`;
125
122
  }
126
123
  }
127
124
  exports.default = ResponseParserV2;
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "eta"
9
9
  ]
10
10
  },
11
- "version": "15.1.11",
11
+ "version": "15.1.12",
12
12
  "files": [
13
13
  "build"
14
14
  ],