@llumiverse/core 0.20.0 → 0.22.0-dev.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 (48) hide show
  1. package/lib/cjs/CompletionStream.js +125 -37
  2. package/lib/cjs/CompletionStream.js.map +1 -1
  3. package/lib/cjs/Driver.js +4 -1
  4. package/lib/cjs/Driver.js.map +1 -1
  5. package/lib/cjs/async.js.map +1 -1
  6. package/lib/cjs/formatters/index.js +0 -1
  7. package/lib/cjs/formatters/index.js.map +1 -1
  8. package/lib/cjs/stream.js +16 -8
  9. package/lib/cjs/stream.js.map +1 -1
  10. package/lib/cjs/validation.js +15 -7
  11. package/lib/cjs/validation.js.map +1 -1
  12. package/lib/esm/CompletionStream.js +125 -37
  13. package/lib/esm/CompletionStream.js.map +1 -1
  14. package/lib/esm/Driver.js +4 -1
  15. package/lib/esm/Driver.js.map +1 -1
  16. package/lib/esm/async.js.map +1 -1
  17. package/lib/esm/formatters/index.js +0 -1
  18. package/lib/esm/formatters/index.js.map +1 -1
  19. package/lib/esm/stream.js +16 -8
  20. package/lib/esm/stream.js.map +1 -1
  21. package/lib/esm/validation.js +15 -7
  22. package/lib/esm/validation.js.map +1 -1
  23. package/lib/tsconfig.tsbuildinfo +1 -0
  24. package/lib/types/CompletionStream.d.ts +3 -3
  25. package/lib/types/CompletionStream.d.ts.map +1 -1
  26. package/lib/types/Driver.d.ts +3 -3
  27. package/lib/types/Driver.d.ts.map +1 -1
  28. package/lib/types/async.d.ts +2 -2
  29. package/lib/types/async.d.ts.map +1 -1
  30. package/lib/types/formatters/index.d.ts +0 -1
  31. package/lib/types/formatters/index.d.ts.map +1 -1
  32. package/lib/types/stream.d.ts.map +1 -1
  33. package/lib/types/validation.d.ts +2 -2
  34. package/lib/types/validation.d.ts.map +1 -1
  35. package/package.json +8 -8
  36. package/src/CompletionStream.ts +123 -41
  37. package/src/Driver.ts +7 -5
  38. package/src/async.ts +4 -4
  39. package/src/formatters/index.ts +0 -1
  40. package/src/stream.ts +19 -9
  41. package/src/validation.ts +15 -10
  42. package/lib/cjs/formatters/openai.js +0 -113
  43. package/lib/cjs/formatters/openai.js.map +0 -1
  44. package/lib/esm/formatters/openai.js +0 -109
  45. package/lib/esm/formatters/openai.js.map +0 -1
  46. package/lib/types/formatters/openai.d.ts +0 -41
  47. package/lib/types/formatters/openai.d.ts.map +0 -1
  48. package/src/formatters/openai.ts +0 -159
@@ -1,76 +1,140 @@
1
- import { AbstractDriver } from "./Driver.js";
2
1
  import { CompletionStream, DriverOptions, ExecutionOptions, ExecutionResponse, ExecutionTokenUsage } from "@llumiverse/common";
2
+ import { AbstractDriver } from "./Driver.js";
3
3
 
