@llumiverse/core 0.12.3 → 0.14.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 (95) hide show
  1. package/README.md +13 -11
  2. package/lib/cjs/CompletionStream.js +6 -8
  3. package/lib/cjs/CompletionStream.js.map +1 -1
  4. package/lib/cjs/Driver.js +20 -16
  5. package/lib/cjs/Driver.js.map +1 -1
  6. package/lib/cjs/async.js +9 -6
  7. package/lib/cjs/async.js.map +1 -1
  8. package/lib/cjs/formatters/claude.js +53 -15
  9. package/lib/cjs/formatters/claude.js.map +1 -1
  10. package/lib/cjs/formatters/commons.js +2 -3
  11. package/lib/cjs/formatters/commons.js.map +1 -1
  12. package/lib/cjs/formatters/generic.js +2 -2
  13. package/lib/cjs/formatters/generic.js.map +1 -1
  14. package/lib/cjs/formatters/index.js +2 -1
  15. package/lib/cjs/formatters/index.js.map +1 -1
  16. package/lib/cjs/formatters/llama2.js +1 -2
  17. package/lib/cjs/formatters/llama2.js.map +1 -1
  18. package/lib/cjs/formatters/llama3.js +42 -0
  19. package/lib/cjs/formatters/llama3.js.map +1 -0
  20. package/lib/cjs/formatters/openai.js +59 -5
  21. package/lib/cjs/formatters/openai.js.map +1 -1
  22. package/lib/cjs/index.js +1 -0
  23. package/lib/cjs/index.js.map +1 -1
  24. package/lib/cjs/json.js +3 -3
  25. package/lib/cjs/json.js.map +1 -1
  26. package/lib/cjs/resolver.js +45 -0
  27. package/lib/cjs/resolver.js.map +1 -0
  28. package/lib/cjs/stream.js +11 -0
  29. package/lib/cjs/stream.js.map +1 -0
  30. package/lib/cjs/types.js.map +1 -1
  31. package/lib/cjs/validation.js +43 -6
  32. package/lib/cjs/validation.js.map +1 -1
  33. package/lib/esm/CompletionStream.js +6 -8
  34. package/lib/esm/CompletionStream.js.map +1 -1
  35. package/lib/esm/Driver.js +19 -15
  36. package/lib/esm/Driver.js.map +1 -1
  37. package/lib/esm/async.js +4 -1
  38. package/lib/esm/async.js.map +1 -1
  39. package/lib/esm/formatters/claude.js +52 -13
  40. package/lib/esm/formatters/claude.js.map +1 -1
  41. package/lib/esm/formatters/commons.js +1 -1
  42. package/lib/esm/formatters/commons.js.map +1 -1
  43. package/lib/esm/formatters/index.js +2 -1
  44. package/lib/esm/formatters/index.js.map +1 -1
  45. package/lib/esm/formatters/llama3.js +39 -0
  46. package/lib/esm/formatters/llama3.js.map +1 -0
  47. package/lib/esm/formatters/openai.js +57 -3
  48. package/lib/esm/formatters/openai.js.map +1 -1
  49. package/lib/esm/index.js +1 -0
  50. package/lib/esm/index.js.map +1 -1
  51. package/lib/esm/resolver.js +42 -0
  52. package/lib/esm/resolver.js.map +1 -0
  53. package/lib/esm/stream.js +8 -0
  54. package/lib/esm/stream.js.map +1 -0
  55. package/lib/esm/types.js.map +1 -1
  56. package/lib/esm/validation.js +38 -4
  57. package/lib/esm/validation.js.map +1 -1
  58. package/lib/types/CompletionStream.d.ts +5 -5
  59. package/lib/types/CompletionStream.d.ts.map +1 -1
  60. package/lib/types/Driver.d.ts +5 -5
  61. package/lib/types/Driver.d.ts.map +1 -1
  62. package/lib/types/async.d.ts +1 -1
  63. package/lib/types/async.d.ts.map +1 -1
  64. package/lib/types/formatters/claude.d.ts +12 -6
  65. package/lib/types/formatters/claude.d.ts.map +1 -1
  66. package/lib/types/formatters/index.d.ts +2 -1
  67. package/lib/types/formatters/index.d.ts.map +1 -1
  68. package/lib/types/formatters/llama3.d.ts +7 -0
  69. package/lib/types/formatters/llama3.d.ts.map +1 -0
  70. package/lib/types/formatters/openai.d.ts +18 -1
  71. package/lib/types/formatters/openai.d.ts.map +1 -1
  72. package/lib/types/index.d.ts +1 -0
  73. package/lib/types/index.d.ts.map +1 -1
  74. package/lib/types/resolver.d.ts +2 -0
  75. package/lib/types/resolver.d.ts.map +1 -0
  76. package/lib/types/stream.d.ts +2 -0
  77. package/lib/types/stream.d.ts.map +1 -0
  78. package/lib/types/types.d.ts +9 -6
  79. package/lib/types/types.d.ts.map +1 -1
  80. package/lib/types/validation.d.ts +1 -2
  81. package/lib/types/validation.d.ts.map +1 -1
  82. package/package.json +87 -85
  83. package/src/CompletionStream.ts +4 -10
  84. package/src/Driver.ts +28 -27
  85. package/src/async.ts +5 -1
  86. package/src/formatters/claude.ts +68 -19
  87. package/src/formatters/commons.ts +1 -1
  88. package/src/formatters/index.ts +5 -3
  89. package/src/formatters/llama3.ts +55 -0
  90. package/src/formatters/openai.ts +93 -6
  91. package/src/index.ts +2 -1
  92. package/src/resolver.ts +39 -0
  93. package/src/stream.ts +8 -0
  94. package/src/types.ts +16 -13
  95. package/src/validation.ts +48 -7
