@botpress/zai 1.0.0-beta.9 → 1.0.1-beta.1

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 (62) hide show
  1. package/dist/csj/adapters/adapter.js +2 -0
  2. package/dist/csj/adapters/botpress-table.js +173 -0
  3. package/dist/csj/adapters/memory.js +12 -0
  4. package/dist/csj/index.js +9 -0
  5. package/dist/csj/models.js +387 -0
  6. package/dist/csj/operations/check.js +143 -0
  7. package/dist/csj/operations/constants.js +2 -0
  8. package/dist/csj/operations/errors.js +15 -0
  9. package/dist/csj/operations/extract.js +214 -0
  10. package/dist/csj/operations/filter.js +182 -0
  11. package/dist/csj/operations/label.js +242 -0
  12. package/dist/csj/operations/rewrite.js +113 -0
  13. package/dist/csj/operations/summarize.js +134 -0
  14. package/dist/csj/operations/text.js +48 -0
  15. package/dist/csj/utils.js +44 -0
  16. package/dist/csj/zai.js +142 -0
  17. package/dist/esm/adapters/adapter.js +5 -0
  18. package/dist/esm/adapters/botpress-table.js +194 -0
  19. package/dist/esm/adapters/memory.js +15 -0
  20. package/dist/esm/index.js +11 -0
  21. package/dist/esm/models.js +390 -0
  22. package/dist/esm/operations/check.js +149 -0
  23. package/dist/esm/operations/constants.js +6 -0
  24. package/dist/esm/operations/errors.js +18 -0
  25. package/dist/esm/operations/extract.js +217 -0
  26. package/dist/esm/operations/filter.js +189 -0
  27. package/dist/esm/operations/label.js +246 -0
  28. package/dist/esm/operations/rewrite.js +113 -0
  29. package/dist/esm/operations/summarize.js +134 -0
  30. package/dist/esm/operations/text.js +48 -0
  31. package/dist/esm/utils.js +51 -0
  32. package/dist/esm/zai.js +161 -0
  33. package/package.json +17 -13
  34. package/scripts/update-models.mts +76 -0
  35. package/scripts/update-types.mts +59 -0
  36. package/src/adapters/adapter.ts +35 -0
  37. package/src/adapters/botpress-table.ts +214 -0
  38. package/src/adapters/memory.ts +13 -0
  39. package/src/index.ts +11 -0
  40. package/src/models.ts +394 -0
  41. package/src/operations/__tests/botpress_docs.txt +26040 -0
  42. package/src/operations/__tests/cache.jsonl +101 -0
  43. package/src/operations/__tests/index.ts +86 -0
  44. package/src/operations/check.ts +188 -0
  45. package/src/operations/constants.ts +2 -0
  46. package/src/operations/errors.ts +9 -0
  47. package/src/operations/extract.ts +292 -0
  48. package/src/operations/filter.ts +232 -0
  49. package/src/operations/label.ts +333 -0
  50. package/src/operations/rewrite.ts +149 -0
  51. package/src/operations/summarize.ts +194 -0
  52. package/src/operations/text.ts +64 -0
  53. package/src/sdk-interfaces/llm/generateContent.ts +127 -0
  54. package/src/sdk-interfaces/llm/listLanguageModels.ts +19 -0
  55. package/src/utils.ts +62 -0
  56. package/src/zai.ts +193 -0
  57. package/dist/index.cjs +0 -1903
  58. package/dist/index.cjs.map +0 -1
  59. package/dist/index.d.cts +0 -916
  60. package/dist/index.d.ts +0 -916
  61. package/dist/index.js +0 -1873
  62. package/dist/index.js.map +0 -1
