@saltcorn/large-language-model 0.6.3 → 0.6.5

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.
Files changed (2) hide show
  1. package/index.js +223 -5
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -227,10 +227,16 @@ module.exports = {
227
227
  type: "String",
228
228
  required: true,
229
229
  },
230
+ {
231
+ name: "chat_history_field",
232
+ label: "Chat history variable",
233
+ sublabel:
234
+ "Use this context variable to store the chat history for subsequent prompts",
235
+ type: "String",
236
+ },
230
237
  ...override_fields,
231
238
  ];
232
- }
233
- if (table) {
239
+ } else if (table) {
234
240
  const textFields = table.fields
235
241
  .filter((f) => f.type?.sql_name === "text")
236
242
  .map((f) => f.name);
@@ -273,6 +279,7 @@ module.exports = {
273
279
  prompt_template,
274
280
  answer_field,
275
281
  override_config,
282
+ chat_history_field,
276
283
  },
277
284
  }) => {
278
285
  let prompt;
@@ -296,9 +303,220 @@ module.exports = {
296
303
  opts.api_key = altcfg.api_key;
297
304
  opts.bearer = altcfg.bearer;
298
305
  }
299
- const ans = await getCompletion(config, { prompt, ...opts });
300
- if (mode === "workflow") return { [answer_field]: ans };
301
- else await table.updateRow({ [answer_field]: ans }, row[table.pk_name]);
306
+ let history = [];
307
+ if (chat_history_field && row[chat_history_field]) {
308
+ history = row[chat_history_field];
309
+ }
310
+ const ans = await getCompletion(config, {
311
+ prompt,
312
+ chat: history,
313
+ ...opts,
314
+ });
315
+ const upd = { [answer_field]: ans };
316
+ if (chat_history_field) {
317
+ upd[chat_history_field] = [
318
+ ...history,
319
+ { role: "user", content: prompt },
320
+ { role: "system", content: ans },
321
+ ];
322
+ }
323
+ if (mode === "workflow") return upd;
324
+ else await table.updateRow(upd, row[table.pk_name]);
325
+ },
326
+ },
327
+ llm_generate_json: {
328
+ requireRow: true,
329
+ configFields: ({ table, mode }) => {
330
+ const override_fields =
331
+ config.backend === "OpenAI-compatible API" &&
332
+ (config.altconfigs || []).filter((c) => c.name).length
333
+ ? [
334
+ {
335
+ name: "override_config",
336
+ label: "Alternative LLM configuration",
337
+ type: "String",
338
+ attributes: { options: config.altconfigs.map((c) => c.name) },
339
+ },
340
+ ]
341
+ : [];
342
+ const cfgFields = [];
343
+ const fieldsField = new FieldRepeat({
344
+ name: "fields",
345
+ fields: [
346
+ {
347
+ name: "name",
348
+ label: "Name",
349
+ sublabel: "The field name, as a valid JavaScript identifier",
350
+ type: "String",
351
+ required: true,
352
+ },
353
+ {
354
+ label: "Description",
355
+ name: "description",
356
+ sublabel: "A description of the field.",
357
+ type: "String",
358
+ },
359
+ {
360
+ name: "type",
361
+ label: "Type",
362
+ type: "String",
363
+ required: true,
364
+ attributes: {
365
+ options: ["string", "integer", "number", "boolean"],
366
+ },
367
+ },
368
+ ],
369
+ });
370
+
371
+ if (mode === "workflow") {
372
+ cfgFields.push(
373
+ {
374
+ name: "prompt_template",
375
+ label: "Prompt",
376
+ sublabel:
377
+ "Prompt text. Use interpolations {{ }} to access variables in the context",
378
+ type: "String",
379
+ fieldview: "textarea",
380
+ required: true,
381
+ },
382
+ {
383
+ name: "answer_field",
384
+ label: "Answer variable",
385
+ sublabel: "Set the generated answer to this context variable",
386
+ type: "String",
387
+ required: true,
388
+ },
389
+ {
390
+ name: "chat_history_field",
391
+ label: "Chat history variable",
392
+ sublabel:
393
+ "Use this context variable to store the chat history for subsequent prompts",
394
+ type: "String",
395
+ }
396
+ );
397
+ } else if (table) {
398
+ const jsonFields = table.fields
399
+ .filter((f) => f.type?.name === "JSON")
400
+ .map((f) => f.name);
401
+
402
+ cfgFields.push(
403
+ {
404
+ name: "prompt_template",
405
+ label: "Prompt",
406
+ sublabel:
407
+ "Prompt text. Use interpolations {{ }} to access variables in the row",
408
+ type: "String",
409
+ fieldview: "textarea",
410
+ required: true,
411
+ },
412
+ {
413
+ name: "answer_field",
414
+ label: "Answer field",
415
+ sublabel: "Output field will be set to the generated data",
416
+ type: "String",
417
+ required: true,
418
+ attributes: { options: jsonFields },
419
+ }
420
+ );
421
+ }
422
+
423
+ cfgFields.push(
424
+ ...override_fields,
425
+ {
426
+ name: "multiple",
427
+ label: "Multiple",
428
+ type: "Bool",
429
+ sublabel:
430
+ "Select to generate an array of objects. Unselect for a single object",
431
+ },
432
+ {
433
+ name: "gen_description",
434
+ label: "Description",
435
+ sublabel: "A short description of what you want to generate.",
436
+ type: "String",
437
+ },
438
+ {
439
+ input_type: "section_header",
440
+ label: "JSON fields to generate",
441
+ },
442
+ fieldsField
443
+ );
444
+ return cfgFields;
445
+ },
446
+ run: async ({
447
+ row,
448
+ table,
449
+ user,
450
+ mode,
451
+ configuration: {
452
+ prompt_template,
453
+ fields,
454
+ mulitple,
455
+ gen_description,
456
+ answer_field,
457
+ override_config,
458
+ chat_history_field,
459
+ },
460
+ }) => {
461
+ let prompt = interpolate(prompt_template, row, user);
462
+
463
+ const opts = {};
464
+ if (override_config) {
465
+ const altcfg = config.altconfigs.find(
466
+ (c) => c.name === override_config
467
+ );
468
+ opts.endpoint = altcfg.endpoint;
469
+ opts.model = altcfg.model;
470
+ opts.api_key = altcfg.api_key;
471
+ opts.bearer = altcfg.bearer;
472
+ }
473
+ let history = [];
474
+ if (chat_history_field && row[chat_history_field]) {
475
+ history = row[chat_history_field];
476
+ }
477
+ const fieldArgs = {};
478
+ (fields || []).forEach((field) => {
479
+ fieldArgs[field.name] = {
480
+ type: field.type,
481
+ description: field.description,
482
+ };
483
+ });
484
+ const argObj = { type: "object", properties: fieldArgs };
485
+ const args = {
486
+ [answer_field]: mulitple ? { type: "array", items: argObj } : argObj,
487
+ };
488
+ const expert_function = {
489
+ type: "function",
490
+ function: {
491
+ name: answer_field,
492
+ description: gen_description || undefined,
493
+ parameters: {
494
+ type: "object",
495
+ properties: args,
496
+ },
497
+ },
498
+ };
499
+ const toolargs = {
500
+ tools: [expert_function],
501
+ tool_choice: { type: "function", function: { name: answer_field } },
502
+ };
503
+ const compl = await getCompletion(config, {
504
+ prompt,
505
+ chat: history,
506
+ ...opts,
507
+ ...toolargs,
508
+ });
509
+ const ans = JSON.parse(compl.tool_calls[0].function.arguments)[answer_field];
510
+ const upd = { [answer_field]: ans };
511
+ if (chat_history_field) {
512
+ upd[chat_history_field] = [
513
+ ...history,
514
+ { role: "user", content: prompt },
515
+ { role: "system", content: ans },
516
+ ];
517
+ }
518
+ if (mode === "workflow") return upd;
519
+ else await table.updateRow(upd, row[table.pk_name]);
302
520
  },
303
521
  },
304
522
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/large-language-model",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "Large language models and functionality for Saltcorn",
5
5
  "main": "index.js",
6
6
  "dependencies": {