@sprucelabs/sprucebot-llm 15.1.4 → 15.1.6

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.
package/README.md CHANGED
@@ -362,16 +362,21 @@ const skill = bots.Skill({
362
362
  ```
363
363
 
364
364
  #### Callback invocation format
365
- When using the `OpenAiAdapter`, the model is instructed to call callbacks using one of these formats:
365
+ The model is instructed to invoke callbacks using the following syntax (V2 format):
366
366
 
367
367
  ```text
368
- <<functionName/>>
369
- <<functionName>>{"param":"value"}<</functionName>>
368
+ @callback { "name": "callbackName", "options": {} }
370
369
  ```
371
370
 
372
- Only one callback invocation per model response is supported. Callbacks can return either a `string` or an image message shaped like `{ imageBase64, imageDescription }` (see the "Sending images" section below).
371
+ Multiple callbacks can be included in a single response, one per line. JSON must be on a single line do not use multi-line or formatted JSON.
373
372
 
374
- Legacy placeholder format (`xxxxx callbackName xxxxx`) is still supported by the response parser for older prompt templates.
373
+ As a shorthand, you can also invoke a named callback directly:
374
+
375
+ ```text
376
+ @myCallback { "param": "value" }
377
+ ```
378
+
379
+ Callbacks can return either a `string` or an image message shaped like `{ imageBase64, imageDescription }` (see the "Sending images" section below).
375
380
 
376
381
  Callback parameters can include basic types (e.g. `text`, `number`, `boolean`, `dateMs`, `dateTimeMs`) and `select` fields with choices from `@sprucelabs/schema`.
377
382
 
@@ -6,3 +6,4 @@ export default class ResponseParserV2 implements ResponseParser {
6
6
  getStateUpdateInstructions(): string;
7
7
  getFunctionCallInstructions(): string;
8
8
  }
9
+ export type ParserCallbackStyle = '@callback' | '@functionCall';
@@ -15,7 +15,9 @@ 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');
18
+ const hasCallbacks = message.includes('@callback') ||
19
+ (callbacks != null &&
20
+ Object.keys(callbacks).some((name) => message.includes(`@${name}`)));
19
21
  if (hasCallbacks) {
20
22
  const { callbackResults: c, message: m } = yield this.invokeCallbacks(message, callbacks);
21
23
  callbackResults = c;
@@ -52,28 +54,31 @@ export default class ResponseParserV2 {
52
54
  return __awaiter(this, void 0, void 0, function* () {
53
55
  let callbackStrippedMessage = message;
54
56
  let callbackResults = '';
55
- const matches = [...message.matchAll(/^@callback\s+({.*})$/gm)];
57
+ const reserved = new Set(['updateState', 'results']);
58
+ const matches = [...message.matchAll(/^@(\w+)\s+({.*})$/gm)];
56
59
  for (const match of matches) {
57
- const callbackData = match && match[1] ? JSON.parse(match[1]) : null;
58
- const { name, options } = callbackData || {};
59
- debugger;
60
- if (match) {
61
- const parts = callbackStrippedMessage.split(match[0]);
62
- callbackStrippedMessage = parts
63
- .map((s) => s.trim())
64
- .join('')
65
- .trim();
60
+ if (reserved.has(match[1])) {
61
+ continue;
66
62
  }
63
+ const parsed = JSON.parse(match[2]);
64
+ const isCanonical = match[1] === 'callback';
65
+ const name = isCanonical ? parsed.name : match[1];
66
+ const options = isCanonical ? parsed.options : parsed;
67
+ const callback = callbacks === null || callbacks === void 0 ? void 0 : callbacks[name];
68
+ if (!isCanonical && !callback) {
69
+ continue;
70
+ }
71
+ const parts = callbackStrippedMessage.split(match[0]);
72
+ callbackStrippedMessage = parts
73
+ .map((s) => s.trim())
74
+ .join('')
75
+ .trim();
67
76
  try {
68
- const callback = callbacks === null || callbacks === void 0 ? void 0 : callbacks[name];
69
77
  if (callback === null || callback === void 0 ? void 0 : callback.parameters) {
70
78
  validateAndNormalizeCallbackOptions(callback.parameters, options);
71
79
  }
72
80
  const results = yield (callback === null || callback === void 0 ? void 0 : callback.cb(options));
73
- callbackResults += this.renderCallbackResults({
74
- name,
75
- results,
76
- });
81
+ callbackResults += this.renderCallbackResults({ name, results });
77
82
  }
78
83
  catch (err) {
79
84
  callbackResults += this.renderCallbackResults({
@@ -6,3 +6,4 @@ export default class ResponseParserV2 implements ResponseParser {
6
6
  getStateUpdateInstructions(): string;
7
7
  getFunctionCallInstructions(): string;
8
8
  }
9
+ export type ParserCallbackStyle = '@callback' | '@functionCall';
@@ -10,7 +10,9 @@ 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');
13
+ const hasCallbacks = message.includes('@callback') ||
14
+ (callbacks != null &&
15
+ Object.keys(callbacks).some((name) => message.includes(`@${name}`)));
14
16
  if (hasCallbacks) {
15
17
  const { callbackResults: c, message: m } = await this.invokeCallbacks(message, callbacks);
16
18
  callbackResults = c;
@@ -45,28 +47,31 @@ class ResponseParserV2 {
45
47
  async invokeCallbacks(message, callbacks) {
46
48
  let callbackStrippedMessage = message;
47
49
  let callbackResults = '';
48
- const matches = [...message.matchAll(/^@callback\s+({.*})$/gm)];
50
+ const reserved = new Set(['updateState', 'results']);
51
+ const matches = [...message.matchAll(/^@(\w+)\s+({.*})$/gm)];
49
52
  for (const match of matches) {
50
- const callbackData = match && match[1] ? JSON.parse(match[1]) : null;
51
- const { name, options } = callbackData || {};
52
- debugger;
53
- if (match) {
54
- const parts = callbackStrippedMessage.split(match[0]);
55
- callbackStrippedMessage = parts
56
- .map((s) => s.trim())
57
- .join('')
58
- .trim();
53
+ if (reserved.has(match[1])) {
54
+ continue;
59
55
  }
56
+ const parsed = JSON.parse(match[2]);
57
+ const isCanonical = match[1] === 'callback';
58
+ const name = isCanonical ? parsed.name : match[1];
59
+ const options = isCanonical ? parsed.options : parsed;
60
+ const callback = callbacks?.[name];
61
+ if (!isCanonical && !callback) {
62
+ continue;
63
+ }
64
+ const parts = callbackStrippedMessage.split(match[0]);
65
+ callbackStrippedMessage = parts
66
+ .map((s) => s.trim())
67
+ .join('')
68
+ .trim();
60
69
  try {
61
- const callback = callbacks?.[name];
62
70
  if (callback?.parameters) {
63
71
  (0, validateAndNormalizeCallbackOptions_1.default)(callback.parameters, options);
64
72
  }
65
73
  const results = await callback?.cb(options);
66
- callbackResults += this.renderCallbackResults({
67
- name,
68
- results,
69
- });
74
+ callbackResults += this.renderCallbackResults({ name, results });
70
75
  }
71
76
  catch (err) {
72
77
  callbackResults += this.renderCallbackResults({
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "eta"
9
9
  ]
10
10
  },
11
- "version": "15.1.4",
11
+ "version": "15.1.6",
12
12
  "files": [
13
13
  "build"
14
14
  ],