@@ -1,19 +1,41 @@
1
1
  import { PromptRole } from "../index.js";
2
+ import { readStreamAsBase64 } from "../stream.js";
2
3
  import { PromptSegment } from "../types.js";
3
4
 
5
+
4
6
  export interface OpenAITextMessage {
5
7
  content: string;
6
8
  role: "system" | "user" | "assistant";
7
9
  }
10
+
11
+ export interface OpenAIMessage {
12
+ content: (OpenAIContentPartText | OpenAIContentPartImage)[]
13
+ role: "system" | "user" | "assistant";
14
+ name?: string;
15
+ }
16
+
17
+ export interface OpenAIContentPartText {
18
+ type: "text";
19
+ text: string
20
+ }
21
+
22
+ export interface OpenAIContentPartImage {
23
+ type: "image_url";
24
+ image_url: {
25
+ detail?: 'auto' | 'low' | 'high'
26
+ url: string
27
+ }
28
+ }
29
+
8
30
  /**
9
31
  * OpenAI text only prompts
10
- * @param segments
11
- * @returns
32
+ * @param segments
33
+ * @returns
12
34
  */
13
- export function formatOpenAILikePrompt(segments: PromptSegment[]) {
35
+ export function formatOpenAILikeTextPrompt(segments: PromptSegment[]): OpenAITextMessage[] {
14
36
  const system: OpenAITextMessage[] = [];
15
- const others: OpenAITextMessage[] = [];
16
37
  const safety: OpenAITextMessage[] = [];
38
+ const user: OpenAITextMessage[] = [];
17
39
 
18
40
  for (const msg of segments) {
19
41
  if (msg.role === PromptRole.system) {
@@ -21,10 +43,75 @@ export function formatOpenAILikePrompt(segments: PromptSegment[]) {
21
43
  } else if (msg.role === PromptRole.safety) {
22
44
  safety.push({ content: "IMPORTANT: " + msg.content, role: "system" });
23
45
  } else {
24
- others.push({ content: msg.content, role: "user" });
46
+ user.push({
47
+ content: msg.content,
48
+ role: msg.role || 'user',
49
+ })
25
50
  }
26
51
  }
27
52
 
28
53
  // put system mesages first and safety last
29
- return system.concat(others).concat(safety);
54
+ return system.concat(user).concat(safety);
30
55
  }
56
+
57
+ export async function formatOpenAILikeMultimodalPrompt(segments: PromptSegment[]): Promise<OpenAIMessage[]> {
58
+ const system: OpenAIMessage[] = [];
59
+ const safety: OpenAIMessage[] = [];
60
+ const others: OpenAIMessage[] = [];
61
+
62
+ for (const msg of segments) {
63
+
64
+ const parts: (OpenAIContentPartImage | OpenAIContentPartText)[] = [];
65
+
66
+ //generate the parts based on promptsegment
67
+ if (msg.files) {
68
+ for (const file of msg.files) {
69
+ const stream = await file.getStream();
70
+ const data = await readStreamAsBase64(stream);
71
+ parts.push({
72
+ image_url: { url: `data:${file.mime_type || "image/jpeg"};base64,${data}` },
73
+ type: "image_url"
74
+ })
75
+ }
76
+ } else {
77
+ parts.push({
78
+ text: msg.content,
79
+ type: "text"
80
+ })
81
+ }
82
+
83
+
84
+
85
+ if (msg.role === PromptRole.system) {
86
+ system.push({
87
+ role: "system",
88
+ content: parts
89
+ })
90
+
91
+ } else if (msg.role === PromptRole.safety) {
92
+ const safetyMsg: OpenAIMessage = {
93
+ role: "system",
94
+ content: parts
95
+ }
96
+
97
+ safetyMsg.content.forEach(c => {
98
+ if (c.type === "text") c.text = "DO NOT IGNORE - IMPORTANT: " + c.text;
99
+ })
100
+
101
+ system.push(safetyMsg)
102
+
103
+ } else {
104
+ others.push({
105
+ role: msg.role ?? 'user',
106
+ content: parts
107
+ })
108
+ }
109
+
110
+
111
+
112
+ }
113
+
114
+ // put system mesages first and safety last
115
+ return system.concat(others).concat(safety);
116
+
117
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./Driver.js";
2
2
  export * from "./json.js";
3
- export * from "./types.js";
3
+ export * from "./stream.js";
4
+ export * from "./types.js";
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Get the property named by "name" of the given object
3
+ * If an array is idnexed using a string key then a map is done and an array with the content of the properties with that name are returned
4
+ * Ex: docs.text => will return an array of text properties of the docs array
5
+ * @param object the obejct
6
+ * @param name the name of the property.
7
+ * @returns the property value
8
+ */
9
+ function _prop(object: any, name: string) {
10
+ if (object === undefined) {
11
+ return undefined;
12
+ }
13
+ if (Array.isArray(object)) {
14
+ const index = +name;
15
+ if (isNaN(index)) {
16
+ // map array to property
17
+ return object.map(item => item[name]);
18
+ } else {
19
+ return object[index];
20
+ }
21
+ } else {
22
+ return object[name];
23
+ }
24
+
25
+ }
26
+
27
+ export function resolveField(object: any, path: string[]) {
28
+ let p = object as any;
29
+ if (!p) return p;
30
+ if (!path.length) return p;
31
+ const last = path.length - 1;
32
+ for (let i = 0; i < last; i++) {
33
+ p = _prop(p, path[i])
34
+ if (!p) {
35
+ return undefined;
36
+ }
37
+ }
38
+ return _prop(p, path[last]);
39
+ }
package/src/stream.ts ADDED
@@ -0,0 +1,8 @@
1
+
2
+ export async function readStreamAsBase64(stream: ReadableStream) {
3
+ const out: Buffer[] = [];
4
+ for await (const chunk of stream as any) {
5
+ out.push(Buffer.from(chunk));
6
+ }
7
+ return Buffer.concat(out).toString('base64');
8
+ }
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { JSONSchema4 } from "json-schema";
2
- import { JSONObject } from "./json.js";
3
2
  import { PromptFormatter } from "./formatters/index.js";
3
+ import { JSONObject } from "./json.js";
4
4
 
5
5
  export interface EmbeddingsOptions {
6
6
  /**
@@ -12,7 +12,7 @@ export interface EmbeddingsOptions {
12
12
  */
13
13
  model?: string;
14
14
  /**
15
- * Additional options for the embeddings generation. Optional.
15
+ * Additional options for the embeddings generation. Optional.
16
16
  * The supported properties depends on the target implementation.
17
17
  */
18
18
  [key: string]: any;
@@ -44,7 +44,7 @@ export interface ResultValidationError {
44
44
  }
45
45
 
46
46
  export interface Completion<ResultT = any> {
47
- // the driver impl must return the result and optionally the token_usage. the execution time is computed by the extended abstract driver
47
+ // the driver impl must return the result and optionally the token_usage. the execution time is computed by the extended abstract driver
48
48
  result: ResultT;
49
49
  token_usage?: ExecutionTokenUsage;
50
50
 
@@ -55,7 +55,7 @@ export interface Completion<ResultT = any> {
55
55
 
56
56
  /**
57
57
  * Set only if a result validation error occured, otherwise if the result is valid the error field is undefined
58
- * This can only be set if the resultSchema is set and the reuslt could not be parsed as a json or if the result does not match the schema
58
+ * This can only be set if the result_schema is set and the reuslt could not be parsed as a json or if the result does not match the schema
59
59
  */
60
60
  error?: ResultValidationError;
61
61
 
@@ -93,18 +93,18 @@ export interface DriverOptions {
93
93
  export interface PromptOptions {
94
94
  model: string;
95
95
  /**
96
- * A custom formatter to use for format the final model prompt from the input prompt segments.
96
+ * A custom formatter to use for format the final model prompt from the input prompt segments.
97
97
  * If no one is specified the driver will choose a formatter compatible with the target model
98
98
  */
99
99
  format?: PromptFormatter;
100
- resultSchema?: JSONSchema4;
100
+ result_schema?: JSONSchema4;
101
101
  }
102
102
  export interface ExecutionOptions extends PromptOptions {
103
103
  temperature?: number;
104
104
  max_tokens?: number;
105
105
  stop_sequence?: string | string[];
106
106
 
107
- /**
107
+ /**
108
108
  * restricts the selection of tokens to the “k” most likely options, based on their probabilities
109
109
  * Lower values make the model more deterministic, more focused. Examples:
110
110
  * - 10 - result will be highly controlled anc contextually relevant
@@ -139,7 +139,7 @@ export interface ExecutionOptions extends PromptOptions {
139
139
 
140
140
  /**
141
141
  * If set to true the original response from the target LLM will be included in the response under the original_response field.
142
- * This is useful for debugging and for some advanced use cases.
142
+ * This is useful for debugging and for some advanced use cases.
143
143
  * It is ignored on streaming requests
144
144
  */
145
145
  include_original_response?: boolean;
@@ -156,6 +156,7 @@ export enum PromptRole {
156
156
  export interface PromptSegment {
157
157
  role: PromptRole;
158
158
  content: string;
159
+ files?: DataSource[]
159
160
  }
160
161
 
161
162
  export interface ExecutionTokenUsage {
@@ -177,8 +178,9 @@ export interface AIModel<ProviderKeys = string> {
177
178
  tags?: string[]; //tags for searching
178
179
  owner?: string; //owner of the model
179
180
  status?: AIModelStatus; //status of the model
180
- canStream?: boolean; //if the model's reponse can be streamed
181
- isCustom?: boolean; //if the model is a custom model (a trained model)
181
+ can_stream?: boolean; //if the model's reponse can be streamed
182
+ is_custom?: boolean; //if the model is a custom model (a trained model)
183
+ is_multimodal?: boolean //if the model support files and images
182
184
  }
183
185
 
184
186
  export enum AIModelStatus {
@@ -231,20 +233,21 @@ export enum ModelType {
231
233
 
232
234
  export interface DataSource {
233
235
  name: string;
234
- getStream(): ReadableStream<Uint8Array | string>;
236
+ mime_type?: string;
237
+ getStream(): Promise<ReadableStream<Uint8Array | string>>;
235
238
  getURL(): Promise<string>;
236
239
  }
237
240
 
238
241
  export interface TrainingOptions {
239
242
  name: string; // the new model name
240
- model: string; // the model to train
243
+ model: string; // the model to train
241
244
  params?: JSONObject; // the training parameters
242
245
  }
243
246
 
244
247
  export interface TrainingPromptOptions {
245
248
  segments: PromptSegment[];
246
249
  completion: string | JSONObject;
247
- model: string; // the model to train
250
+ model: string; // the model to train
248
251
  schema?: JSONSchema4; // the resuilt schema f any
249
252
  }
250
253
 
package/src/validation.ts CHANGED
@@ -1,7 +1,23 @@
1
- import { JSONSchema4, validate } from "json-schema";
1
+ import { Ajv } from 'ajv';
2
+ import addFormats from 'ajv-formats';
2
3
  import { extractAndParseJSON } from "./json.js";
4
+ import { resolveField } from './resolver.js';
3
5
  import { ResultValidationError } from "./types.js";
4
6
 
7
+
8
+ const ajv = new Ajv({
9
+ coerceTypes: 'array',
10
+ allowDate: true,
11
+ strict: false,
12
+ useDefaults: true,
13
+ removeAdditional: "failing"
14
+ });
15
+
16
+ //use ts ignore to avoid error with ESM and ajv-formats
17
+ // @ts-ignore This expression is not callable
18
+ addFormats(ajv)
19
+
20
+
5
21
  export class ValidationError extends Error implements ResultValidationError {
6
22
  constructor(
7
23
  public code: 'validation_error' | 'json_error',
@@ -12,8 +28,9 @@ export class ValidationError extends Error implements ResultValidationError {
12
28
  }
13
29
  }
14
30
 
15
- export function validateResult(data: any, schema: JSONSchema4) {
31
+ export function validateResult(data: any, schema: Object) {
16
32
  let json;
33
+
17
34
  if (typeof data === "string") {
18
35
  try {
19
36
  json = extractAndParseJSON(data);
@@ -23,11 +40,35 @@ export function validateResult(data: any, schema: JSONSchema4) {
23
40
  } else {
24
41
  json = data;
25
42
  }
26
- const validation = validate(json, schema);
27
- if (!validation.valid) {
28
- throw new ValidationError(
29
- "validation_error",
30
- validation.errors.map(e => e.message).join(",\n"))
43
+
44
+ const validate = ajv.compile(schema);
45
+ const valid = validate(json);
46
+
47
+ if (!valid && validate.errors) {
48
+ let errors = [];
49
+
50
+ for (const e of validate.errors) {
51
+ const path = e.instancePath.split("/").slice(1);
52
+ const value = resolveField(json, path);
53
+ const schemaPath = e.schemaPath.split("/").slice(1);
54
+ const schemaFieldFormat = resolveField(schema, schemaPath);
55
+ const schemaField = resolveField(schema, schemaPath.slice(0, -3));
56
+
57
+ //ignore date if empty or null
58
+ if (!value
59
+ && ["date", "date-time"].includes(schemaFieldFormat)
60
+ && !schemaField?.required?.includes(path[path.length - 1])) {
61
+ continue;
62
+ } else {
63
+ errors.push(e);
64
+ }
65
+ }
66
+
67
+ //console.log("Errors", errors)
68
+ if (errors.length > 0) {
69
+ const errorsMessage = errors.map(e => `${e.instancePath}: ${e.message}\n${JSON.stringify(e.params)}`).join(",\n\n");
70
+ throw new ValidationError("validation_error", errorsMessage)
71
+ }
31
72
  }
32
73
 
33
74
  return json;