4
4
  export class DefaultCompletionStream<PromptT = any> implements CompletionStream<PromptT> {
5
5
 
6
- chunks: string[];
6
+ chunks: number; // Counter for number of chunks instead of storing strings
7
7
  completion: ExecutionResponse<PromptT> | undefined;
8
8
 
9
9
  constructor(public driver: AbstractDriver<DriverOptions, PromptT>,
10
10
  public prompt: PromptT,
11
11
  public options: ExecutionOptions) {
12
- this.chunks = [];
12
+ this.chunks = 0;
13
13
  }
14
14
 
15
15
  async *[Symbol.asyncIterator]() {
16
16
  // reset state
17
17
  this.completion = undefined;
18
- if (this.chunks.length > 0) {
19
- this.chunks = [];
20
- }
21
- const chunks = this.chunks;
18
+ this.chunks = 0;
19
+ const accumulatedResults: any[] = []; // Accumulate CompletionResult[] from chunks
22
20
 
23
21
  this.driver.logger.debug(
24
- `[${this.driver.provider}] Streaming Execution of ${this.options.model} with prompt`, this.prompt,
22
+ `[${this.driver.provider}] Streaming Execution of ${this.options.model} with prompt`,
25
23
  );
26
24
 
27
25
  const start = Date.now();
28
- const stream = await this.driver.requestTextCompletionStream(this.prompt, this.options);
29
-
30
26
  let finish_reason: string | undefined = undefined;
31
27
  let promptTokens: number = 0;
32
28
  let resultTokens: number | undefined = undefined;
33
- for await (const chunk of stream) {
34
- if (chunk) {
35
- if (typeof chunk === 'string') {
36
- chunks.push(chunk);
37
- yield chunk;
38
- } else {
39
- if (chunk.finish_reason) { //Do not replace non-null values with null values
40
- finish_reason = chunk.finish_reason; //Used to skip empty finish_reason chunks coming after "stop" or "length"
41
- }
42
- if (chunk.token_usage) {
43
- //Tokens returned include prior parts of stream,
44
- //so overwrite rather than accumulate
45
- //Math.max used as some models report final token count at beginning of stream
46
- promptTokens = Math.max(promptTokens, chunk.token_usage.prompt ?? 0);
47
- resultTokens = Math.max(resultTokens ?? 0, chunk.token_usage.result ?? 0);
48
- }
49
- if (chunk.result) {
50
- chunks.push(chunk.result);
51
- yield chunk.result;
29
+
30
+ try {
31
+ const stream = await this.driver.requestTextCompletionStream(this.prompt, this.options);
32
+ for await (const chunk of stream) {
33
+ if (chunk) {
34
+ if (typeof chunk === 'string') {
35
+ this.chunks++;
36
+ yield chunk;
37
+ } else {
38
+ if (chunk.finish_reason) { //Do not replace non-null values with null values
39
+ finish_reason = chunk.finish_reason; //Used to skip empty finish_reason chunks coming after "stop" or "length"
40
+ }
41
+ if (chunk.token_usage) {
42
+ //Tokens returned include prior parts of stream,
43
+ //so overwrite rather than accumulate
44
+ //Math.max used as some models report final token count at beginning of stream
45
+ promptTokens = Math.max(promptTokens, chunk.token_usage.prompt ?? 0);
46
+ resultTokens = Math.max(resultTokens ?? 0, chunk.token_usage.result ?? 0);
47
+ }
48
+ if (Array.isArray(chunk.result) && chunk.result.length > 0) {
49
+ // Process each result in the chunk, combining consecutive text/JSON
50
+ for (const result of chunk.result) {
51
+ // Check if we can combine with the last accumulated result
52
+ const lastResult = accumulatedResults[accumulatedResults.length - 1];
53
+
54
+ if (lastResult &&
55
+ ((lastResult.type === 'text' && result.type === 'text') ||
56
+ (lastResult.type === 'json' && result.type === 'json'))) {
57
+ // Combine consecutive text or JSON results
58
+ if (result.type === 'text') {
59
+ lastResult.value += result.value;
60
+ } else if (result.type === 'json') {
61
+ // For JSON, combine the parsed objects directly
62
+ try {
63
+ const lastParsed = lastResult.value;
64
+ const currentParsed = result.value;
65
+ if (lastParsed !== null && typeof lastParsed === 'object' &&
66
+ currentParsed !== null && typeof currentParsed === 'object') {
67
+ const combined = { ...lastParsed, ...currentParsed };
68
+ lastResult.value = combined;
69
+ } else {
70
+ // If not objects, convert to string and concatenate
71
+ const lastStr = typeof lastParsed === 'string' ? lastParsed : JSON.stringify(lastParsed);
72
+ const currentStr = typeof currentParsed === 'string' ? currentParsed : JSON.stringify(currentParsed);
73
+ lastResult.value = lastStr + currentStr;
74
+ }
75
+ } catch {
76
+ // If anything fails, just concatenate string representations
77
+ lastResult.value = String(lastResult.value) + String(result.value);
78
+ }
79
+ }
80
+ } else {
81
+ // Add as new result
82
+ accumulatedResults.push(result);
83
+ }
84
+ }
85
+
86
+ // Convert CompletionResult[] to string for streaming
87
+ // Only yield if we have results to show
88
+ const resultText = chunk.result.map(r => {
89
+ switch (r.type) {
90
+ case 'text':
91
+ return r.value;
92
+ case 'json':
93
+ return JSON.stringify(r.value);
94
+ case 'image':
95
+ // Show truncated image placeholder for streaming
96
+ const truncatedValue = typeof r.value === 'string' ? r.value.slice(0, 10) : String(r.value).slice(0, 10);
97
+ return `\n[Image: ${truncatedValue}...]\n`;
98
+ default:
99
+ return String((r as any).value || '');
100
+ }
101
+ }).join('');
102
+
103
+ if (resultText) {
104
+ this.chunks++;
105
+ yield resultText;
106
+ }
107
+ }
52
108
  }
53
109
  }
54
110
  }
111
+ } catch (error: any) {
112
+ error.prompt = this.prompt;
113
+ throw error;
55
114
  }
56
115
 
57
- const content = chunks.join('');
58
-
59
116
  // Return undefined for the ExecutionTokenUsage object if there is nothing to fill it with.
60
- // Allows for checking for truthyness on token_usage, rather than it's internals. For testing and downstream usage.
61
- let tokens: ExecutionTokenUsage | undefined = resultTokens ?
117
+ // Allows for checking for truthy-ness on token_usage, rather than it's internals. For testing and downstream usage.
118
+ const tokens: ExecutionTokenUsage | undefined = resultTokens ?
62
119
  { prompt: promptTokens, result: resultTokens, total: resultTokens + promptTokens, } : undefined
63
120
 
64
121
  this.completion = {
65
- result: content,
122
+ result: accumulatedResults, // Return the accumulated CompletionResult[] instead of text
66
123
  prompt: this.prompt,
67
124
  execution_time: Date.now() - start,
68
125
  token_usage: tokens,
69
126
  finish_reason: finish_reason,
70
- chunks: chunks.length,
127
+ chunks: this.chunks,
71
128
  }
72
129
 
73
- this.driver.validateResult(this.completion, this.options);
130
+ try {
131
+ if (this.completion) {
132
+ this.driver.validateResult(this.completion, this.options);
133
+ }
134
+ } catch (error: any) {
135
+ error.prompt = this.prompt;
136
+ throw error;
137
+ }
74
138
  }
75
139
 
76
140
  }
@@ -90,10 +154,28 @@ export class FallbackCompletionStream<PromptT = any> implements CompletionStream
90
154
  this.driver.logger.debug(
91
155
  `[${this.driver.provider}] Streaming is not supported, falling back to blocking execution`
92
156
  );
93
- const completion = await this.driver._execute(this.prompt, this.options);
94
- const content = typeof completion.result === 'string' ? completion.result : JSON.stringify(completion.result);
95
- yield content;
96
-
97
- this.completion = completion;
157
+ try {
158
+ const completion = await this.driver._execute(this.prompt, this.options);
159
+ // For fallback streaming, yield the text content but keep the original completion
160
+ const content = completion.result.map(r => {
161
+ switch (r.type) {
162
+ case 'text':
163
+ return r.value;
164
+ case 'json':
165
+ return JSON.stringify(r.value);
166
+ case 'image':
167
+ // Show truncated image placeholder for streaming
168
+ const truncatedValue = typeof r.value === 'string' ? r.value.slice(0, 10) : String(r.value).slice(0, 10);
169
+ return `[Image: ${truncatedValue}...]`;
170
+ default:
171
+ return String((r as any).value || '');
172
+ }
173
+ }).join('');
174
+ yield content;
175
+ this.completion = completion; // Return the original completion with untouched CompletionResult[]
176
+ } catch (error: any) {
177
+ error.prompt = this.prompt;
178
+ throw error;
179
+ }
98
180
  }
99
181
  }
package/src/Driver.ts CHANGED
@@ -9,7 +9,7 @@ import { formatTextPrompt } from "./formatters/index.js";
9
9
  import {
10
10
  AIModel,
11
11
  Completion,
12
- CompletionChunk,
12
+ CompletionChunkObject,
13
13
  CompletionStream,
14
14
  DataSource,
15
15
  DriverOptions,
@@ -17,7 +17,6 @@ import {
17
17
  EmbeddingsResult,
18
18
  ExecutionOptions,
19
19
  ExecutionResponse,
20
- ImageGeneration,
21
20
  Logger,
22
21
  Modalities,
23
22
  ModelSearchPayload,
@@ -143,7 +142,10 @@ export abstract class AbstractDriver<OptionsT extends DriverOptions = DriverOpti
143
142
 
144
143
  async execute(segments: PromptSegment[], options: ExecutionOptions): Promise<ExecutionResponse<PromptT>> {
145
144
  const prompt = await this.createPrompt(segments, options);
146
- return this._execute(prompt, options);
145
+ return this._execute(prompt, options).catch((error: any) => {
146
+ (error as any).prompt = prompt;
147
+ throw error;
148
+ });
147
149
  }
148
150
 
149
151
  async _execute(prompt: PromptT, options: ExecutionOptions): Promise<ExecutionResponse<PromptT>> {
@@ -222,9 +224,9 @@ export abstract class AbstractDriver<OptionsT extends DriverOptions = DriverOpti
222
224
 
223
225
  abstract requestTextCompletion(prompt: PromptT, options: ExecutionOptions): Promise<Completion>;
224
226
 
225
- abstract requestTextCompletionStream(prompt: PromptT, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunk>>;
227
+ abstract requestTextCompletionStream(prompt: PromptT, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunkObject>>;
226
228
 
227
- async requestImageGeneration(_prompt: PromptT, _options: ExecutionOptions): Promise<Completion<ImageGeneration>> {
229
+ async requestImageGeneration(_prompt: PromptT, _options: ExecutionOptions): Promise<Completion> {
228
230
  throw new Error("Image generation not implemented.");
229
231
  //Cannot be made abstract, as abstract methods are required in the derived class
230
232
  }
package/src/async.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ServerSentEvent } from "@vertesia/api-fetch-client"
2
- import { CompletionChunk } from "@llumiverse/common";
2
+ import { CompletionChunkObject } from "@llumiverse/common";
3
3
 
4
4
  export async function* asyncMap<T, R>(asyncIterable: AsyncIterable<T>, callback: (value: T, index: number) => R) {
5
5
  let i = 0;
@@ -18,9 +18,9 @@ export function oneAsyncIterator<T>(value: T): AsyncIterable<T> {
18
18
  /**
19
19
  * Given a ReadableStream of server sent events, tran
20
20
  */
21
- export function transformSSEStream(stream: ReadableStream<ServerSentEvent>, transform: (data: string) => CompletionChunk): ReadableStream<CompletionChunk> & AsyncIterable<CompletionChunk> {
21
+ export function transformSSEStream(stream: ReadableStream<ServerSentEvent>, transform: (data: string) => CompletionChunkObject): ReadableStream<CompletionChunkObject> & AsyncIterable<CompletionChunkObject> {
22
22
  // on node and bun the ReadableStream is an async iterable
23
- return stream.pipeThrough(new TransformStream<ServerSentEvent, CompletionChunk>({
23
+ return stream.pipeThrough(new TransformStream<ServerSentEvent, CompletionChunkObject>({
24
24
  transform(event: ServerSentEvent, controller) {
25
25
  if (event.type === 'event' && event.data && event.data !== '[DONE]') {
26
26
  try {
@@ -32,7 +32,7 @@ export function transformSSEStream(stream: ReadableStream<ServerSentEvent>, tran
32
32
  }
33
33
  }
34
34
  }
35
- })) as ReadableStream<CompletionChunk> & AsyncIterable<CompletionChunk>;
35
+ })) satisfies ReadableStream<CompletionChunkObject> & AsyncIterable<CompletionChunkObject>;
36
36
  }
37
37
 
38
38
  export class EventStream<T, ReturnT = any> implements AsyncIterable<T> {
@@ -1,4 +1,3 @@
1
1
  export * from "./commons.js";
2
2
  export * from "./generic.js";
3
- export * from "./openai.js";
4
3
  export * from "./nova.js";
package/src/stream.ts CHANGED
@@ -1,20 +1,30 @@
1
1
 
2
2
  export async function readStreamAsBase64(stream: ReadableStream): Promise<string> {
3
- return (await _readStreamAsBuffer(stream)).toString('base64');
3
+ const uint8Array = await readStreamAsUint8Array(stream);
4
+ return Buffer.from(uint8Array).toString('base64');
4
5
  }
5
6
 
6
7
  export async function readStreamAsString(stream: ReadableStream): Promise<string> {
7
- return (await _readStreamAsBuffer(stream)).toString();
8
+ const uint8Array = await readStreamAsUint8Array(stream);
9
+ return Buffer.from(uint8Array).toString();
8
10
  }
9
11
 
10
12
  export async function readStreamAsUint8Array(stream: ReadableStream): Promise<Uint8Array> {
11
- return _readStreamAsBuffer(stream);
12
- }
13
-
14
- async function _readStreamAsBuffer(stream: ReadableStream): Promise<Buffer> {
15
- const out: Buffer[] = [];
13
+ const chunks: Uint8Array[] = [];
14
+ let totalLength = 0;
15
+
16
16
  for await (const chunk of stream) {
17
- out.push(Buffer.from(chunk));
17
+ const uint8Chunk = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
18
+ chunks.push(uint8Chunk);
19
+ totalLength += uint8Chunk.length;
20
+ }
21
+
22
+ const combined = new Uint8Array(totalLength);
23
+ let offset = 0;
24
+ for (const chunk of chunks) {
25
+ combined.set(chunk, offset);
26
+ offset += chunk.length;
18
27
  }
19
- return Buffer.concat(out);
28
+
29
+ return combined;
20
30
  }
package/src/validation.ts CHANGED
@@ -2,7 +2,7 @@ import { Ajv } from 'ajv';
2
2
  import addFormats from 'ajv-formats';
3
3
  import { extractAndParseJSON } from "./json.js";
4
4
  import { resolveField } from './resolver.js';
5
- import { ResultValidationError } from "@llumiverse/common";
5
+ import { CompletionResult, completionResultToString, ResultValidationError } from "@llumiverse/common";
6
6
 
7
7
 
8
8
  const ajv = new Ajv({
@@ -28,17 +28,22 @@ export class ValidationError extends Error implements ResultValidationError {
28
28
  }
29
29
  }
30
30
 
31
- export function validateResult(data: any, schema: Object) {
31
+ export function validateResult(data: CompletionResult[], schema: Object): CompletionResult[] {
32
32
  let json;
33
-
34
- if (typeof data === "string") {
35
- try {
36
- json = extractAndParseJSON(data);
37
- } catch (error: any) {
38
- throw new ValidationError("json_error", error.message)
33
+ if (Array.isArray(data)) {
34
+ const jsonResults = data.filter(r => r.type === "json");
35
+ if (jsonResults.length > 0) {
36
+ json = jsonResults[0].value;
37
+ } else {
38
+ const stringResult = data.map(completionResultToString).join("");
39
+ try {
40
+ json = extractAndParseJSON(stringResult);
41
+ } catch (error: any) {
42
+ throw new ValidationError("json_error", error.message)
43
+ }
39
44
  }
40
45
  } else {
41
- json = data;
46
+ throw new Error("Data to validate must be an array")
42
47
  }
43
48
 
44
49
  const validate = ajv.compile(schema);
@@ -71,5 +76,5 @@ export function validateResult(data: any, schema: Object) {
71
76
  }
72
77
  }
73
78
 
74
- return json;
79
+ return [{ type: "json", value: json }];
75
80
  }
@@ -1,113 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatOpenAILikeTextPrompt = formatOpenAILikeTextPrompt;
4
- exports.formatOpenAILikeMultimodalPrompt = formatOpenAILikeMultimodalPrompt;
5
- const common_1 = require("@llumiverse/common");
6
- const stream_js_1 = require("../stream.js");
7
- /**
8
- * OpenAI text only prompts
9
- * @param segments
10
- * @returns
11
- */
12
- function formatOpenAILikeTextPrompt(segments) {
13
- const system = [];
14
- const safety = [];
15
- const user = [];
16
- for (const msg of segments) {
17
- if (msg.role === common_1.PromptRole.system) {
18
- system.push({ content: msg.content, role: "system" });
19
- }
20
- else if (msg.role === common_1.PromptRole.safety) {
21
- safety.push({ content: "IMPORTANT: " + msg.content, role: "system" });
22
- }
23
- else if (msg.role !== common_1.PromptRole.negative && msg.role !== common_1.PromptRole.mask && msg.role !== common_1.PromptRole.tool) {
24
- user.push({
25
- content: msg.content,
26
- role: msg.role || 'user',
27
- });
28
- }
29
- }
30
- // put system messages first and safety last
31
- return system.concat(user).concat(safety);
32
- }
33
- async function formatOpenAILikeMultimodalPrompt(segments, opts) {
34
- const system = [];
35
- const safety = [];
36
- const others = [];
37
- for (const msg of segments) {
38
- const parts = [];
39
- //generate the parts based on PromptSegment
40
- if (msg.files) {
41
- for (const file of msg.files) {
42
- const stream = await file.getStream();
43
- const data = await (0, stream_js_1.readStreamAsBase64)(stream);
44
- parts.push({
45
- type: "image_url",
46
- image_url: {
47
- url: `data:${file.mime_type || "image/jpeg"};base64,${data}`,
48
- //detail: "auto" //This is modified just before execution to "low" | "high" | "auto"
49
- },
50
- });
51
- }
52
- }
53
- if (msg.content) {
54
- parts.push({
55
- text: msg.content,
56
- type: "text"
57
- });
58
- }
59
- if (msg.role === common_1.PromptRole.system) {
60
- system.push({
61
- role: "system",
62
- content: parts
63
- });
64
- if (opts.useToolForFormatting && opts.schema) {
65
- system.forEach(s => {
66
- s.content.forEach(c => {
67
- if (c.type === "text")
68
- c.text = "TOOL: " + c.text;
69
- });
70
- });
71
- }
72
- }
73
- else if (msg.role === common_1.PromptRole.safety) {
74
- const safetyMsg = {
75
- role: "system",
76
- content: parts
77
- };
78
- safetyMsg.content.forEach(c => {
79
- if (c.type === "text")
80
- c.text = "DO NOT IGNORE - IMPORTANT: " + c.text;
81
- });
82
- system.push(safetyMsg);
83
- }
84
- else if (msg.role === common_1.PromptRole.tool) {
85
- if (!msg.tool_use_id) {
86
- throw new Error("Tool use id is required for tool messages");
87
- }
88
- others.push({
89
- role: "tool",
90
- tool_call_id: msg.tool_use_id,
91
- content: msg.content
92
- });
93
- }
94
- else if (msg.role !== common_1.PromptRole.negative && msg.role !== common_1.PromptRole.mask) {
95
- others.push({
96
- role: msg.role ?? 'user',
97
- content: parts
98
- });
99
- }
100
- }
101
- if (opts.result_schema && !opts.useToolForFormatting) {
102
- system.push({
103
- role: "system",
104
- content: [{
105
- type: "text",
106
- text: "IMPORTANT: only answer using JSON, and respecting the schema included below, between the <response_schema> tags. " + `<response_schema>${JSON.stringify(opts.result_schema)}</response_schema>`
107
- }]
108
- });
109
- }
110
- // put system messages first and safety last
111
- return [].concat(system).concat(others).concat(safety);
112
- }
113
- //# sourceMappingURL=openai.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/formatters/openai.ts"],"names":[],"mappings":"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"}
@@ -1,109 +0,0 @@
1
- import { PromptRole } from "@llumiverse/common";
2
- import { readStreamAsBase64 } from "../stream.js";
3
- /**
4
- * OpenAI text only prompts
5
- * @param segments
6
- * @returns
7
- */
8
- export function formatOpenAILikeTextPrompt(segments) {
9
- const system = [];
10
- const safety = [];
11
- const user = [];
12
- for (const msg of segments) {
13
- if (msg.role === PromptRole.system) {
14
- system.push({ content: msg.content, role: "system" });
15
- }
16
- else if (msg.role === PromptRole.safety) {
17
- safety.push({ content: "IMPORTANT: " + msg.content, role: "system" });
18
- }
19
- else if (msg.role !== PromptRole.negative && msg.role !== PromptRole.mask && msg.role !== PromptRole.tool) {
20
- user.push({
21
- content: msg.content,
22
- role: msg.role || 'user',
23
- });
24
- }
25
- }
26
- // put system messages first and safety last
27
- return system.concat(user).concat(safety);
28
- }
29
- export async function formatOpenAILikeMultimodalPrompt(segments, opts) {
30
- const system = [];
31
- const safety = [];
32
- const others = [];
33
- for (const msg of segments) {
34
- const parts = [];
35
- //generate the parts based on PromptSegment
36
- if (msg.files) {
37
- for (const file of msg.files) {
38
- const stream = await file.getStream();
39
- const data = await readStreamAsBase64(stream);
40
- parts.push({
41
- type: "image_url",
42
- image_url: {
43
- url: `data:${file.mime_type || "image/jpeg"};base64,${data}`,
44
- //detail: "auto" //This is modified just before execution to "low" | "high" | "auto"
45
- },
46
- });
47
- }
48
- }
49
- if (msg.content) {
50
- parts.push({
51
- text: msg.content,
52
- type: "text"
53
- });
54
- }
55
- if (msg.role === PromptRole.system) {
56
- system.push({
57
- role: "system",
58
- content: parts
59
- });
60
- if (opts.useToolForFormatting && opts.schema) {
61
- system.forEach(s => {
62
- s.content.forEach(c => {
63
- if (c.type === "text")
64
- c.text = "TOOL: " + c.text;
65
- });
66
- });
67
- }
68
- }
69
- else if (msg.role === PromptRole.safety) {
70
- const safetyMsg = {
71
- role: "system",
72
- content: parts
73
- };
74
- safetyMsg.content.forEach(c => {
75
- if (c.type === "text")
76
- c.text = "DO NOT IGNORE - IMPORTANT: " + c.text;
77
- });
78
- system.push(safetyMsg);
79
- }
80
- else if (msg.role === PromptRole.tool) {
81
- if (!msg.tool_use_id) {
82
- throw new Error("Tool use id is required for tool messages");
83
- }
84
- others.push({
85
- role: "tool",
86
- tool_call_id: msg.tool_use_id,
87
- content: msg.content
88
- });
89
- }
90
- else if (msg.role !== PromptRole.negative && msg.role !== PromptRole.mask) {
91
- others.push({
92
- role: msg.role ?? 'user',
93
- content: parts
94
- });
95
- }
96
- }
97
- if (opts.result_schema && !opts.useToolForFormatting) {
98
- system.push({
99
- role: "system",
100
- content: [{
101
- type: "text",
102
- text: "IMPORTANT: only answer using JSON, and respecting the schema included below, between the <response_schema> tags. " + `<response_schema>${JSON.stringify(opts.result_schema)}</response_schema>`
103
- }]
104
- });
105
- }
106
- // put system messages first and safety last
107
- return [].concat(system).concat(others).concat(safety);
108
- }
109
- //# sourceMappingURL=openai.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/formatters/openai.ts"],"names":[],"mappings":"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"}
@@ -1,41 +0,0 @@
1
- import { PromptOptions } from "@llumiverse/common";
2
- import { PromptSegment } from "@llumiverse/common";
3
- export interface OpenAITextMessage {
4
- content: string;
5
- role: "system" | "user" | "assistant";
6
- }
7
- export interface OpenAIMessage {
8
- content: (OpenAIContentPartText | OpenAIContentPartImage)[];
9
- role: "system" | "user" | "assistant";
10
- name?: string;
11
- }
12
- export interface OpenAIToolMessage {
13
- role: "tool";
14
- tool_call_id: string;
15
- content: string;
16
- }
17
- export type OpenAIInputMessage = OpenAIMessage | OpenAIToolMessage;
18
- export interface OpenAIContentPartText {
19
- type: "text";
20
- text: string;
21
- }
22
- export interface OpenAIContentPartImage {
23
- type: "image_url";
24
- image_url: {
25
- detail?: 'auto' | 'low' | 'high';
26
- url: string;
27
- };
28
- }
29
- /**
30
- * OpenAI text only prompts
31
- * @param segments
32
- * @returns
33
- */
34
- export declare function formatOpenAILikeTextPrompt(segments: PromptSegment[]): OpenAITextMessage[];
35
- export declare function formatOpenAILikeMultimodalPrompt(segments: PromptSegment[], opts: PromptOptions & OpenAIPromptFormatterOptions): Promise<OpenAIInputMessage[]>;
36
- export interface OpenAIPromptFormatterOptions {
37
- multimodal?: boolean;
38
- useToolForFormatting?: boolean;
39
- schema?: Object;
40
- }
41
- //# sourceMappingURL=openai.d.ts.map