wingbot 3.75.9-alpha.1 → 3.75.9-alpha.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.
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npx mocha:*)",
5
+ "Bash(npx tsc *)",
6
+ "Bash(npm test *)",
7
+ "Bash(node -e \"const p = require\\('./bot/plugins/BTMLLM'\\); console.log\\('factory type:', typeof p\\); console.log\\('factory name:', p.name\\);\")",
8
+ "Bash(grep -n \"prompt\\\\`\\\\|tagged\\\\|render\\\\|compile\\\\|hbs\" /Users/ondrejveres/Wingbot/wingbot-llm/src/prompt.js)"
9
+ ]
10
+ }
11
+ }
package/jsconfig.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "module": "commonjs",
4
- "lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string", "dom"],
4
+ "lib": ["es2019", "es2020.promise", "es2020.bigint", "es2020.string", "es2022.error", "dom"],
5
5
  "target": "ESNext",
6
6
  "allowSyntheticDefaultImports": true,
7
7
  "checkJs": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wingbot",
3
- "version": "3.75.9-alpha.1",
3
+ "version": "3.75.9-alpha.3",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
package/src/ChatGpt.js CHANGED
@@ -373,7 +373,8 @@ class ChatGpt {
373
373
  type: 'json_schema',
374
374
  json_schema: {
375
375
  name,
376
- schema
376
+ schema,
377
+ strict: true
377
378
  }
378
379
  };
379
380
  } else if (typeof responseFormat === 'string') {
package/src/LLMRouter.js CHANGED
@@ -143,7 +143,7 @@ class LLMRouter {
143
143
  .object({
144
144
  action: LLMType.string()
145
145
  .description('recommended action')
146
- }, 'conversation routing information')
146
+ }, 'conversation_routing_information')
147
147
  .toJSON();
148
148
  }
149
149
  return LLMRouter._cachedStructuredOutput;
@@ -159,12 +159,34 @@ class LLMRouter {
159
159
  static defaultRoute (prompt) {
160
160
  /** @type {RouterResolver} */
161
161
  const route = async (llm, req, routing) => {
162
- const res = await llm.session('routing')
162
+ const session = llm.session('routing')
163
163
  .setData(routing)
164
- .systemPrompt(prompt)
165
- .generateStructured(LLMRouter.structuredOutput());
164
+ .systemPrompt(prompt);
166
165
 
167
- if (!routing.byAction.has(LLMRouter._normByAction(res.action))) {
166
+ const userText = typeof req?.text === 'function' ? req.text() : null;
167
+ if (userText) {
168
+ session.user(userText);
169
+ }
170
+
171
+ let res;
172
+ try {
173
+ res = await session.generateStructured(LLMRouter.structuredOutput());
174
+ } catch (e) {
175
+ // Fail closed: any error in routing classification is treated
176
+ // as "no context change" so the user's current flow continues.
177
+ // Surfaces to Sentry via the host-configured logger.
178
+ llm.log?.error('LLMRouter classification failed', e, {
179
+ // userText,
180
+ candidateActions: routing?.byAction
181
+ ? Array.from(routing.byAction.keys())
182
+ : [],
183
+ senderId: req?.senderId ?? null,
184
+ pageId: req?.pageId ?? null
185
+ });
186
+ return null;
187
+ }
188
+
189
+ if (!res || !routing.byAction.has(LLMRouter._normByAction(res.action))) {
168
190
  return null;
169
191
  }
170
192
 
@@ -226,6 +248,10 @@ class LLMRouter {
226
248
  });
227
249
  }
228
250
 
251
+ /**
252
+ * @param {string} act
253
+ * @returns {string}
254
+ */
229
255
  static _normByAction (act) {
230
256
  return act.replace(/^\/|\/$/g, '');
231
257
  }
package/src/LLMSession.js CHANGED
@@ -118,7 +118,6 @@ const stateData = require('./utils/stateData');
118
118
  * @prop {string} name - The function name
119
119
  * @prop {string} [description] - What the function does
120
120
  * @prop {FnParamsObject} [parameters] - Parameter schema
121
- * @prop {boolean} [strict]
122
121
  */
123
122
 
124
123
  /**
@@ -351,19 +350,15 @@ class LLMSession {
351
350
  .map(({
352
351
  name,
353
352
  description = null,
354
- parameters = {},
355
- strict = true
353
+ parameters = {}
356
354
  }) => ({
357
355
  name,
358
356
  ...(description && { description }),
359
- ...(typeof strict === 'boolean' ? { strict } : {}),
357
+ strict: true,
360
358
  parameters: {
361
359
  type: 'object',
362
360
  properties: {},
363
361
  additionalProperties: false,
364
- required: 'properties' in parameters
365
- ? Object.keys(parameters.properties)
366
- : [],
367
362
  ...parameters
368
363
  }
369
364
  }));
@@ -847,7 +842,14 @@ class LLMSession {
847
842
  responseFormat
848
843
  }, logOptions);
849
844
 
850
- return JSON.parse(result.content);
845
+ try {
846
+ return JSON.parse(result.content);
847
+ } catch (e) {
848
+ throw new Error(
849
+ `LLM structured output is not valid JSON: ${e.message}. Raw content: ${JSON.stringify(result.content)}`,
850
+ { cause: e }
851
+ );
852
+ }
851
853
  });
852
854
  return this;
853
855
  }
package/src/LLMType.js CHANGED
@@ -196,10 +196,11 @@ class LLMType {
196
196
  }
197
197
 
198
198
  /**
199
- * Marks field as optional when used as an object property.
199
+ * Marks field as optional when used as an object property. In the
200
+ * generated schema this surfaces as a nullable type (e.g. `['string', 'null']`)
201
+ * — strict mode still requires the key to be present, just allows `null`.
200
202
  *
201
- * When used outside object-property context, it has no practical effect,
202
- * because requiredness is evaluated by parent object schemas.
203
+ * Outside an object-property context it has no practical effect.
203
204
  *
204
205
  * @example
205
206
  * const input = LLMType.object({
@@ -215,10 +216,9 @@ class LLMType {
215
216
  }
216
217
 
217
218
  /**
218
- * Returns JSON Schema representation.
219
- *
220
- * For object schemas, nested properties are resolved recursively by calling
221
- * `toJSON()` on each nested `LLMType` instance.
219
+ * Returns JSON Schema representation in OpenAI strict-mode form:
220
+ * every property is listed in `required`, and properties marked
221
+ * `optional()` are made nullable instead of being dropped from `required`.
222
222
  *
223
223
  * @example
224
224
  * const schema = LLMType.object({
@@ -246,18 +246,18 @@ class LLMType {
246
246
  const properties = {};
247
247
  const required = [];
248
248
  Object.entries(this._properties).forEach(([key, child]) => {
249
- properties[key] = child.toJSON();
250
- if (child._required) {
251
- required.push(key);
249
+ const childSchema = child.toJSON();
250
+ if (!child._required) {
251
+ childSchema.type = [childSchema.type, 'null'];
252
252
  }
253
+ properties[key] = childSchema;
254
+ required.push(key);
253
255
  });
254
256
 
255
257
  schema.type = 'object';
256
258
  schema.properties = properties;
257
259
  schema.additionalProperties = false;
258
- if (required.length > 0) {
259
- schema.required = required;
260
- }
260
+ schema.required = required;
261
261
  break;
262
262
  }
263
263