@@ -0,0 +1,142 @@
1
+ import sdk from "@botpress/sdk";
2
+ import { getWasmTokenizer } from "@botpress/wasm";
3
+ import { TableAdapter } from "./adapters/botpress-table";
4
+ import { MemoryAdapter } from "./adapters/memory";
5
+ import { Models } from "./models";
6
+ import { BotpressClient } from "./utils";
7
+ const { z } = sdk;
8
+ const ActiveLearning = z.object({
9
+ enable: z.boolean().describe("Whether to enable active learning").default(false),
10
+ tableName: z.string().regex(
11
+ /^[A-Za-z0-9_/-]{1,100}Table$/,
12
+ "Namespace must be alphanumeric and contain only letters, numbers, underscores, hyphens and slashes"
13
+ ).describe("The name of the table to store active learning tasks").default("ActiveLearningTable"),
14
+ taskId: z.string().regex(
15
+ /^[A-Za-z0-9_/-]{1,100}$/,
16
+ "Namespace must be alphanumeric and contain only letters, numbers, underscores, hyphens and slashes"
17
+ ).describe("The ID of the task").default("default")
18
+ });
19
+ const ZaiConfig = z.object({
20
+ client: BotpressClient,
21
+ userId: z.string().describe("The ID of the user consuming the API").optional(),
22
+ retry: z.object({ maxRetries: z.number().min(0).max(100) }).default({ maxRetries: 3 }),
23
+ modelId: z.custom(
24
+ (value) => {
25
+ if (typeof value !== "string" || !value.includes("__")) {
26
+ return false;
27
+ }
28
+ return true;
29
+ },
30
+ {
31
+ message: "Invalid model ID"
32
+ }
33
+ ).describe("The ID of the model you want to use").default("openai__gpt-4o-mini-2024-07-18"),
34
+ activeLearning: ActiveLearning.default({ enable: false }),
35
+ namespace: z.string().regex(
36
+ /^[A-Za-z0-9_/-]{1,100}$/,
37
+ "Namespace must be alphanumeric and contain only letters, numbers, underscores, hyphens and slashes"
38
+ ).default("zai")
39
+ });
40
+ export class Zai {
41
+ static tokenizer = null;
42
+ client;
43
+ originalConfig;
44
+ userId;
45
+ integration;
46
+ model;
47
+ retry;
48
+ Model;
49
+ namespace;
50
+ adapter;
51
+ activeLearning;
52
+ constructor(config) {
53
+ var _a;
54
+ this.originalConfig = config;
55
+ const parsed = ZaiConfig.parse(config);
56
+ this.client = parsed.client;
57
+ const [integration, modelId] = parsed.modelId.split("__");
58
+ if (!(integration == null ? void 0 : integration.length) || !(modelId == null ? void 0 : modelId.length)) {
59
+ throw new Error(`Invalid model ID: ${parsed.modelId}. Expected format: <integration>__<modelId>`);
60
+ }
61
+ this.integration = integration;
62
+ this.model = modelId;
63
+ this.namespace = parsed.namespace;
64
+ this.userId = parsed.userId;
65
+ this.retry = parsed.retry;
66
+ this.Model = Models.find((m) => m.id === parsed.modelId);
67
+ this.activeLearning = parsed.activeLearning;
68
+ this.adapter = ((_a = parsed.activeLearning) == null ? void 0 : _a.enable) ? new TableAdapter({ client: this.client, tableName: parsed.activeLearning.tableName }) : new MemoryAdapter([]);
69
+ }
70
+ /** @internal */
71
+ async callModel(props) {
72
+ let retries = this.retry.maxRetries;
73
+ while (retries-- >= 0) {
74
+ try {
75
+ return await this._callModel(props);
76
+ } catch (e) {
77
+ if (retries >= 0) {
78
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
79
+ } else {
80
+ throw new Error("Failed to call model after multiple retries");
81
+ }
82
+ }
83
+ }
84
+ throw new Error("Failed to call model after multiple retries");
85
+ }
86
+ /** @internal */
87
+ async _callModel(props) {
88
+ let retries = this.retry.maxRetries;
89
+ do {
90
+ const start = Date.now();
91
+ const input = {
92
+ messages: [],
93
+ temperature: 0,
94
+ topP: 1,
95
+ model: { id: this.model },
96
+ userId: this.userId,
97
+ ...props
98
+ };
99
+ const { output } = await this.client.callAction({
100
+ type: `${this.integration}:generateContent`,
101
+ input
102
+ });
103
+ const latency = Date.now() - start;
104
+ return {
105
+ ...output,
106
+ metadata: {
107
+ model: this.model,
108
+ latency,
109
+ cost: { input: output.usage.inputCost, output: output.usage.outputCost },
110
+ tokens: { input: output.usage.inputTokens, output: output.usage.outputTokens }
111
+ }
112
+ };
113
+ } while (--retries > 0);
114
+ }
115
+ async getTokenizer() {
116
+ Zai.tokenizer ??= await (async () => {
117
+ while (!getWasmTokenizer) {
118
+ await new Promise((resolve) => setTimeout(resolve, 25));
119
+ }
120
+ return getWasmTokenizer();
121
+ })();
122
+ return Zai.tokenizer;
123
+ }
124
+ get taskId() {
125
+ if (!this.activeLearning.enable) {
126
+ return void 0;
127
+ }
128
+ return `${this.namespace}/${this.activeLearning.taskId}`.replace(/\/+/g, "/");
129
+ }
130
+ with(options) {
131
+ return new Zai({
132
+ ...this.originalConfig,
133
+ ...options
134
+ });
135
+ }
136
+ learn(taskId) {
137
+ return new Zai({
138
+ ...this.originalConfig,
139
+ activeLearning: { ...this.activeLearning, taskId, enable: true }
140
+ });
141
+ }
142
+ }
@@ -0,0 +1,5 @@
1
+ class Adapter {
2
+ }
3
+ export {
4
+ Adapter
5
+ };
@@ -0,0 +1,194 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __spreadValues = (a, b) => {
7
+ for (var prop in b || (b = {}))
8
+ if (__hasOwnProp.call(b, prop))
9
+ __defNormalProp(a, prop, b[prop]);
10
+ if (__getOwnPropSymbols)
11
+ for (var prop of __getOwnPropSymbols(b)) {
12
+ if (__propIsEnum.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ }
15
+ return a;
16
+ };
17
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
18
+ import sdk from "@botpress/sdk";
19
+ const { z } = sdk;
20
+ import { BotpressClient, GenerationMetadata } from "../utils";
21
+ import { Adapter } from "./adapter";
22
+ const CRITICAL_TAGS = {
23
+ system: "true",
24
+ "schema-purpose": "active-learning",
25
+ "schema-version": "Oct-2024"
26
+ };
27
+ const OPTIONAL_TAGS = {
28
+ "x-studio-title": "Active Learning",
29
+ "x-studio-description": "Table for storing active learning tasks and examples",
30
+ "x-studio-readonly": "true",
31
+ "x-studio-icon": "lucide://atom",
32
+ "x-studio-color": "green"
33
+ };
34
+ const FACTOR = 30;
35
+ const Props = z.object({
36
+ client: BotpressClient,
37
+ tableName: z.string().regex(
38
+ /^[a-zA-Z0-9_]{1,45}Table$/,
39
+ "Table name must be lowercase and contain only letters, numbers and underscores"
40
+ )
41
+ });
42
+ const TableSchema = z.object({
43
+ taskType: z.string().describe("The type of the task (filter, extract, etc.)"),
44
+ taskId: z.string(),
45
+ key: z.string().describe("A unique key for the task (e.g. a hash of the input, taskId, taskType and instructions)"),
46
+ instructions: z.string(),
47
+ input: z.object({}).passthrough().describe("The input to the task"),
48
+ output: z.object({}).passthrough().describe("The expected output"),
49
+ explanation: z.string().nullable(),
50
+ metadata: GenerationMetadata,
51
+ status: z.enum(["pending", "rejected", "approved"]),
52
+ feedback: z.object({
53
+ rating: z.enum(["very-bad", "bad", "good", "very-good"]),
54
+ comment: z.string().nullable()
55
+ }).nullable().default(null)
56
+ });
57
+ const searchableColumns = ["input"];
58
+ const TableJsonSchema = Object.entries(TableSchema.shape).reduce((acc, [key, value]) => {
59
+ var _a, _b;
60
+ acc[key] = value.toJsonSchema();
61
+ (_b = (_a = acc[key])["x-zui"]) != null ? _b : _a["x-zui"] = {};
62
+ acc[key]["x-zui"].searchable = searchableColumns.includes(key);
63
+ return acc;
64
+ }, {});
65
+ class TableAdapter extends Adapter {
66
+ constructor(props) {
67
+ super();
68
+ __publicField(this, "client");
69
+ __publicField(this, "tableName");
70
+ __publicField(this, "status");
71
+ __publicField(this, "errors", []);
72
+ props = Props.parse(props);
73
+ this.client = props.client;
74
+ this.tableName = props.tableName;
75
+ this.status = "ready";
76
+ }
77
+ async getExamples({ taskType, taskId, input }) {
78
+ await this.assertTableExists();
79
+ const { rows } = await this.client.findTableRows({
80
+ table: this.tableName,
81
+ search: JSON.stringify({ value: input }).substring(0, 1023),
82
+ // Search is limited to 1024 characters
83
+ limit: 10,
84
+ // TODO
85
+ filter: {
86
+ // Proximity match of approved examples
87
+ taskType,
88
+ taskId,
89
+ status: "approved"
90
+ }
91
+ }).catch((err) => {
92
+ console.error(`Error fetching examples: ${err.message}`);
93
+ return { rows: [] };
94
+ });
95
+ return rows.map((row) => {
96
+ var _a;
97
+ return {
98
+ key: row.key,
99
+ input: row.input.value,
100
+ output: row.output.value,
101
+ explanation: row.explanation,
102
+ similarity: (_a = row.similarity) != null ? _a : 0
103
+ };
104
+ });
105
+ }
106
+ async saveExample({
107
+ key,
108
+ taskType,
109
+ taskId,
110
+ instructions,
111
+ input,
112
+ output,
113
+ explanation,
114
+ metadata,
115
+ status = "pending"
116
+ }) {
117
+ await this.assertTableExists();
118
+ await this.client.upsertTableRows({
119
+ table: this.tableName,
120
+ keyColumn: "key",
121
+ rows: [
122
+ {
123
+ key,
124
+ taskType,
125
+ taskId,
126
+ instructions,
127
+ input: { value: input },
128
+ output: { value: output },
129
+ explanation: explanation != null ? explanation : null,
130
+ status,
131
+ metadata
132
+ }
133
+ ]
134
+ }).catch(() => {
135
+ });
136
+ }
137
+ async assertTableExists() {
138
+ var _a, _b, _c;
139
+ if (this.status !== "ready") {
140
+ return;
141
+ }
142
+ const { table, created } = await this.client.getOrCreateTable({
143
+ table: this.tableName,
144
+ factor: FACTOR,
145
+ frozen: true,
146
+ isComputeEnabled: false,
147
+ tags: __spreadValues(__spreadValues({}, CRITICAL_TAGS), OPTIONAL_TAGS),
148
+ schema: TableJsonSchema
149
+ }).catch((err) => {
150
+ this.status = "error";
151
+ this.errors = [err.message];
152
+ return { table: null, created: false };
153
+ });
154
+ if (!table) {
155
+ return;
156
+ }
157
+ if (!created) {
158
+ const issues = [];
159
+ if (table.factor !== FACTOR) {
160
+ issues.push(`Factor is ${table.factor} instead of ${FACTOR}`);
161
+ }
162
+ if (table.frozen !== true) {
163
+ issues.push("Table is not frozen");
164
+ }
165
+ for (const [key, value] of Object.entries(CRITICAL_TAGS)) {
166
+ if (((_a = table.tags) == null ? void 0 : _a[key]) !== value) {
167
+ issues.push(`Tag ${key} is ${(_b = table.tags) == null ? void 0 : _b[key]} instead of ${value}`);
168
+ }
169
+ }
170
+ for (const key of Object.keys(TableJsonSchema)) {
171
+ const column = (_c = table.schema) == null ? void 0 : _c.properties[key];
172
+ const expected = TableJsonSchema[key];
173
+ if (!column) {
174
+ issues.push(`Column ${key} is missing`);
175
+ continue;
176
+ }
177
+ if (column.type !== expected.type) {
178
+ issues.push(`Column ${key} has type ${column.type} instead of ${expected.type}`);
179
+ }
180
+ if (expected["x-zui"].searchable && !column["x-zui"].searchable) {
181
+ issues.push(`Column ${key} is not searchable but should be`);
182
+ }
183
+ }
184
+ if (issues.length) {
185
+ this.status = "error";
186
+ this.errors = issues;
187
+ }
188
+ }
189
+ this.status = "initialized";
190
+ }
191
+ }
192
+ export {
193
+ TableAdapter
194
+ };
@@ -0,0 +1,15 @@
1
+ import { Adapter } from "./adapter";
2
+ class MemoryAdapter extends Adapter {
3
+ constructor(examples) {
4
+ super();
5
+ this.examples = examples;
6
+ }
7
+ async getExamples() {
8
+ return this.examples;
9
+ }
10
+ async saveExample() {
11
+ }
12
+ }
13
+ export {
14
+ MemoryAdapter
15
+ };
@@ -0,0 +1,11 @@
1
+ import { Zai } from "./zai";
2
+ import "./operations/text";
3
+ import "./operations/rewrite";
4
+ import "./operations/summarize";
5
+ import "./operations/check";
6
+ import "./operations/filter";
7
+ import "./operations/extract";
8
+ import "./operations/label";
9
+ export {
10
+ Zai
11
+ };