@botpress/zai 1.0.1 → 1.1.0

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 (47) hide show
  1. package/dist/adapters/adapter.js +2 -0
  2. package/dist/adapters/botpress-table.js +168 -0
  3. package/dist/adapters/memory.js +12 -0
  4. package/dist/index.d.ts +99 -98
  5. package/dist/index.js +9 -1873
  6. package/dist/models.js +387 -0
  7. package/dist/operations/check.js +141 -0
  8. package/dist/operations/constants.js +2 -0
  9. package/dist/operations/errors.js +15 -0
  10. package/dist/operations/extract.js +212 -0
  11. package/dist/operations/filter.js +179 -0
  12. package/dist/operations/label.js +237 -0
  13. package/dist/operations/rewrite.js +111 -0
  14. package/dist/operations/summarize.js +132 -0
  15. package/dist/operations/text.js +46 -0
  16. package/dist/utils.js +43 -0
  17. package/dist/zai.js +140 -0
  18. package/package.json +21 -19
  19. package/src/adapters/adapter.ts +35 -0
  20. package/src/adapters/botpress-table.ts +210 -0
  21. package/src/adapters/memory.ts +13 -0
  22. package/src/index.ts +11 -0
  23. package/src/models.ts +394 -0
  24. package/src/operations/__tests/botpress_docs.txt +26040 -0
  25. package/src/operations/__tests/cache.jsonl +101 -0
  26. package/src/operations/__tests/index.ts +87 -0
  27. package/src/operations/check.ts +187 -0
  28. package/src/operations/constants.ts +2 -0
  29. package/src/operations/errors.ts +9 -0
  30. package/src/operations/extract.ts +291 -0
  31. package/src/operations/filter.ts +231 -0
  32. package/src/operations/label.ts +332 -0
  33. package/src/operations/rewrite.ts +148 -0
  34. package/src/operations/summarize.ts +193 -0
  35. package/src/operations/text.ts +63 -0
  36. package/src/sdk-interfaces/llm/generateContent.ts +127 -0
  37. package/src/sdk-interfaces/llm/listLanguageModels.ts +19 -0
  38. package/src/utils.ts +61 -0
  39. package/src/zai.ts +193 -0
  40. package/tsconfig.json +2 -2
  41. package/dist/index.cjs +0 -1903
  42. package/dist/index.cjs.map +0 -1
  43. package/dist/index.d.cts +0 -916
  44. package/dist/index.js.map +0 -1
  45. package/tsup.config.ts +0 -16
  46. package/vitest.config.ts +0 -9
  47. package/vitest.setup.ts +0 -24
