wingbot 3.76.11 → 3.76.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wingbot",
3
- "version": "3.76.11",
3
+ "version": "3.76.13",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
package/src/ChatGpt.js CHANGED
@@ -14,6 +14,7 @@ const LLM = require('./LLM');
14
14
  /** @typedef {import('./Responder').QuickReply} QuickReply */
15
15
  /** @typedef {import('./LLM').LLMMessage} LLMMessage */
16
16
  /** @typedef {import('./LLM').LLMProviderOptions} LLMProviderOptions */
17
+ /** @typedef {import('./LLM').LLMUsage} LLMUsage */
17
18
  /** @typedef {import('./LLMSession').ToolFunction} ToolFunction */
18
19
  /** @typedef {import('./LLMSession').JsonSchemaProp} SimpleJsonSchema */
19
20
 
@@ -285,10 +286,13 @@ class ChatGpt {
285
286
  * @param {LLMMessage[]} prompt
286
287
  * @param {LLMProviderOptions} [options]
287
288
  * @param {ToolFunction[]} [tools=[]]
289
+ * @param {LLMUsage} [usage] - gets filled with the reported token usage
288
290
  * @returns {Promise<LLMMessage>}
289
291
  */
290
- async requestChat (prompt, options, tools = []) {
291
- const choice = await this._request(prompt, options, tools);
292
+ async requestChat (prompt, options, tools = [], usage = {}) {
293
+ const { choice, usage: reportedUsage } = await this._request(prompt, options, tools);
294
+
295
+ Object.assign(usage, reportedUsage);
292
296
 
293
297
  const { finish_reason: finishReason, message } = choice;
294
298
 
@@ -310,7 +314,7 @@ class ChatGpt {
310
314
  * @param {LLMMessage[]} chat
311
315
  * @param {LLMProviderOptions} requestOptions
312
316
  * @param {ToolFunction[]} [tools=[]]
313
- * @returns {Promise<ChatGPTChoice>}
317
+ * @returns {Promise<{choice:ChatGPTChoice, usage:LLMUsage}>}
314
318
  */
315
319
  async _request (chat, requestOptions, tools = []) {
316
320
  const {
@@ -485,11 +489,28 @@ class ChatGpt {
485
489
 
486
490
  const [choice] = responseData.choices;
487
491
 
492
+ const { usage = {}, model: usedModel } = responseData;
493
+ const {
494
+ prompt_tokens: promptTokens,
495
+ completion_tokens: completionTokens,
496
+ prompt_tokens_details: promptDetails = {},
497
+ completion_tokens_details: completionDetails = {}
498
+ } = usage;
499
+
500
+ /** @type {LLMUsage} */
501
+ const llmUsage = {
502
+ model: usedModel,
503
+ promptTokens,
504
+ completionTokens,
505
+ cachedTokens: promptDetails.cached_tokens,
506
+ reasoningTokens: completionDetails.reasoning_tokens
507
+ };
508
+
488
509
  const durationMs = Date.now() - startTime;
489
510
 
490
511
  this._log('#GPT response', { choice, responseData, durationMs });
491
512
 
492
- return choice;
513
+ return { choice, usage: llmUsage };
493
514
  } catch (e) {
494
515
  this._logger.log('#GPT failed', {
495
516
  message: e.message, body, responseText, responseData, status, statusText
@@ -516,7 +537,9 @@ class ChatGpt {
516
537
  { role: 'user', content }
517
538
  ];
518
539
 
519
- return this._request(messages, requestOptions);
540
+ const { choice } = await this._request(messages, requestOptions);
541
+
542
+ return choice;
520
543
  }
521
544
 
522
545
  /**
package/src/LLM.js CHANGED
@@ -88,6 +88,7 @@ const LLMSession = require('./LLMSession');
88
88
  * @param {LLMMessage[]} prompt
89
89
  * @param {LLMProviderOptions} [options]
90
90
  * @param {ToolFunction[]} [tools]
91
+ * @param {LLMUsage} [usage] - gets filled with the reported token usage
91
92
  * @returns {Promise<LLMMessage>}
92
93
  */
93
94
 
@@ -158,6 +159,15 @@ const LLMSession = require('./LLMSession');
158
159
  * @prop {RegExp} regex
159
160
  */
160
161
 
162
+ /**
163
+ * @typedef {object} LLMUsage
164
+ * @prop {string} [model]
165
+ * @prop {number} [promptTokens]
166
+ * @prop {number} [cachedTokens]
167
+ * @prop {number} [completionTokens]
168
+ * @prop {number} [reasoningTokens]
169
+ */
170
+
161
171
  /**
162
172
  * @typedef {object} PromptInfo
163
173
  * @prop {LLMMessage[]} prompt
@@ -167,6 +177,7 @@ const LLMSession = require('./LLMSession');
167
177
  * @prop {number} [durationMs]
168
178
  * @prop {LLMCallOptions} [options]
169
179
  * @prop {string} [error]
180
+ * @prop {LLMUsage} [usage]
170
181
  */
171
182
 
172
183
  /**
@@ -443,8 +454,10 @@ class LLM {
443
454
  const startTime = Date.now();
444
455
  let result = null;
445
456
  let error = null;
457
+ /** @type {LLMUsage} */
458
+ const usage = {};
446
459
  try {
447
- result = await this._provider.requestChat(prompt, opts, session.tools);
460
+ result = await this._provider.requestChat(prompt, opts, session.tools, usage);
448
461
  } catch (e) {
449
462
  error = e;
450
463
  }
@@ -456,7 +469,8 @@ class LLM {
456
469
  session.tools,
457
470
  durationMs,
458
471
  opts,
459
- error
472
+ error,
473
+ Object.keys(usage).length ? usage : null
460
474
  );
461
475
  if (error) throw error;
462
476
  return result;
@@ -471,8 +485,9 @@ class LLM {
471
485
  * @param {number} [durationMs]
472
486
  * @param {LLMCallOptions} [options]
473
487
  * @param {Error} [error]
488
+ * @param {LLMUsage} [usage]
474
489
  */
475
- logPrompt (prompt, result, vectorSearchResult, tools, durationMs, options, error) {
490
+ logPrompt (prompt, result, vectorSearchResult, tools, durationMs, options, error, usage) {
476
491
  this._lastResult = result;
477
492
  this._configuration.logger.logPrompt({
478
493
  prompt,
@@ -481,6 +496,7 @@ class LLM {
481
496
  tools,
482
497
  durationMs,
483
498
  ...(options != null && { options }),
499
+ ...(usage != null && { usage }),
484
500
  ...(error != null && { error: error?.message || String(error) })
485
501
  });
486
502
  }
package/src/Responder.js CHANGED
@@ -911,6 +911,52 @@ class Responder {
911
911
  this.routePath = routePath;
912
912
  }
913
913
 
914
+ /**
915
+ *
916
+ * @param {Object.<string,string|QuickReply>|QuickReply[]} [replies] - quick replies
917
+ * @param {object} [messageData]
918
+ * @returns {QuickReply[]}
919
+ */
920
+ resolveQuickRepliesForAnswer (replies = null, messageData = null) {
921
+ if (!replies && this._quickReplyCollector.length === 0) {
922
+ return [];
923
+ }
924
+
925
+ const {
926
+ quickReplies: qrs, expectedKeywords, disambiguationIntents
927
+ } = makeQuickReplies(
928
+ replies,
929
+ this.path,
930
+ this._t,
931
+ this._quickReplyCollector,
932
+ Ai.ai,
933
+ this.currentAction()
934
+ );
935
+
936
+ if (!messageData) {
937
+ return qrs;
938
+ }
939
+
940
+ if (disambiguationIntents.length > 0) {
941
+ this._senderMeta = {
942
+ flag: ResponseFlag.DISAMBIGUATION_OFFERED,
943
+ disambiguationIntents
944
+ };
945
+ }
946
+
947
+ if (qrs.length > 0) {
948
+ this.finalMessageSent = true;
949
+ Object.assign(messageData.message, {
950
+ quick_replies: qrs
951
+ });
952
+
953
+ this._addExpectedIntents(expectedKeywords);
954
+ this._quickReplyCollector = [];
955
+ }
956
+
957
+ return qrs;
958
+ }
959
+
914
960
  /**
915
961
  * @typedef {object} MessageOptions
916
962
  * @prop {boolean} [disableAutoTyping]
@@ -953,27 +999,7 @@ class Responder {
953
999
 
954
1000
  this._textResponses.push(text);
955
1001
 
956
- if (replies || this._quickReplyCollector.length !== 0) {
957
- const qrc = this._quickReplyCollector;
958
- const {
959
- quickReplies: qrs, expectedKeywords, disambiguationIntents
960
- } = makeQuickReplies(replies, this.path, this._t, qrc, Ai.ai, this.currentAction());
961
-
962
- if (disambiguationIntents.length > 0) {
963
- this._senderMeta = {
964
- flag: ResponseFlag.DISAMBIGUATION_OFFERED,
965
- disambiguationIntents
966
- };
967
- }
968
-
969
- if (qrs.length > 0) {
970
- this.finalMessageSent = true;
971
- messageData.message.quick_replies = qrs;
972
-
973
- this._addExpectedIntents(expectedKeywords);
974
- this._quickReplyCollector = [];
975
- }
976
- }
1002
+ this.resolveQuickRepliesForAnswer(replies, messageData);
977
1003
 
978
1004
  if (this._features.includes(FEATURE_VOICE)
979
1005
  && (voice || this.voiceControl)) {
@@ -129,6 +129,14 @@ type ToolFunction {
129
129
  parameters: Any
130
130
  }
131
131
 
132
+ type LLMUsage {
133
+ model: String
134
+ promptTokens: Float
135
+ cachedTokens: Float
136
+ completionTokens: Float
137
+ reasoningTokens: Float
138
+ }
139
+
132
140
  type PromptInfo {
133
141
  prompt: [LLMMessage!]!
134
142
  result: LLMMessage
@@ -137,6 +145,7 @@ type PromptInfo {
137
145
  durationMs: Float
138
146
  options: Any
139
147
  error: String
148
+ usage: LLMUsage
140
149
  }
141
150
 
142
151
  type UserInteraction {
package/src/prompt.js CHANGED
@@ -93,7 +93,9 @@ function prompt (strings, ...args) {
93
93
 
94
94
  const renderer = async (req, res = null) => {
95
95
  const reqIsRequest = 'action' in req && typeof req.action === 'function';
96
+ const reqIsResponder = typeof req?.send === 'function';
96
97
  const data = {
98
+ ...(reqIsResponder ? stateData(null, req) : {}),
97
99
  ...(reqIsRequest ? stateData(req, res) : req),
98
100
  ...inputData
99
101
  };
@@ -446,6 +446,10 @@ function message (params, context = {}) {
446
446
  };
447
447
  }
448
448
 
449
+ res.setData({
450
+ _qRepliesToSend: sendReplies || []
451
+ });
452
+
449
453
  if (params.type === 'prompt' && !res.llm.configuration.disableLLM) {
450
454
  res.typingOn()
451
455
  .wait(1000);
@@ -122,14 +122,15 @@ function makeQuickReplies (replies, path = '', translate = (w) => w, quickReplyC
122
122
 
123
123
  let unshift = 0;
124
124
  quickReplyCollector.forEach((reply) => {
125
- if (reply._justToExisting) {
126
- delete reply._justToExisting; // eslint-disable-line no-param-reassign
125
+ const clear = { ...reply };
126
+ if (clear._justToExisting) {
127
+ delete clear._justToExisting;
127
128
  }
128
- if (reply._prepend) {
129
- delete reply._prepend; // eslint-disable-line no-param-reassign
130
- iterate.splice(unshift++, 0, reply);
129
+ if (clear._prepend) {
130
+ delete clear._prepend;
131
+ iterate.splice(unshift++, 0, clear);
131
132
  } else {
132
- iterate.push(reply);
133
+ iterate.push(clear);
133
134
  }
134
135
  });
135
136
 
@@ -56,6 +56,16 @@ module.exports = function stateData (
56
56
  state: res.options.state
57
57
  };
58
58
 
59
+ let $qrTexts;
60
+
61
+ if (typeof res?.resolveQuickRepliesForAnswer === 'function') {
62
+ $qrTexts = res?.resolveQuickRepliesForAnswer(res.data._qRepliesToSend || [])
63
+ .filter((r) => r.title)
64
+ .map((r) => r.title);
65
+ } else {
66
+ $qrTexts = [];
67
+ }
68
+
59
69
  return {
60
70
  senderId,
61
71
  pageId,
@@ -73,6 +83,7 @@ module.exports = function stateData (
73
83
  // yes - res because of circular dependency
74
84
  ...(res && req && req.actionData()),
75
85
  ...(res ? res.data : {}),
76
- $input: $this
86
+ $input: $this,
87
+ $qrTexts
77
88
  };
78
89
  };