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.
- package/.claude/settings.local.json +11 -0
- package/jsconfig.json +1 -1
- package/package.json +1 -1
- package/src/ChatGpt.js +2 -1
- package/src/LLMRouter.js +31 -5
- package/src/LLMSession.js +10 -8
- package/src/LLMType.js +13 -13
|
@@ -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
package/src/ChatGpt.js
CHANGED
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
|
-
}, '
|
|
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
|
|
162
|
+
const session = llm.session('routing')
|
|
163
163
|
.setData(routing)
|
|
164
|
-
.systemPrompt(prompt)
|
|
165
|
-
.generateStructured(LLMRouter.structuredOutput());
|
|
164
|
+
.systemPrompt(prompt);
|
|
166
165
|
|
|
167
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
250
|
-
if (child._required) {
|
|
251
|
-
|
|
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
|
-
|
|
259
|
-
schema.required = required;
|
|
260
|
-
}
|
|
260
|
+
schema.required = required;
|
|
261
261
|
break;
|
|
262
262
|
}
|
|
263
263
|
|