package/dist/index.cjs DELETED
@@ -1,1903 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- Zai: () => Zai
34
- });
35
- module.exports = __toCommonJS(index_exports);
36
-
37
- // src/zai.ts
38
- var import_sdk3 = __toESM(require("@botpress/sdk"), 1);
39
- var import_wasm = require("@botpress/wasm");
40
-
41
- // src/adapters/botpress-table.ts
42
- var import_sdk2 = __toESM(require("@botpress/sdk"), 1);
43
-
44
- // src/utils.ts
45
- var import_sdk = __toESM(require("@botpress/sdk"), 1);
46
- var { z } = import_sdk.default;
47
- var stringify = /* @__PURE__ */ __name((input, beautify = true) => {
48
- return typeof input === "string" && !!input.length ? input : input ? JSON.stringify(input, beautify ? null : void 0, beautify ? 2 : void 0) : "<input is null, false, undefined or empty>";
49
- }, "stringify");
50
- var BotpressClient = z.custom(
51
- (value) => typeof value === "object" && value !== null && "callAction" in value && typeof value.callAction === "function",
52
- {
53
- message: "Invalid Botpress Client. Make sure to pass an instance of @botpress/client"
54
- }
55
- );
56
- function fastHash(str) {
57
- let hash = 0;
58
- for (let i = 0; i < str.length; i++) {
59
- hash = (hash << 5) - hash + str.charCodeAt(i);
60
- hash |= 0;
61
- }
62
- return (hash >>> 0).toString(16);
63
- }
64
- __name(fastHash, "fastHash");
65
- var takeUntilTokens = /* @__PURE__ */ __name((arr, tokens, count) => {
66
- const result = [];
67
- let total = 0;
68
- for (const value of arr) {
69
- const valueTokens = count(value);
70
- if (total + valueTokens > tokens) {
71
- break;
72
- }
73
- total += valueTokens;
74
- result.push(value);
75
- }
76
- return result;
77
- }, "takeUntilTokens");
78
- var GenerationMetadata = z.object({
79
- model: z.string(),
80
- cost: z.object({
81
- input: z.number(),
82
- output: z.number()
83
- }).describe("Cost in $USD"),
84
- latency: z.number().describe("Latency in milliseconds"),
85
- tokens: z.object({
86
- input: z.number(),
87
- output: z.number()
88
- }).describe("Number of tokens used")
89
- });
90
-
91
- // src/adapters/adapter.ts
92
- var Adapter = class {
93
- static {
94
- __name(this, "Adapter");
95
- }
96
- };
97
-
98
- // src/adapters/botpress-table.ts
99
- var { z: z2 } = import_sdk2.default;
100
- var CRITICAL_TAGS = {
101
- system: "true",
102
- "schema-purpose": "active-learning",
103
- "schema-version": "Oct-2024"
104
- };
105
- var OPTIONAL_TAGS = {
106
- "x-studio-title": "Active Learning",
107
- "x-studio-description": "Table for storing active learning tasks and examples",
108
- "x-studio-readonly": "true",
109
- "x-studio-icon": "lucide://atom",
110
- "x-studio-color": "green"
111
- };
112
- var FACTOR = 30;
113
- var Props = z2.object({
114
- client: BotpressClient,
115
- tableName: z2.string().regex(
116
- /^[a-zA-Z0-9_]{1,45}Table$/,
117
- "Table name must be lowercase and contain only letters, numbers and underscores"
118
- )
119
- });
120
- var TableSchema = z2.object({
121
- taskType: z2.string().describe("The type of the task (filter, extract, etc.)"),
122
- taskId: z2.string(),
123
- key: z2.string().describe("A unique key for the task (e.g. a hash of the input, taskId, taskType and instructions)"),
124
- instructions: z2.string(),
125
- input: z2.object({}).passthrough().describe("The input to the task"),
126
- output: z2.object({}).passthrough().describe("The expected output"),
127
- explanation: z2.string().nullable(),
128
- metadata: GenerationMetadata,
129
- status: z2.enum(["pending", "rejected", "approved"]),
130
- feedback: z2.object({
131
- rating: z2.enum(["very-bad", "bad", "good", "very-good"]),
132
- comment: z2.string().nullable()
133
- }).nullable().default(null)
134
- });
135
- var searchableColumns = ["input"];
136
- var TableJsonSchema = Object.entries(TableSchema.shape).reduce((acc, [key, value]) => {
137
- acc[key] = value.toJsonSchema();
138
- acc[key]["x-zui"] ??= {};
139
- acc[key]["x-zui"].searchable = searchableColumns.includes(key);
140
- return acc;
141
- }, {});
142
- var TableAdapter = class extends Adapter {
143
- static {
144
- __name(this, "TableAdapter");
145
- }
146
- client;
147
- tableName;
148
- status;
149
- errors = [];
150
- constructor(props) {
151
- super();
152
- props = Props.parse(props);
153
- this.client = props.client;
154
- this.tableName = props.tableName;
155
- this.status = "ready";
156
- }
157
- async getExamples({ taskType, taskId, input }) {
158
- await this.assertTableExists();
159
- const { rows } = await this.client.findTableRows({
160
- table: this.tableName,
161
- search: JSON.stringify({ value: input }).substring(0, 1023),
162
- // Search is limited to 1024 characters
163
- limit: 10,
164
- // TODO
165
- filter: {
166
- // Proximity match of approved examples
167
- taskType,
168
- taskId,
169
- status: "approved"
170
- }
171
- }).catch((err) => {
172
- console.error(`Error fetching examples: ${err.message}`);
173
- return { rows: [] };
174
- });
175
- return rows.map((row) => ({
176
- key: row.key,
177
- input: row.input.value,
178
- output: row.output.value,
179
- explanation: row.explanation,
180
- similarity: row.similarity ?? 0
181
- }));
182
- }
183
- async saveExample({
184
- key,
185
- taskType,
186
- taskId,
187
- instructions,
188
- input,
189
- output,
190
- explanation,
191
- metadata,
192
- status = "pending"
193
- }) {
194
- await this.assertTableExists();
195
- await this.client.upsertTableRows({
196
- table: this.tableName,
197
- keyColumn: "key",
198
- rows: [
199
- {
200
- key,
201
- taskType,
202
- taskId,
203
- instructions,
204
- input: { value: input },
205
- output: { value: output },
206
- explanation: explanation ?? null,
207
- status,
208
- metadata
209
- }
210
- ]
211
- }).catch(() => {
212
- });
213
- }
214
- async assertTableExists() {
215
- if (this.status !== "ready") {
216
- return;
217
- }
218
- const { table, created } = await this.client.getOrCreateTable({
219
- table: this.tableName,
220
- factor: FACTOR,
221
- frozen: true,
222
- isComputeEnabled: false,
223
- tags: {
224
- ...CRITICAL_TAGS,
225
- ...OPTIONAL_TAGS
226
- },
227
- schema: TableJsonSchema
228
- }).catch((err) => {
229
- this.status = "error";
230
- this.errors = [err.message];
231
- return { table: null, created: false };
232
- });
233
- if (!table) {
234
- return;
235
- }
236
- if (!created) {
237
- const issues = [];
238
- if (table.factor !== FACTOR) {
239
- issues.push(`Factor is ${table.factor} instead of ${FACTOR}`);
240
- }
241
- if (table.frozen !== true) {
242
- issues.push("Table is not frozen");
243
- }
244
- for (const [key, value] of Object.entries(CRITICAL_TAGS)) {
245
- if (table.tags?.[key] !== value) {
246
- issues.push(`Tag ${key} is ${table.tags?.[key]} instead of ${value}`);
247
- }
248
- }
249
- for (const key of Object.keys(TableJsonSchema)) {
250
- const column = table.schema?.properties[key];
251
- const expected = TableJsonSchema[key];
252
- if (!column) {
253
- issues.push(`Column ${key} is missing`);
254
- continue;
255
- }
256
- if (column.type !== expected.type) {
257
- issues.push(`Column ${key} has type ${column.type} instead of ${expected.type}`);
258
- }
259
- if (expected["x-zui"].searchable && !column["x-zui"].searchable) {
260
- issues.push(`Column ${key} is not searchable but should be`);
261
- }
262
- }
263
- if (issues.length) {
264
- this.status = "error";
265
- this.errors = issues;
266
- }
267
- }
268
- this.status = "initialized";
269
- }
270
- };
271
-
272
- // src/adapters/memory.ts
273
- var MemoryAdapter = class extends Adapter {
274
- constructor(examples) {
275
- super();
276
- this.examples = examples;
277
- }
278
- static {
279
- __name(this, "MemoryAdapter");
280
- }
281
- async getExamples() {
282
- return this.examples;
283
- }
284
- async saveExample() {
285
- }
286
- };
287
-
288
- // src/models.ts
289
- var Models = [
290
- {
291
- "id": "anthropic__claude-3-haiku-20240307",
292
- "name": "Claude 3 Haiku",
293
- "integration": "anthropic",
294
- "input": {
295
- "maxTokens": 2e5
296
- },
297
- "output": {
298
- "maxTokens": 4096
299
- }
300
- },
301
- {
302
- "id": "anthropic__claude-3-5-sonnet-20240620",
303
- "name": "Claude 3.5 Sonnet",
304
- "integration": "anthropic",
305
- "input": {
306
- "maxTokens": 2e5
307
- },
308
- "output": {
309
- "maxTokens": 4096
310
- }
311
- },
312
- {
313
- "id": "cerebras__llama3.1-70b",
314
- "name": "Llama 3.1 70B",
315
- "integration": "cerebras",
316
- "input": {
317
- "maxTokens": 8192
318
- },
319
- "output": {
320
- "maxTokens": 8192
321
- }
322
- },
323
- {
324
- "id": "cerebras__llama3.1-8b",
325
- "name": "Llama 3.1 8B",
326
- "integration": "cerebras",
327
- "input": {
328
- "maxTokens": 8192
329
- },
330
- "output": {
331
- "maxTokens": 8192
332
- }
333
- },
334
- {
335
- "id": "fireworks-ai__accounts/fireworks/models/deepseek-coder-v2-instruct",
336
- "name": "DeepSeek Coder V2 Instruct",
337
- "integration": "fireworks-ai",
338
- "input": {
339
- "maxTokens": 131072
340
- },
341
- "output": {
342
- "maxTokens": 131072
343
- }
344
- },
345
- {
346
- "id": "fireworks-ai__accounts/fireworks/models/deepseek-coder-v2-lite-instruct",
347
- "name": "DeepSeek Coder V2 Lite",
348
- "integration": "fireworks-ai",
349
- "input": {
350
- "maxTokens": 163840
351
- },
352
- "output": {
353
- "maxTokens": 163840
354
- }
355
- },
356
- {
357
- "id": "fireworks-ai__accounts/fireworks/models/firellava-13b",
358
- "name": "FireLLaVA-13B",
359
- "integration": "fireworks-ai",
360
- "input": {
361
- "maxTokens": 4096
362
- },
363
- "output": {
364
- "maxTokens": 4096
365
- }
366
- },
367
- {
368
- "id": "fireworks-ai__accounts/fireworks/models/firefunction-v2",
369
- "name": "Firefunction V2",
370
- "integration": "fireworks-ai",
371
- "input": {
372
- "maxTokens": 8192
373
- },
374
- "output": {
375
- "maxTokens": 8192
376
- }
377
- },
378
- {
379
- "id": "fireworks-ai__accounts/fireworks/models/gemma2-9b-it",
380
- "name": "Gemma 2 9B Instruct",
381
- "integration": "fireworks-ai",
382
- "input": {
383
- "maxTokens": 8192
384
- },
385
- "output": {
386
- "maxTokens": 8192
387
- }
388
- },
389
- {
390
- "id": "fireworks-ai__accounts/fireworks/models/llama-v3p1-405b-instruct",
391
- "name": "Llama 3.1 405B Instruct",
392
- "integration": "fireworks-ai",
393
- "input": {
394
- "maxTokens": 131072
395
- },
396
- "output": {
397
- "maxTokens": 131072
398
- }
399
- },
400
- {
401
- "id": "fireworks-ai__accounts/fireworks/models/llama-v3p1-70b-instruct",
402
- "name": "Llama 3.1 70B Instruct",
403
- "integration": "fireworks-ai",
404
- "input": {
405
- "maxTokens": 131072
406
- },
407
- "output": {
408
- "maxTokens": 131072
409
- }
410
- },
411
- {
412
- "id": "fireworks-ai__accounts/fireworks/models/llama-v3p1-8b-instruct",
413
- "name": "Llama 3.1 8B Instruct",
414
- "integration": "fireworks-ai",
415
- "input": {
416
- "maxTokens": 131072
417
- },
418
- "output": {
419
- "maxTokens": 131072
420
- }
421
- },
422
- {
423
- "id": "fireworks-ai__accounts/fireworks/models/mixtral-8x22b-instruct",
424
- "name": "Mixtral MoE 8x22B Instruct",
425
- "integration": "fireworks-ai",
426
- "input": {
427
- "maxTokens": 65536
428
- },
429
- "output": {
430
- "maxTokens": 65536
431
- }
432
- },
433
- {
434
- "id": "fireworks-ai__accounts/fireworks/models/mixtral-8x7b-instruct",
435
- "name": "Mixtral MoE 8x7B Instruct",
436
- "integration": "fireworks-ai",
437
- "input": {
438
- "maxTokens": 32768
439
- },
440
- "output": {
441
- "maxTokens": 32768
442
- }
443
- },
444
- {
445
- "id": "fireworks-ai__accounts/fireworks/models/mythomax-l2-13b",
446
- "name": "MythoMax L2 13b",
447
- "integration": "fireworks-ai",
448
- "input": {
449
- "maxTokens": 4096
450
- },
451
- "output": {
452
- "maxTokens": 4096
453
- }
454
- },
455
- {
456
- "id": "fireworks-ai__accounts/fireworks/models/qwen2-72b-instruct",
457
- "name": "Qwen2 72b Instruct",
458
- "integration": "fireworks-ai",
459
- "input": {
460
- "maxTokens": 32768
461
- },
462
- "output": {
463
- "maxTokens": 32768
464
- }
465
- },
466
- {
467
- "id": "groq__gemma2-9b-it",
468
- "name": "Gemma2 9B",
469
- "integration": "groq",
470
- "input": {
471
- "maxTokens": 8192
472
- },
473
- "output": {
474
- "maxTokens": 8192
475
- }
476
- },
477
- {
478
- "id": "groq__llama3-70b-8192",
479
- "name": "LLaMA 3 70B",
480
- "integration": "groq",
481
- "input": {
482
- "maxTokens": 8192
483
- },
484
- "output": {
485
- "maxTokens": 8192
486
- }
487
- },
488
- {
489
- "id": "groq__llama3-8b-8192",
490
- "name": "LLaMA 3 8B",
491
- "integration": "groq",
492
- "input": {
493
- "maxTokens": 8192
494
- },
495
- "output": {
496
- "maxTokens": 8192
497
- }
498
- },
499
- {
500
- "id": "groq__llama-3.1-70b-versatile",
501
- "name": "LLaMA 3.1 70B",
502
- "integration": "groq",
503
- "input": {
504
- "maxTokens": 128e3
505
- },
506
- "output": {
507
- "maxTokens": 8192
508
- }
509
- },
510
- {
511
- "id": "groq__llama-3.1-8b-instant",
512
- "name": "LLaMA 3.1 8B",
513
- "integration": "groq",
514
- "input": {
515
- "maxTokens": 128e3
516
- },
517
- "output": {
518
- "maxTokens": 8192
519
- }
520
- },
521
- {
522
- "id": "groq__llama-3.2-11b-vision-preview",
523
- "name": "LLaMA 3.2 11B Vision",
524
- "integration": "groq",
525
- "input": {
526
- "maxTokens": 128e3
527
- },
528
- "output": {
529
- "maxTokens": 8192
530
- }
531
- },
532
- {
533
- "id": "groq__llama-3.2-1b-preview",
534
- "name": "LLaMA 3.2 1B",
535
- "integration": "groq",
536
- "input": {
537
- "maxTokens": 128e3
538
- },
539
- "output": {
540
- "maxTokens": 8192
541
- }
542
- },
543
- {
544
- "id": "groq__llama-3.2-3b-preview",
545
- "name": "LLaMA 3.2 3B",
546
- "integration": "groq",
547
- "input": {
548
- "maxTokens": 128e3
549
- },
550
- "output": {
551
- "maxTokens": 8192
552
- }
553
- },
554
- {
555
- "id": "groq__llama-3.2-90b-vision-preview",
556
- "name": "LLaMA 3.2 90B Vision",
557
- "integration": "groq",
558
- "input": {
559
- "maxTokens": 128e3
560
- },
561
- "output": {
562
- "maxTokens": 8192
563
- }
564
- },
565
- {
566
- "id": "groq__llama-3.3-70b-versatile",
567
- "name": "LLaMA 3.3 70B",
568
- "integration": "groq",
569
- "input": {
570
- "maxTokens": 128e3
571
- },
572
- "output": {
573
- "maxTokens": 32768
574
- }
575
- },
576
- {
577
- "id": "groq__mixtral-8x7b-32768",
578
- "name": "Mixtral 8x7B",
579
- "integration": "groq",
580
- "input": {
581
- "maxTokens": 32768
582
- },
583
- "output": {
584
- "maxTokens": 32768
585
- }
586
- },
587
- {
588
- "id": "openai__o1-2024-12-17",
589
- "name": "GPT o1",
590
- "integration": "openai",
591
- "input": {
592
- "maxTokens": 2e5
593
- },
594
- "output": {
595
- "maxTokens": 1e5
596
- }
597
- },
598
- {
599
- "id": "openai__o1-mini-2024-09-12",
600
- "name": "GPT o1-mini",
601
- "integration": "openai",
602
- "input": {
603
- "maxTokens": 128e3
604
- },
605
- "output": {
606
- "maxTokens": 65536
607
- }
608
- },
609
- {
610
- "id": "openai__gpt-3.5-turbo-0125",
611
- "name": "GPT-3.5 Turbo",
612
- "integration": "openai",
613
- "input": {
614
- "maxTokens": 128e3
615
- },
616
- "output": {
617
- "maxTokens": 4096
618
- }
619
- },
620
- {
621
- "id": "openai__gpt-4-turbo-2024-04-09",
622
- "name": "GPT-4 Turbo",
623
- "integration": "openai",
624
- "input": {
625
- "maxTokens": 128e3
626
- },
627
- "output": {
628
- "maxTokens": 4096
629
- }
630
- },
631
- {
632
- "id": "openai__gpt-4o-2024-08-06",
633
- "name": "GPT-4o (August 2024)",
634
- "integration": "openai",
635
- "input": {
636
- "maxTokens": 128e3
637
- },
638
- "output": {
639
- "maxTokens": 16384
640
- }
641
- },
642
- {
643
- "id": "openai__gpt-4o-2024-05-13",
644
- "name": "GPT-4o (May 2024)",
645
- "integration": "openai",
646
- "input": {
647
- "maxTokens": 128e3
648
- },
649
- "output": {
650
- "maxTokens": 4096
651
- }
652
- },
653
- {
654
- "id": "openai__gpt-4o-2024-11-20",
655
- "name": "GPT-4o (November 2024)",
656
- "integration": "openai",
657
- "input": {
658
- "maxTokens": 128e3
659
- },
660
- "output": {
661
- "maxTokens": 16384
662
- }
663
- },
664
- {
665
- "id": "openai__gpt-4o-mini-2024-07-18",
666
- "name": "GPT-4o Mini",
667
- "integration": "openai",
668
- "input": {
669
- "maxTokens": 128e3
670
- },
671
- "output": {
672
- "maxTokens": 16384
673
- }
674
- }
675
- ];
676
-
677
- // src/zai.ts
678
- var { z: z3 } = import_sdk3.default;
679
- var ActiveLearning = z3.object({
680
- enable: z3.boolean().describe("Whether to enable active learning").default(false),
681
- tableName: z3.string().regex(
682
- /^[A-Za-z0-9_/-]{1,100}Table$/,
683
- "Namespace must be alphanumeric and contain only letters, numbers, underscores, hyphens and slashes"
684
- ).describe("The name of the table to store active learning tasks").default("ActiveLearningTable"),
685
- taskId: z3.string().regex(
686
- /^[A-Za-z0-9_/-]{1,100}$/,
687
- "Namespace must be alphanumeric and contain only letters, numbers, underscores, hyphens and slashes"
688
- ).describe("The ID of the task").default("default")
689
- });
690
- var ZaiConfig = z3.object({
691
- client: BotpressClient,
692
- userId: z3.string().describe("The ID of the user consuming the API").optional(),
693
- retry: z3.object({ maxRetries: z3.number().min(0).max(100) }).default({ maxRetries: 3 }),
694
- modelId: z3.custom(
695
- (value) => {
696
- if (typeof value !== "string" || !value.includes("__")) {
697
- return false;
698
- }
699
- return true;
700
- },
701
- {
702
- message: "Invalid model ID"
703
- }
704
- ).describe("The ID of the model you want to use").default("openai__gpt-4o-mini-2024-07-18"),
705
- activeLearning: ActiveLearning.default({ enable: false }),
706
- namespace: z3.string().regex(
707
- /^[A-Za-z0-9_/-]{1,100}$/,
708
- "Namespace must be alphanumeric and contain only letters, numbers, underscores, hyphens and slashes"
709
- ).default("zai")
710
- });
711
- var Zai = class _Zai {
712
- static {
713
- __name(this, "Zai");
714
- }
715
- static tokenizer = null;
716
- client;
717
- originalConfig;
718
- userId;
719
- integration;
720
- model;
721
- retry;
722
- Model;
723
- namespace;
724
- adapter;
725
- activeLearning;
726
- constructor(config) {
727
- this.originalConfig = config;
728
- const parsed = ZaiConfig.parse(config);
729
- this.client = parsed.client;
730
- const [integration, modelId] = parsed.modelId.split("__");
731
- if (!integration?.length || !modelId?.length) {
732
- throw new Error(`Invalid model ID: ${parsed.modelId}. Expected format: <integration>__<modelId>`);
733
- }
734
- this.integration = integration;
735
- this.model = modelId;
736
- this.namespace = parsed.namespace;
737
- this.userId = parsed.userId;
738
- this.retry = parsed.retry;
739
- this.Model = Models.find((m) => m.id === parsed.modelId);
740
- this.activeLearning = parsed.activeLearning;
741
- this.adapter = parsed.activeLearning?.enable ? new TableAdapter({ client: this.client, tableName: parsed.activeLearning.tableName }) : new MemoryAdapter([]);
742
- }
743
- /** @internal */
744
- async callModel(props) {
745
- let retries = this.retry.maxRetries;
746
- while (retries-- >= 0) {
747
- try {
748
- return await this._callModel(props);
749
- } catch (e) {
750
- if (retries >= 0) {
751
- await new Promise((resolve) => setTimeout(resolve, 1e3));
752
- } else {
753
- throw new Error("Failed to call model after multiple retries");
754
- }
755
- }
756
- }
757
- throw new Error("Failed to call model after multiple retries");
758
- }
759
- /** @internal */
760
- async _callModel(props) {
761
- let retries = this.retry.maxRetries;
762
- do {
763
- const start = Date.now();
764
- const input = {
765
- messages: [],
766
- temperature: 0,
767
- topP: 1,
768
- model: { id: this.model },
769
- userId: this.userId,
770
- ...props
771
- };
772
- const { output } = await this.client.callAction({
773
- type: `${this.integration}:generateContent`,
774
- input
775
- });
776
- const latency = Date.now() - start;
777
- return {
778
- ...output,
779
- metadata: {
780
- model: this.model,
781
- latency,
782
- cost: { input: output.usage.inputCost, output: output.usage.outputCost },
783
- tokens: { input: output.usage.inputTokens, output: output.usage.outputTokens }
784
- }
785
- };
786
- } while (--retries > 0);
787
- }
788
- async getTokenizer() {
789
- _Zai.tokenizer ??= await (async () => {
790
- while (!import_wasm.getWasmTokenizer) {
791
- await new Promise((resolve) => setTimeout(resolve, 25));
792
- }
793
- return (0, import_wasm.getWasmTokenizer)();
794
- })();
795
- return _Zai.tokenizer;
796
- }
797
- get taskId() {
798
- if (!this.activeLearning.enable) {
799
- return void 0;
800
- }
801
- return `${this.namespace}/${this.activeLearning.taskId}`.replace(/\/+/g, "/");
802
- }
803
- with(options) {
804
- return new _Zai({
805
- ...this.originalConfig,
806
- ...options
807
- });
808
- }
809
- learn(taskId) {
810
- return new _Zai({
811
- ...this.originalConfig,
812
- activeLearning: { ...this.activeLearning, taskId, enable: true }
813
- });
814
- }
815
- };
816
-
817
- // src/operations/text.ts
818
- var import_sdk4 = __toESM(require("@botpress/sdk"), 1);
819
- var import_lodash = __toESM(require("lodash"), 1);
820
-
821
- // src/operations/constants.ts
822
- var PROMPT_INPUT_BUFFER = 1048;
823
- var PROMPT_OUTPUT_BUFFER = 512;
824
-
825
- // src/operations/text.ts
826
- var { z: z4 } = import_sdk4.default;
827
- var Options = z4.object({
828
- length: z4.number().min(1).max(1e5).optional().describe("The maximum number of tokens to generate")
829
- });
830
- Zai.prototype.text = async function(prompt, _options) {
831
- const options = Options.parse(_options ?? {});
832
- const tokenizer = await this.getTokenizer();
833
- prompt = tokenizer.truncate(prompt, Math.max(this.Model.input.maxTokens - PROMPT_INPUT_BUFFER, 100));
834
- if (options.length) {
835
- options.length = Math.min(this.Model.output.maxTokens - PROMPT_OUTPUT_BUFFER, options.length);
836
- }
837
- const instructions = [];
838
- let chart = "";
839
- if (options.length) {
840
- const length = import_lodash.default.clamp(options.length * 0.75, 5, options.length);
841
- instructions.push(`IMPORTANT: Length constraint: ${length} tokens/words`);
842
- instructions.push(`The text must be standalone and complete in less than ${length} tokens/words`);
843
- }
844
- if (options.length && options.length <= 500) {
845
- chart = `
846
- | Tokens | Text Length (approximate) |
847
- |-------------|--------------------------------------|
848
- | < 5 tokens | 1-3 words |
849
- | 5-10 tokens | 3-6 words |
850
- | 10-20 tokens| 6-15 words |
851
- | 20-50 tokens| A short sentence (15-30 words) |
852
- | 50-100 tokens| A medium sentence (30-70 words) |
853
- | 100-200 tokens| A short paragraph (70-150 words) |
854
- | 200-300 tokens| A medium paragraph (150-200 words) |
855
- | 300-500 tokens| A long paragraph (200-300 words) |`.trim();
856
- }
857
- const output = await this.callModel({
858
- systemPrompt: `
859
- Generate a text that fulfills the user prompt below. Answer directly to the prompt, without any acknowledgements or fluff. Also, make sure the text is standalone and complete.
860
- ${instructions.map((x) => `- ${x}`).join("\n")}
861
- ${chart}
862
- `.trim(),
863
- temperature: 0.7,
864
- messages: [{ type: "text", content: prompt, role: "user" }],
865
- maxTokens: options.length
866
- });
867
- return output?.choices?.[0]?.content;
868
- };
869
-
870
- // src/operations/rewrite.ts
871
- var import_sdk5 = __toESM(require("@botpress/sdk"), 1);
872
- var { z: z5 } = import_sdk5.default;
873
- var Example = z5.object({
874
- input: z5.string(),
875
- output: z5.string()
876
- });
877
- var Options2 = z5.object({
878
- examples: z5.array(Example).default([]),
879
- length: z5.number().min(10).max(16e3).optional().describe("The maximum number of tokens to generate")
880
- });
881
- var START = "\u25A0START\u25A0";
882
- var END = "\u25A0END\u25A0";
883
- Zai.prototype.rewrite = async function(original, prompt, _options) {
884
- const options = Options2.parse(_options ?? {});
885
- const tokenizer = await this.getTokenizer();
886
- const taskId = this.taskId;
887
- const taskType = "zai.rewrite";
888
- const INPUT_COMPONENT_SIZE = Math.max(100, (this.Model.input.maxTokens - PROMPT_INPUT_BUFFER) / 2);
889
- prompt = tokenizer.truncate(prompt, INPUT_COMPONENT_SIZE);
890
- const inputSize = tokenizer.count(original) + tokenizer.count(prompt);
891
- const maxInputSize = this.Model.input.maxTokens - tokenizer.count(prompt) - PROMPT_INPUT_BUFFER;
892
- if (inputSize > maxInputSize) {
893
- throw new Error(
894
- `The input size is ${inputSize} tokens long, which is more than the maximum of ${maxInputSize} tokens for this model (${this.Model.name} = ${this.Model.input.maxTokens} tokens)`
895
- );
896
- }
897
- const instructions = [];
898
- const originalSize = tokenizer.count(original);
899
- if (options.length && originalSize > options.length) {
900
- instructions.push(`The original text is ${originalSize} tokens long \u2013 it should be less than ${options.length}`);
901
- instructions.push(
902
- `The text must be standalone and complete in less than ${options.length} tokens, so it has to be shortened to fit the length as well`
903
- );
904
- }
905
- const format = /* @__PURE__ */ __name((before, prompt2) => {
906
- return `
907
- Prompt: ${prompt2}
908
-
909
- ${START}
910
- ${before}
911
- ${END}
912
- `.trim();
913
- }, "format");
914
- const Key = fastHash(
915
- stringify({
916
- taskId,
917
- taskType,
918
- input: original,
919
- prompt
920
- })
921
- );
922
- const formatExample = /* @__PURE__ */ __name(({ input, output: output2, instructions: instructions2 }) => {
923
- return [
924
- { type: "text", role: "user", content: format(input, instructions2 || prompt) },
925
- { type: "text", role: "assistant", content: `${START}${output2}${END}` }
926
- ];
927
- }, "formatExample");
928
- const defaultExamples = [
929
- { input: "Hello, how are you?", output: "Bonjour, comment \xE7a va?", instructions: "translate to French" },
930
- { input: "1\n2\n3", output: "3\n2\n1", instructions: "reverse the order" }
931
- ];
932
- const tableExamples = taskId ? await this.adapter.getExamples({
933
- input: original,
934
- taskId,
935
- taskType
936
- }) : [];
937
- const exactMatch = tableExamples.find((x) => x.key === Key);
938
- if (exactMatch) {
939
- return exactMatch.output;
940
- }
941
- const savedExamples = [
942
- ...tableExamples.map((x) => ({ input: x.input, output: x.output })),
943
- ...options.examples
944
- ];
945
- const REMAINING_TOKENS = this.Model.input.maxTokens - tokenizer.count(prompt) - PROMPT_INPUT_BUFFER;
946
- const examples = takeUntilTokens(
947
- savedExamples.length ? savedExamples : defaultExamples,
948
- REMAINING_TOKENS,
949
- (el) => tokenizer.count(stringify(el.input)) + tokenizer.count(stringify(el.output))
950
- ).map(formatExample).flat();
951
- const output = await this.callModel({
952
- systemPrompt: `
953
- Rewrite the text between the ${START} and ${END} tags to match the user prompt.
954
- ${instructions.map((x) => `\u2022 ${x}`).join("\n")}
955
- `.trim(),
956
- messages: [...examples, { type: "text", content: format(original, prompt), role: "user" }],
957
- maxTokens: options.length,
958
- stopSequences: [END]
959
- });
960
- let result = output.choices[0]?.content;
961
- if (result.includes(START)) {
962
- result = result.slice(result.indexOf(START) + START.length);
963
- }
964
- if (result.includes(END)) {
965
- result = result.slice(0, result.indexOf(END));
966
- }
967
- if (taskId) {
968
- await this.adapter.saveExample({
969
- key: Key,
970
- metadata: output.metadata,
971
- instructions: prompt,
972
- input: original,
973
- output: result,
974
- taskType,
975
- taskId
976
- });
977
- }
978
- return result;
979
- };
980
-
981
- // src/operations/summarize.ts
982
- var import_sdk6 = __toESM(require("@botpress/sdk"), 1);
983
- var import_lodash2 = __toESM(require("lodash"), 1);
984
- var { z: z6 } = import_sdk6.default;
985
- var Options3 = z6.object({
986
- prompt: z6.string().describe("What should the text be summarized to?").default("New information, concepts and ideas that are deemed important"),
987
- format: z6.string().describe("How to format the example text").default(
988
- "A normal text with multiple sentences and paragraphs. Use markdown to format the text into sections. Use headings, lists, and other markdown features to make the text more readable. Do not include links, images, or other non-text elements."
989
- ),
990
- length: z6.number().min(10).max(1e5).describe("The length of the summary in tokens").default(250),
991
- intermediateFactor: z6.number().min(1).max(10).describe("How many times longer (than final length) are the intermediate summaries generated").default(4),
992
- maxIterations: z6.number().min(1).default(100),
993
- sliding: z6.object({
994
- window: z6.number().min(10).max(1e5),
995
- overlap: z6.number().min(0).max(1e5)
996
- }).describe("Sliding window options").default({ window: 5e4, overlap: 250 })
997
- });
998
- var START2 = "\u25A0START\u25A0";
999
- var END2 = "\u25A0END\u25A0";
1000
- Zai.prototype.summarize = async function(original, _options) {
1001
- const options = Options3.parse(_options ?? {});
1002
- const tokenizer = await this.getTokenizer();
1003
- const INPUT_COMPONENT_SIZE = Math.max(100, (this.Model.input.maxTokens - PROMPT_INPUT_BUFFER) / 4);
1004
- options.prompt = tokenizer.truncate(options.prompt, INPUT_COMPONENT_SIZE);
1005
- options.format = tokenizer.truncate(options.format, INPUT_COMPONENT_SIZE);
1006
- const maxOutputSize = this.Model.output.maxTokens - PROMPT_OUTPUT_BUFFER;
1007
- if (options.length > maxOutputSize) {
1008
- throw new Error(
1009
- `The desired output length is ${maxOutputSize} tokens long, which is more than the maximum of ${this.Model.output.maxTokens} tokens for this model (${this.Model.name})`
1010
- );
1011
- }
1012
- options.sliding.window = Math.min(options.sliding.window, this.Model.input.maxTokens - PROMPT_INPUT_BUFFER);
1013
- options.sliding.overlap = Math.min(options.sliding.overlap, options.sliding.window - 3 * options.sliding.overlap);
1014
- const format = /* @__PURE__ */ __name((summary, newText) => {
1015
- return `
1016
- ${START2}
1017
- ${summary.length ? summary : "<summary still empty>"}
1018
- ${END2}
1019
-
1020
- Please amend the summary between the ${START2} and ${END2} tags to accurately reflect the prompt and the additional text below.
1021
-
1022
- <|start_new_information|>
1023
- ${newText}
1024
- <|new_information|>`.trim();
1025
- }, "format");
1026
- const tokens = tokenizer.split(original);
1027
- const parts = Math.ceil(tokens.length / (options.sliding.window - options.sliding.overlap));
1028
- let iteration = 0;
1029
- const N = 2;
1030
- const useMergeSort = parts >= Math.pow(2, N);
1031
- const chunkSize = Math.ceil(tokens.length / (parts * N));
1032
- if (useMergeSort) {
1033
- const chunks = import_lodash2.default.chunk(tokens, chunkSize).map((x) => x.join(""));
1034
- const allSummaries = await Promise.all(chunks.map((chunk) => this.summarize(chunk, options)));
1035
- return this.summarize(allSummaries.join("\n\n============\n\n"), options);
1036
- }
1037
- const summaries = [];
1038
- let currentSummary = "";
1039
- for (let i = 0; i < tokens.length; i += options.sliding.window) {
1040
- const from = Math.max(0, i - options.sliding.overlap);
1041
- const to = Math.min(tokens.length, i + options.sliding.window + options.sliding.overlap);
1042
- const isFirst = i === 0;
1043
- const isLast = to >= tokens.length;
1044
- const slice = tokens.slice(from, to).join("");
1045
- if (iteration++ >= options.maxIterations) {
1046
- break;
1047
- }
1048
- const instructions = [
1049
- `At each step, you will receive a part of the text to summarize. Make sure to reply with the new summary in the tags ${START2} and ${END2}.`,
1050
- "Summarize the text and make sure that the main points are included.",
1051
- "Ignore any unnecessary details and focus on the main points.",
1052
- "Use short and concise sentences to increase readability and information density.",
1053
- "When looking at the new information, focus on: " + options.prompt
1054
- ];
1055
- if (isFirst) {
1056
- instructions.push(
1057
- "The current summary is empty. You need to generate a summary that covers the main points of the text."
1058
- );
1059
- }
1060
- let generationLength = options.length;
1061
- if (!isLast) {
1062
- generationLength = Math.min(
1063
- tokenizer.count(currentSummary) + options.length * options.intermediateFactor,
1064
- maxOutputSize
1065
- );
1066
- instructions.push(
1067
- "You need to amend the summary to include the new information. Make sure the summary is complete and covers all the main points."
1068
- );
1069
- instructions.push(`The current summary is ${currentSummary.length} tokens long.`);
1070
- instructions.push(`You can amend the summary to be up to ${generationLength} tokens long.`);
1071
- }
1072
- if (isLast) {
1073
- instructions.push(
1074
- "This is the last part you will have to summarize. Make sure the summary is complete and covers all the main points."
1075
- );
1076
- instructions.push(
1077
- `The current summary is ${currentSummary.length} tokens long. You need to make sure it is ${options.length} tokens or less.`
1078
- );
1079
- if (currentSummary.length > options.length) {
1080
- instructions.push(
1081
- `The current summary is already too long, so you need to shorten it to ${options.length} tokens while also including the new information.`
1082
- );
1083
- }
1084
- }
1085
- const output = await this.callModel({
1086
- systemPrompt: `
1087
- You are summarizing a text. The text is split into ${parts} parts, and you are currently working on part ${iteration}.
1088
- At every step, you will receive the current summary and a new part of the text. You need to amend the summary to include the new information (if needed).
1089
- The summary needs to cover the main points of the text and must be concise.
1090
-
1091
- IMPORTANT INSTRUCTIONS:
1092
- ${instructions.map((x) => `- ${x.trim()}`).join("\n")}
1093
-
1094
- FORMAT OF THE SUMMARY:
1095
- ${options.format}
1096
- `.trim(),
1097
- messages: [{ type: "text", content: format(currentSummary, slice), role: "user" }],
1098
- maxTokens: generationLength,
1099
- stopSequences: [END2]
1100
- });
1101
- let result = output?.choices[0]?.content;
1102
- if (result.includes(START2)) {
1103
- result = result.slice(result.indexOf(START2) + START2.length);
1104
- }
1105
- if (result.includes("\u25A0")) {
1106
- result = result.slice(0, result.indexOf("\u25A0"));
1107
- }
1108
- summaries.push(result);
1109
- currentSummary = result;
1110
- }
1111
- return currentSummary.trim();
1112
- };
1113
-
1114
- // src/operations/check.ts
1115
- var import_sdk7 = __toESM(require("@botpress/sdk"), 1);
1116
- var { z: z7 } = import_sdk7.default;
1117
- var Example2 = z7.object({
1118
- input: z7.any(),
1119
- check: z7.boolean(),
1120
- reason: z7.string().optional()
1121
- });
1122
- var Options4 = z7.object({
1123
- examples: z7.array(Example2).describe("Examples to check the condition against").default([])
1124
- });
1125
- var TRUE = "\u25A0TRUE\u25A0";
1126
- var FALSE = "\u25A0FALSE\u25A0";
1127
- var END3 = "\u25A0END\u25A0";
1128
- Zai.prototype.check = async function(input, condition, _options) {
1129
- const options = Options4.parse(_options ?? {});
1130
- const tokenizer = await this.getTokenizer();
1131
- const PROMPT_COMPONENT = Math.max(this.Model.input.maxTokens - PROMPT_INPUT_BUFFER, 100);
1132
- const taskId = this.taskId;
1133
- const taskType = "zai.check";
1134
- const PROMPT_TOKENS = {
1135
- INPUT: Math.floor(0.5 * PROMPT_COMPONENT),
1136
- CONDITION: Math.floor(0.2 * PROMPT_COMPONENT)
1137
- };
1138
- const inputAsString = tokenizer.truncate(stringify(input), PROMPT_TOKENS.INPUT);
1139
- condition = tokenizer.truncate(condition, PROMPT_TOKENS.CONDITION);
1140
- const EXAMPLES_TOKENS = PROMPT_COMPONENT - tokenizer.count(inputAsString) - tokenizer.count(condition);
1141
- const Key = fastHash(
1142
- JSON.stringify({
1143
- taskType,
1144
- taskId,
1145
- input: inputAsString,
1146
- condition
1147
- })
1148
- );
1149
- const examples = taskId ? await this.adapter.getExamples({
1150
- input: inputAsString,
1151
- taskType,
1152
- taskId
1153
- }) : [];
1154
- const exactMatch = examples.find((x) => x.key === Key);
1155
- if (exactMatch) {
1156
- return exactMatch.output;
1157
- }
1158
- const defaultExamples = [
1159
- { input: "50 Cent", check: true, reason: "50 Cent is widely recognized as a public personality." },
1160
- {
1161
- input: ["apple", "banana", "carrot", "house"],
1162
- check: false,
1163
- reason: "The list contains a house, which is not a fruit. Also, the list contains a carrot, which is a vegetable."
1164
- }
1165
- ];
1166
- const userExamples = [
1167
- ...examples.map((e) => ({ input: e.input, check: e.output, reason: e.explanation })),
1168
- ...options.examples
1169
- ];
1170
- let exampleId = 1;
1171
- const formatInput = /* @__PURE__ */ __name((input2, condition2) => {
1172
- const header = userExamples.length ? `Expert Example #${exampleId++}` : `Example of condition: "${condition2}"`;
1173
- return `
1174
- ${header}
1175
- <|start_input|>
1176
- ${input2.trim()}
1177
- <|end_input|>
1178
- `.trim();
1179
- }, "formatInput");
1180
- const formatOutput = /* @__PURE__ */ __name((answer2, justification) => {
1181
- return `
1182
- Analysis: ${justification}
1183
- Final Answer: ${answer2 ? TRUE : FALSE}
1184
- ${END3}
1185
- `.trim();
1186
- }, "formatOutput");
1187
- const formatExample = /* @__PURE__ */ __name((example) => [
1188
- { type: "text", content: formatInput(stringify(example.input ?? null), condition), role: "user" },
1189
- {
1190
- type: "text",
1191
- content: formatOutput(example.check, example.reason ?? ""),
1192
- role: "assistant"
1193
- }
1194
- ], "formatExample");
1195
- const allExamples = takeUntilTokens(
1196
- userExamples.length ? userExamples : defaultExamples,
1197
- EXAMPLES_TOKENS,
1198
- (el) => tokenizer.count(stringify(el.input)) + tokenizer.count(el.reason ?? "")
1199
- ).map(formatExample).flat();
1200
- const specialInstructions = userExamples.length ? `
1201
- - You have been provided with examples from previous experts. Make sure to read them carefully before making your decision.
1202
- - Make sure to refer to the examples provided by the experts to justify your decision (when applicable).
1203
- - When in doubt, ground your decision on the examples provided by the experts instead of your own intuition.
1204
- - When no example is similar to the input, make sure to provide a clear justification for your decision while inferring the decision-making process from the examples provided by the experts.
1205
- `.trim() : "";
1206
- const output = await this.callModel({
1207
- systemPrompt: `
1208
- Check if the following condition is true or false for the given input. Before answering, make sure to read the input and the condition carefully.
1209
- Justify your answer, then answer with either ${TRUE} or ${FALSE} at the very end, then add ${END3} to finish the response.
1210
- IMPORTANT: Make sure to answer with either ${TRUE} or ${FALSE} at the end of your response, but NOT both.
1211
- ---
1212
- Expert Examples (#1 to #${exampleId - 1}):
1213
- ${specialInstructions}
1214
- `.trim(),
1215
- stopSequences: [END3],
1216
- messages: [
1217
- ...allExamples,
1218
- {
1219
- type: "text",
1220
- content: `
1221
- Considering the below input and above examples, is the following condition true or false?
1222
- ${formatInput(inputAsString, condition)}
1223
- In your "Analysis", please refer to the Expert Examples # to justify your decision.`.trim(),
1224
- role: "user"
1225
- }
1226
- ]
1227
- });
1228
- const answer = output.choices[0]?.content;
1229
- const hasTrue = answer.includes(TRUE);
1230
- const hasFalse = answer.includes(FALSE);
1231
- if (!hasTrue && !hasFalse) {
1232
- throw new Error(`The model did not return a valid answer. The response was: ${answer}`);
1233
- }
1234
- let finalAnswer;
1235
- if (hasTrue && hasFalse) {
1236
- finalAnswer = answer.lastIndexOf(TRUE) > answer.lastIndexOf(FALSE);
1237
- } else {
1238
- finalAnswer = hasTrue;
1239
- }
1240
- if (taskId) {
1241
- await this.adapter.saveExample({
1242
- key: Key,
1243
- taskType,
1244
- taskId,
1245
- input: inputAsString,
1246
- instructions: condition,
1247
- metadata: output.metadata,
1248
- output: finalAnswer,
1249
- explanation: answer.replace(TRUE, "").replace(FALSE, "").replace(END3, "").replace("Final Answer:", "").trim()
1250
- });
1251
- }
1252
- return finalAnswer;
1253
- };
1254
-
1255
- // src/operations/filter.ts
1256
- var import_sdk8 = __toESM(require("@botpress/sdk"), 1);
1257
- var import_lodash3 = __toESM(require("lodash"), 1);
1258
- var { z: z8 } = import_sdk8.default;
1259
- var Example3 = z8.object({
1260
- input: z8.any(),
1261
- filter: z8.boolean(),
1262
- reason: z8.string().optional()
1263
- });
1264
- var Options5 = z8.object({
1265
- tokensPerItem: z8.number().min(1).max(1e5).optional().describe("The maximum number of tokens per item").default(250),
1266
- examples: z8.array(Example3).describe("Examples to filter the condition against").default([])
1267
- });
1268
- var END4 = "\u25A0END\u25A0";
1269
- Zai.prototype.filter = async function(input, condition, _options) {
1270
- const options = Options5.parse(_options ?? {});
1271
- const tokenizer = await this.getTokenizer();
1272
- const taskId = this.taskId;
1273
- const taskType = "zai.filter";
1274
- const MAX_ITEMS_PER_CHUNK = 50;
1275
- const TOKENS_TOTAL_MAX = this.Model.input.maxTokens - PROMPT_INPUT_BUFFER - PROMPT_OUTPUT_BUFFER;
1276
- const TOKENS_EXAMPLES_MAX = Math.floor(Math.max(250, TOKENS_TOTAL_MAX * 0.5));
1277
- const TOKENS_CONDITION_MAX = import_lodash3.default.clamp(TOKENS_TOTAL_MAX * 0.25, 250, tokenizer.count(condition));
1278
- const TOKENS_INPUT_ARRAY_MAX = TOKENS_TOTAL_MAX - TOKENS_EXAMPLES_MAX - TOKENS_CONDITION_MAX;
1279
- condition = tokenizer.truncate(condition, TOKENS_CONDITION_MAX);
1280
- let chunks = [];
1281
- let currentChunk = [];
1282
- let currentChunkTokens = 0;
1283
- for (const element of input) {
1284
- const elementAsString = tokenizer.truncate(stringify(element, false), options.tokensPerItem);
1285
- const elementTokens = tokenizer.count(elementAsString);
1286
- if (currentChunkTokens + elementTokens > TOKENS_INPUT_ARRAY_MAX || currentChunk.length >= MAX_ITEMS_PER_CHUNK) {
1287
- chunks.push(currentChunk);
1288
- currentChunk = [];
1289
- currentChunkTokens = 0;
1290
- }
1291
- currentChunk.push(element);
1292
- currentChunkTokens += elementTokens;
1293
- }
1294
- if (currentChunk.length > 0) {
1295
- chunks.push(currentChunk);
1296
- }
1297
- chunks = chunks.filter((x) => x.length > 0);
1298
- const formatInput = /* @__PURE__ */ __name((input2, condition2) => {
1299
- return `
1300
- Condition to check:
1301
- ${condition2}
1302
-
1303
- Items (from \u25A00 to \u25A0${input2.length - 1})
1304
- ==============================
1305
- ${input2.map((x, idx) => `\u25A0${idx} = ${stringify(x.input ?? null, false)}`).join("\n")}
1306
- `.trim();
1307
- }, "formatInput");
1308
- const formatExamples = /* @__PURE__ */ __name((examples) => {
1309
- return `
1310
- ${examples.map((x, idx) => `\u25A0${idx}:${!!x.filter ? "true" : "false"}`).join("")}
1311
- ${END4}
1312
- ====
1313
- Here's the reasoning behind each example:
1314
- ${examples.map((x, idx) => `\u25A0${idx}:${!!x.filter ? "true" : "false"}:${x.reason ?? "No reason provided"}`).join("\n")}
1315
- `.trim();
1316
- }, "formatExamples");
1317
- const genericExamples = [
1318
- {
1319
- input: "apple",
1320
- filter: true,
1321
- reason: "Apples are fruits"
1322
- },
1323
- {
1324
- input: "Apple Inc.",
1325
- filter: false,
1326
- reason: "Apple Inc. is a company, not a fruit"
1327
- },
1328
- {
1329
- input: "banana",
1330
- filter: true,
1331
- reason: "Bananas are fruits"
1332
- },
1333
- {
1334
- input: "potato",
1335
- filter: false,
1336
- reason: "Potatoes are vegetables"
1337
- }
1338
- ];
1339
- const genericExamplesMessages = [
1340
- {
1341
- type: "text",
1342
- content: formatInput(genericExamples, "is a fruit"),
1343
- role: "user"
1344
- },
1345
- {
1346
- type: "text",
1347
- content: formatExamples(genericExamples),
1348
- role: "assistant"
1349
- }
1350
- ];
1351
- const filterChunk = /* @__PURE__ */ __name(async (chunk) => {
1352
- const examples = taskId ? await this.adapter.getExamples({
1353
- // The Table API can't search for a huge input string
1354
- input: JSON.stringify(chunk).slice(0, 1e3),
1355
- taskType,
1356
- taskId
1357
- }).then(
1358
- (x) => x.map((y) => ({ filter: y.output, input: y.input, reason: y.explanation }))
1359
- ) : [];
1360
- const allExamples = takeUntilTokens(
1361
- [...examples, ...options.examples ?? []],
1362
- TOKENS_EXAMPLES_MAX,
1363
- (el) => tokenizer.count(stringify(el.input))
1364
- );
1365
- const exampleMessages = [
1366
- {
1367
- type: "text",
1368
- content: formatInput(allExamples, condition),
1369
- role: "user"
1370
- },
1371
- {
1372
- type: "text",
1373
- content: formatExamples(allExamples),
1374
- role: "assistant"
1375
- }
1376
- ];
1377
- const output = await this.callModel({
1378
- systemPrompt: `
1379
- You are given a list of items. Your task is to filter out the items that meet the condition below.
1380
- You need to return the full list of items with the format:
1381
- \u25A0x:true\u25A0y:false\u25A0z:true (where x, y, z are the indices of the items in the list)
1382
- You need to start with "\u25A00" and go up to the last index "\u25A0${chunk.length - 1}".
1383
- If an item meets the condition, you should return ":true", otherwise ":false".
1384
-
1385
- IMPORTANT: Make sure to read the condition and the examples carefully before making your decision.
1386
- The condition is: "${condition}"
1387
- `.trim(),
1388
- stopSequences: [END4],
1389
- messages: [
1390
- ...exampleMessages.length ? exampleMessages : genericExamplesMessages,
1391
- {
1392
- type: "text",
1393
- content: formatInput(
1394
- chunk.map((x) => ({ input: x })),
1395
- condition
1396
- ),
1397
- role: "user"
1398
- }
1399
- ]
1400
- });
1401
- const answer = output.choices[0]?.content;
1402
- const indices = answer.trim().split("\u25A0").filter((x) => x.length > 0).map((x) => {
1403
- const [idx, filter] = x.split(":");
1404
- return { idx: parseInt(idx?.trim() ?? ""), filter: filter?.toLowerCase().trim() === "true" };
1405
- });
1406
- const partial = chunk.filter((_6, idx) => {
1407
- return indices.find((x) => x.idx === idx)?.filter ?? false;
1408
- });
1409
- if (taskId) {
1410
- const key = fastHash(
1411
- stringify({
1412
- taskId,
1413
- taskType,
1414
- input: JSON.stringify(chunk),
1415
- condition
1416
- })
1417
- );
1418
- await this.adapter.saveExample({
1419
- key,
1420
- taskType,
1421
- taskId,
1422
- input: JSON.stringify(chunk),
1423
- output: partial,
1424
- instructions: condition,
1425
- metadata: output.metadata
1426
- });
1427
- }
1428
- return partial;
1429
- }, "filterChunk");
1430
- const filteredChunks = await Promise.all(chunks.map(filterChunk));
1431
- return filteredChunks.flat();
1432
- };
1433
-
1434
- // src/operations/extract.ts
1435
- var import_sdk9 = __toESM(require("@botpress/sdk"), 1);
1436
- var import_json5 = __toESM(require("json5"), 1);
1437
- var import_jsonrepair = require("jsonrepair");
1438
- var import_lodash4 = __toESM(require("lodash"), 1);
1439
-
1440
- // src/operations/errors.ts
1441
- var JsonParsingError = class extends Error {
1442
- constructor(json, error) {
1443
- const message = `Error parsing JSON:
1444
-
1445
- ---JSON---
1446
- ${json}
1447
-
1448
- ---Error---
1449
-
1450
- ${error}`;
1451
- super(message);
1452
- this.json = json;
1453
- this.error = error;
1454
- }
1455
- static {
1456
- __name(this, "JsonParsingError");
1457
- }
1458
- };
1459
-
1460
- // src/operations/extract.ts
1461
- var { z: z9 } = import_sdk9.default;
1462
- var Options6 = z9.object({
1463
- instructions: z9.string().optional().describe("Instructions to guide the user on how to extract the data"),
1464
- chunkLength: z9.number().min(100).max(1e5).optional().describe("The maximum number of tokens per chunk").default(16e3)
1465
- });
1466
- var START3 = "\u25A0json_start\u25A0";
1467
- var END5 = "\u25A0json_end\u25A0";
1468
- var NO_MORE = "\u25A0NO_MORE_ELEMENT\u25A0";
1469
- Zai.prototype.extract = async function(input, schema, _options) {
1470
- const options = Options6.parse(_options ?? {});
1471
- const tokenizer = await this.getTokenizer();
1472
- const taskId = this.taskId;
1473
- const taskType = "zai.extract";
1474
- const PROMPT_COMPONENT = Math.max(this.Model.input.maxTokens - PROMPT_INPUT_BUFFER, 100);
1475
- let isArrayOfObjects = false;
1476
- const originalSchema = schema;
1477
- if (schema instanceof import_sdk9.default.ZodObject) {
1478
- } else if (schema instanceof import_sdk9.default.ZodArray) {
1479
- if (schema._def.type instanceof import_sdk9.default.ZodObject) {
1480
- isArrayOfObjects = true;
1481
- schema = schema._def.type;
1482
- } else {
1483
- throw new Error("Schema must be a ZodObject or a ZodArray<ZodObject>");
1484
- }
1485
- } else {
1486
- throw new Error("Schema must be either a ZuiObject or a ZuiArray<ZuiObject>");
1487
- }
1488
- const schemaTypescript = schema.toTypescript({ declaration: false });
1489
- const schemaLength = tokenizer.count(schemaTypescript);
1490
- options.chunkLength = Math.min(options.chunkLength, this.Model.input.maxTokens - PROMPT_INPUT_BUFFER - schemaLength);
1491
- const keys = Object.keys(schema.shape);
1492
- let inputAsString = stringify(input);
1493
- if (tokenizer.count(inputAsString) > options.chunkLength) {
1494
- if (isArrayOfObjects) {
1495
- const tokens = tokenizer.split(inputAsString);
1496
- const chunks = import_lodash4.default.chunk(tokens, options.chunkLength).map((x) => x.join(""));
1497
- const all = await Promise.all(chunks.map((chunk) => this.extract(chunk, originalSchema)));
1498
- return all.flat();
1499
- } else {
1500
- inputAsString = tokenizer.truncate(stringify(input), options.chunkLength);
1501
- }
1502
- }
1503
- const instructions = [];
1504
- if (options.instructions) {
1505
- instructions.push(options.instructions);
1506
- }
1507
- const shape = `{ ${keys.map((key) => `"${key}": ...`).join(", ")} }`;
1508
- const abbv = "{ ... }";
1509
- if (isArrayOfObjects) {
1510
- instructions.push("You may have multiple elements, or zero elements in the input.");
1511
- instructions.push("You must extract each element separately.");
1512
- instructions.push(`Each element must be a JSON object with exactly the format: ${START3}${shape}${END5}`);
1513
- instructions.push(`When you are done extracting all elements, type "${NO_MORE}" to finish.`);
1514
- instructions.push(`For example, if you have zero elements, the output should look like this: ${NO_MORE}`);
1515
- instructions.push(
1516
- `For example, if you have two elements, the output should look like this: ${START3}${abbv}${END5}${START3}${abbv}${END5}${NO_MORE}`
1517
- );
1518
- } else {
1519
- instructions.push("You may have exactly one element in the input.");
1520
- instructions.push(`The element must be a JSON object with exactly the format: ${START3}${shape}${END5}`);
1521
- }
1522
- const EXAMPLES_TOKENS = PROMPT_COMPONENT - tokenizer.count(inputAsString) - tokenizer.count(instructions.join("\n"));
1523
- const Key = fastHash(
1524
- JSON.stringify({
1525
- taskType,
1526
- taskId,
1527
- input: inputAsString,
1528
- instructions: options.instructions
1529
- })
1530
- );
1531
- const examples = taskId ? await this.adapter.getExamples({
1532
- input: inputAsString,
1533
- taskType,
1534
- taskId
1535
- }) : [];
1536
- const exactMatch = examples.find((x) => x.key === Key);
1537
- if (exactMatch) {
1538
- return exactMatch.output;
1539
- }
1540
- const defaultExample = isArrayOfObjects ? {
1541
- input: `The story goes as follow.
1542
- Once upon a time, there was a person named Alice who was 30 years old.
1543
- Then, there was a person named Bob who was 25 years old.
1544
- The end.`,
1545
- schema: "Array<{ name: string, age: number }>",
1546
- instructions: "Extract all people",
1547
- extracted: [
1548
- {
1549
- name: "Alice",
1550
- age: 30
1551
- },
1552
- {
1553
- name: "Bob",
1554
- age: 25
1555
- }
1556
- ]
1557
- } : {
1558
- input: `The story goes as follow.
1559
- Once upon a time, there was a person named Alice who was 30 years old.
1560
- The end.`,
1561
- schema: "{ name: string, age: number }",
1562
- instructions: "Extract the person",
1563
- extracted: { name: "Alice", age: 30 }
1564
- };
1565
- const userExamples = examples.map((e) => ({
1566
- input: e.input,
1567
- extracted: e.output,
1568
- schema: schemaTypescript,
1569
- instructions: options.instructions
1570
- }));
1571
- let exampleId = 1;
1572
- const formatInput = /* @__PURE__ */ __name((input2, schema2, instructions2) => {
1573
- const header = userExamples.length ? `Expert Example #${exampleId++}` : "Here's an example to help you understand the format:";
1574
- return `
1575
- ${header}
1576
-
1577
- <|start_schema|>
1578
- ${schema2}
1579
- <|end_schema|>
1580
-
1581
- <|start_instructions|>
1582
- ${instructions2 ?? "No specific instructions, just follow the schema above."}
1583
- <|end_instructions|>
1584
-
1585
- <|start_input|>
1586
- ${input2.trim()}
1587
- <|end_input|>
1588
- `.trim();
1589
- }, "formatInput");
1590
- const formatOutput = /* @__PURE__ */ __name((extracted) => {
1591
- extracted = import_lodash4.default.isArray(extracted) ? extracted : [extracted];
1592
- return extracted.map(
1593
- (x) => `
1594
- ${START3}
1595
- ${JSON.stringify(x, null, 2)}
1596
- ${END5}`.trim()
1597
- ).join("\n") + NO_MORE;
1598
- }, "formatOutput");
1599
- const formatExample = /* @__PURE__ */ __name((example) => [
1600
- {
1601
- type: "text",
1602
- content: formatInput(stringify(example.input ?? null), example.schema, example.instructions),
1603
- role: "user"
1604
- },
1605
- {
1606
- type: "text",
1607
- content: formatOutput(example.extracted),
1608
- role: "assistant"
1609
- }
1610
- ], "formatExample");
1611
- const allExamples = takeUntilTokens(
1612
- userExamples.length ? userExamples : [defaultExample],
1613
- EXAMPLES_TOKENS,
1614
- (el) => tokenizer.count(stringify(el.input)) + tokenizer.count(stringify(el.extracted))
1615
- ).map(formatExample).flat();
1616
- const output = await this.callModel({
1617
- systemPrompt: `
1618
- Extract the following information from the input:
1619
- ${schemaTypescript}
1620
- ====
1621
-
1622
- ${instructions.map((x) => `\u2022 ${x}`).join("\n")}
1623
- `.trim(),
1624
- stopSequences: [isArrayOfObjects ? NO_MORE : END5],
1625
- messages: [
1626
- ...allExamples,
1627
- {
1628
- role: "user",
1629
- type: "text",
1630
- content: formatInput(inputAsString, schemaTypescript, options.instructions ?? "")
1631
- }
1632
- ]
1633
- });
1634
- const answer = output.choices[0]?.content;
1635
- const elements = answer.split(START3).filter((x) => x.trim().length > 0).map((x) => {
1636
- try {
1637
- const json = x.slice(0, x.indexOf(END5)).trim();
1638
- const repairedJson = (0, import_jsonrepair.jsonrepair)(json);
1639
- const parsedJson = import_json5.default.parse(repairedJson);
1640
- return schema.parse(parsedJson);
1641
- } catch (error) {
1642
- throw new JsonParsingError(x, error instanceof Error ? error : new Error("Unknown error"));
1643
- }
1644
- }).filter((x) => x !== null);
1645
- let final;
1646
- if (isArrayOfObjects) {
1647
- final = elements;
1648
- } else if (elements.length === 0) {
1649
- final = schema.parse({});
1650
- } else {
1651
- final = elements[0];
1652
- }
1653
- if (taskId) {
1654
- await this.adapter.saveExample({
1655
- key: Key,
1656
- taskId: `zai/${taskId}`,
1657
- taskType,
1658
- instructions: options.instructions ?? "No specific instructions",
1659
- input: inputAsString,
1660
- output: final,
1661
- metadata: output.metadata
1662
- });
1663
- }
1664
- return final;
1665
- };
1666
-
1667
- // src/operations/label.ts
1668
- var import_sdk10 = __toESM(require("@botpress/sdk"), 1);
1669
- var import_lodash5 = __toESM(require("lodash"), 1);
1670
- var { z: z10 } = import_sdk10.default;
1671
- var LABELS = {
1672
- ABSOLUTELY_NOT: "ABSOLUTELY_NOT",
1673
- PROBABLY_NOT: "PROBABLY_NOT",
1674
- AMBIGUOUS: "AMBIGUOUS",
1675
- PROBABLY_YES: "PROBABLY_YES",
1676
- ABSOLUTELY_YES: "ABSOLUTELY_YES"
1677
- };
1678
- var ALL_LABELS = Object.values(LABELS).join(" | ");
1679
- var Options7 = z10.object({
1680
- examples: z10.array(
1681
- z10.object({
1682
- input: z10.any(),
1683
- labels: z10.record(z10.object({ label: z10.enum(ALL_LABELS), explanation: z10.string().optional() }))
1684
- })
1685
- ).default([]).describe("Examples to help the user make a decision"),
1686
- instructions: z10.string().optional().describe("Instructions to guide the user on how to extract the data"),
1687
- chunkLength: z10.number().min(100).max(1e5).optional().describe("The maximum number of tokens per chunk").default(16e3)
1688
- });
1689
- var Labels = z10.record(z10.string().min(1).max(250), z10.string()).superRefine((labels, ctx) => {
1690
- const keys = Object.keys(labels);
1691
- for (const key of keys) {
1692
- if (key.length < 1 || key.length > 250) {
1693
- ctx.addIssue({ message: `The label key "${key}" must be between 1 and 250 characters long`, code: "custom" });
1694
- }
1695
- if (keys.lastIndexOf(key) !== keys.indexOf(key)) {
1696
- ctx.addIssue({ message: `Duplicate label: ${labels[key]}`, code: "custom" });
1697
- }
1698
- if (/[^a-zA-Z0-9_]/.test(key)) {
1699
- ctx.addIssue({
1700
- message: `The label key "${key}" must only contain alphanumeric characters and underscores`,
1701
- code: "custom"
1702
- });
1703
- }
1704
- }
1705
- return true;
1706
- });
1707
- var parseLabel = /* @__PURE__ */ __name((label) => {
1708
- label = label.toUpperCase().replace(/\s+/g, "_").replace(/_{2,}/g, "_").trim();
1709
- if (label.includes("ABSOLUTELY") && label.includes("NOT")) {
1710
- return LABELS.ABSOLUTELY_NOT;
1711
- } else if (label.includes("NOT")) {
1712
- return LABELS.PROBABLY_NOT;
1713
- } else if (label.includes("AMBIGUOUS")) {
1714
- return LABELS.AMBIGUOUS;
1715
- }
1716
- if (label.includes("YES")) {
1717
- return LABELS.PROBABLY_YES;
1718
- } else if (label.includes("ABSOLUTELY") && label.includes("YES")) {
1719
- return LABELS.ABSOLUTELY_YES;
1720
- }
1721
- return LABELS.AMBIGUOUS;
1722
- }, "parseLabel");
1723
- Zai.prototype.label = async function(input, _labels, _options) {
1724
- const options = Options7.parse(_options ?? {});
1725
- const labels = Labels.parse(_labels);
1726
- const tokenizer = await this.getTokenizer();
1727
- const taskId = this.taskId;
1728
- const taskType = "zai.label";
1729
- const TOTAL_MAX_TOKENS = import_lodash5.default.clamp(options.chunkLength, 1e3, this.Model.input.maxTokens - PROMPT_INPUT_BUFFER);
1730
- const CHUNK_EXAMPLES_MAX_TOKENS = import_lodash5.default.clamp(Math.floor(TOTAL_MAX_TOKENS * 0.5), 250, 1e4);
1731
- const CHUNK_INPUT_MAX_TOKENS = import_lodash5.default.clamp(
1732
- TOTAL_MAX_TOKENS - CHUNK_EXAMPLES_MAX_TOKENS,
1733
- TOTAL_MAX_TOKENS * 0.5,
1734
- TOTAL_MAX_TOKENS
1735
- );
1736
- const inputAsString = stringify(input);
1737
- if (tokenizer.count(inputAsString) > CHUNK_INPUT_MAX_TOKENS) {
1738
- const tokens = tokenizer.split(inputAsString);
1739
- const chunks = import_lodash5.default.chunk(tokens, CHUNK_INPUT_MAX_TOKENS).map((x) => x.join(""));
1740
- const allLabels = await Promise.all(chunks.map((chunk) => this.label(chunk, _labels)));
1741
- return allLabels.reduce((acc, x) => {
1742
- Object.keys(x).forEach((key) => {
1743
- if (acc[key] === true) {
1744
- acc[key] = true;
1745
- } else {
1746
- acc[key] = acc[key] || x[key];
1747
- }
1748
- });
1749
- return acc;
1750
- }, {});
1751
- }
1752
- const END6 = "\u25A0END\u25A0";
1753
- const Key = fastHash(
1754
- JSON.stringify({
1755
- taskType,
1756
- taskId,
1757
- input: inputAsString,
1758
- instructions: options.instructions ?? ""
1759
- })
1760
- );
1761
- const convertToAnswer = /* @__PURE__ */ __name((mapping) => {
1762
- return Object.keys(labels).reduce((acc, key) => {
1763
- acc[key] = mapping[key]?.label === "ABSOLUTELY_YES" || mapping[key]?.label === "PROBABLY_YES";
1764
- return acc;
1765
- }, {});
1766
- }, "convertToAnswer");
1767
- const examples = taskId ? await this.adapter.getExamples({
1768
- input: inputAsString,
1769
- taskType,
1770
- taskId
1771
- }) : [];
1772
- options.examples.forEach((example) => {
1773
- examples.push({
1774
- key: fastHash(JSON.stringify(example)),
1775
- input: example.input,
1776
- similarity: 1,
1777
- explanation: "",
1778
- output: example.labels
1779
- });
1780
- });
1781
- const exactMatch = examples.find((x) => x.key === Key);
1782
- if (exactMatch) {
1783
- return convertToAnswer(exactMatch.output);
1784
- }
1785
- const allExamples = takeUntilTokens(
1786
- examples,
1787
- CHUNK_EXAMPLES_MAX_TOKENS,
1788
- (el) => tokenizer.count(stringify(el.input)) + tokenizer.count(stringify(el.output)) + tokenizer.count(el.explanation ?? "") + 100
1789
- ).map((example, idx) => [
1790
- {
1791
- type: "text",
1792
- role: "user",
1793
- content: `
1794
- Expert Example #${idx + 1}
1795
-
1796
- <|start_input|>
1797
- ${stringify(example.input)}
1798
- <|end_input|>`.trim()
1799
- },
1800
- {
1801
- type: "text",
1802
- role: "assistant",
1803
- content: `
1804
- Expert Example #${idx + 1}
1805
- ============
1806
- ${Object.keys(example.output).map(
1807
- (key) => `
1808
- \u25A0${key}:\u3010${example.output[key]?.explanation}\u3011:${example.output[key]?.label}\u25A0
1809
- `.trim()
1810
- ).join("\n")}
1811
- ${END6}
1812
- `.trim()
1813
- }
1814
- ]).flat();
1815
- const format = Object.keys(labels).map((key) => {
1816
- return `
1817
- \u25A0${key}:\u3010explanation (where "explanation" is answering the question "${labels[key]}")\u3011:x\u25A0 (where x is ${ALL_LABELS})
1818
- `.trim();
1819
- }).join("\n\n");
1820
- const output = await this.callModel({
1821
- stopSequences: [END6],
1822
- systemPrompt: `
1823
- You need to tag the input with the following labels based on the question asked:
1824
- ${LABELS.ABSOLUTELY_NOT}: You are absolutely sure that the answer is "NO" to the question.
1825
- ${LABELS.PROBABLY_NOT}: You are leaning towards "NO" to the question.
1826
- ${LABELS.AMBIGUOUS}: You are unsure about the answer to the question.
1827
- ${LABELS.PROBABLY_YES}: You are leaning towards "YES" to the question.
1828
- ${LABELS.ABSOLUTELY_YES}: You are absolutely sure that the answer is "YES" to the question.
1829
-
1830
- You need to return a mapping of the labels, an explanation and the answer for each label following the format below:
1831
- \`\`\`
1832
- ${format}
1833
- ${END6}
1834
- \`\`\`
1835
-
1836
- ${options.instructions}
1837
-
1838
- ===
1839
- You should consider the Expert Examples below to help you make your decision.
1840
- In your "Analysis", please refer to the Expert Examples # to justify your decision.
1841
- `.trim(),
1842
- messages: [
1843
- ...allExamples,
1844
- {
1845
- type: "text",
1846
- role: "user",
1847
- content: `
1848
- Input to tag:
1849
- <|start_input|>
1850
- ${inputAsString}
1851
- <|end_input|>
1852
-
1853
- Answer with this following format:
1854
- \`\`\`
1855
- ${format}
1856
- ${END6}
1857
- \`\`\`
1858
-
1859
- Format cheatsheet:
1860
- \`\`\`
1861
- \u25A0label:\u3010explanation\u3011:x\u25A0
1862
- \`\`\`
1863
-
1864
- Where \`x\` is one of the following: ${ALL_LABELS}
1865
-
1866
- Remember: In your \`explanation\`, please refer to the Expert Examples # (and quote them) that are relevant to ground your decision-making process.
1867
- The Expert Examples are there to help you make your decision. They have been provided by experts in the field and their answers (and reasoning) are considered the ground truth and should be used as a reference to make your decision when applicable.
1868
- For example, you can say: "According to Expert Example #1, ..."`.trim()
1869
- }
1870
- ]
1871
- });
1872
- const answer = output.choices[0].content;
1873
- const final = Object.keys(labels).reduce((acc, key) => {
1874
- const match = answer.match(new RegExp(`\u25A0${key}:\u3010(.+)\u3011:(\\w{2,})\u25A0`, "i"));
1875
- if (match) {
1876
- const explanation = match[1].trim();
1877
- const label = parseLabel(match[2]);
1878
- acc[key] = {
1879
- explanation,
1880
- label
1881
- };
1882
- } else {
1883
- acc[key] = {
1884
- explanation: "",
1885
- label: LABELS.AMBIGUOUS
1886
- };
1887
- }
1888
- return acc;
1889
- }, {});
1890
- if (taskId) {
1891
- await this.adapter.saveExample({
1892
- key: Key,
1893
- taskType,
1894
- taskId,
1895
- instructions: options.instructions ?? "",
1896
- metadata: output.metadata,
1897
- input: inputAsString,
1898
- output: final
1899
- });
1900
- }
1901
- return convertToAnswer(final);
1902
- };
1903
- //# sourceMappingURL=index.cjs.map