modelfusion 0.126.0 → 0.128.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 (84) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +6 -11
  3. package/core/api/postToApi.cjs +2 -2
  4. package/core/api/postToApi.d.ts +2 -3
  5. package/core/api/postToApi.js +2 -2
  6. package/core/getFunctionCallLogger.cjs +2 -2
  7. package/core/getFunctionCallLogger.js +2 -2
  8. package/model-function/generate-image/generateImage.cjs +2 -1
  9. package/model-function/generate-image/generateImage.d.ts +4 -5
  10. package/model-function/generate-image/generateImage.js +2 -1
  11. package/model-function/generate-speech/SpeechGenerationEvent.d.ts +1 -2
  12. package/model-function/generate-speech/SpeechGenerationModel.d.ts +3 -4
  13. package/model-function/generate-speech/generateSpeech.d.ts +3 -4
  14. package/model-function/generate-speech/streamSpeech.d.ts +3 -4
  15. package/model-function/generate-structure/StructureFromTextGenerationModel.cjs +2 -2
  16. package/model-function/generate-structure/StructureFromTextGenerationModel.js +2 -2
  17. package/model-function/generate-structure/StructureFromTextStreamingModel.cjs +1 -1
  18. package/model-function/generate-structure/StructureFromTextStreamingModel.js +1 -1
  19. package/model-function/generate-structure/streamStructure.cjs +14 -12
  20. package/model-function/generate-structure/streamStructure.d.ts +11 -29
  21. package/model-function/generate-structure/streamStructure.js +14 -12
  22. package/model-function/generate-text/prompt-template/ContentPart.cjs +9 -1
  23. package/model-function/generate-text/prompt-template/ContentPart.d.ts +3 -2
  24. package/model-function/generate-text/prompt-template/ContentPart.js +7 -0
  25. package/model-function/generate-text/streamText.cjs +1 -1
  26. package/model-function/generate-text/streamText.d.ts +1 -1
  27. package/model-function/generate-text/streamText.js +1 -1
  28. package/model-provider/elevenlabs/ElevenLabsSpeechModel.cjs +2 -1
  29. package/model-provider/elevenlabs/ElevenLabsSpeechModel.d.ts +2 -3
  30. package/model-provider/elevenlabs/ElevenLabsSpeechModel.js +2 -1
  31. package/model-provider/llamacpp/LlamaCppBakLLaVA1PromptTemplate.cjs +2 -2
  32. package/model-provider/llamacpp/LlamaCppBakLLaVA1PromptTemplate.js +3 -3
  33. package/model-provider/lmnt/LmntSpeechModel.cjs +2 -1
  34. package/model-provider/lmnt/LmntSpeechModel.d.ts +1 -2
  35. package/model-provider/lmnt/LmntSpeechModel.js +2 -1
  36. package/model-provider/mistral/MistralChatModel.test.cjs +2 -2
  37. package/model-provider/mistral/MistralChatModel.test.js +2 -2
  38. package/model-provider/ollama/OllamaChatModel.cjs +1 -1
  39. package/model-provider/ollama/OllamaChatModel.d.ts +5 -5
  40. package/model-provider/ollama/OllamaChatModel.js +1 -1
  41. package/model-provider/ollama/OllamaChatPromptTemplate.cjs +1 -1
  42. package/model-provider/ollama/OllamaChatPromptTemplate.js +2 -2
  43. package/model-provider/ollama/OllamaCompletionModel.cjs +2 -2
  44. package/model-provider/ollama/OllamaCompletionModel.d.ts +5 -5
  45. package/model-provider/ollama/OllamaCompletionModel.js +2 -2
  46. package/model-provider/ollama/OllamaCompletionModel.test.cjs +4 -6
  47. package/model-provider/ollama/OllamaCompletionModel.test.js +4 -6
  48. package/model-provider/openai/OpenAIChatMessage.cjs +5 -4
  49. package/model-provider/openai/OpenAIChatMessage.js +5 -4
  50. package/model-provider/openai/OpenAIChatModel.test.cjs +4 -6
  51. package/model-provider/openai/OpenAIChatModel.test.js +4 -6
  52. package/model-provider/openai/OpenAISpeechModel.d.ts +1 -2
  53. package/model-provider/openai/OpenAITranscriptionModel.d.ts +1 -2
  54. package/model-provider/openai-compatible/FireworksAIApiConfiguration.cjs +6 -0
  55. package/model-provider/openai-compatible/FireworksAIApiConfiguration.d.ts +3 -1
  56. package/model-provider/openai-compatible/FireworksAIApiConfiguration.js +6 -0
  57. package/model-provider/openai-compatible/OpenAICompatibleApiConfiguration.d.ts +5 -0
  58. package/model-provider/openai-compatible/OpenAICompatibleChatModel.cjs +1 -1
  59. package/model-provider/openai-compatible/OpenAICompatibleChatModel.d.ts +2 -3
  60. package/model-provider/openai-compatible/OpenAICompatibleChatModel.js +1 -1
  61. package/model-provider/openai-compatible/OpenAICompatibleCompletionModel.cjs +1 -1
  62. package/model-provider/openai-compatible/OpenAICompatibleCompletionModel.d.ts +2 -3
  63. package/model-provider/openai-compatible/OpenAICompatibleCompletionModel.js +1 -1
  64. package/model-provider/openai-compatible/OpenAICompatibleTextEmbeddingModel.cjs +1 -1
  65. package/model-provider/openai-compatible/OpenAICompatibleTextEmbeddingModel.d.ts +2 -3
  66. package/model-provider/openai-compatible/OpenAICompatibleTextEmbeddingModel.js +1 -1
  67. package/model-provider/openai-compatible/PerplexityApiConfiguration.cjs +6 -0
  68. package/model-provider/openai-compatible/PerplexityApiConfiguration.d.ts +3 -1
  69. package/model-provider/openai-compatible/PerplexityApiConfiguration.js +6 -0
  70. package/model-provider/openai-compatible/TogetherAIApiConfiguration.cjs +6 -0
  71. package/model-provider/openai-compatible/TogetherAIApiConfiguration.d.ts +3 -1
  72. package/model-provider/openai-compatible/TogetherAIApiConfiguration.js +6 -0
  73. package/model-provider/openai-compatible/index.cjs +1 -1
  74. package/model-provider/openai-compatible/index.d.ts +1 -1
  75. package/model-provider/openai-compatible/index.js +1 -1
  76. package/model-provider/stability/StabilityImageGenerationModel.d.ts +5 -5
  77. package/model-provider/whispercpp/WhisperCppTranscriptionModel.d.ts +1 -2
  78. package/package.json +3 -2
  79. package/util/UInt8Utils.cjs +50 -0
  80. package/util/UInt8Utils.d.ts +3 -0
  81. package/util/UInt8Utils.js +44 -0
  82. package/model-provider/openai-compatible/OpenAICompatibleProviderName.d.ts +0 -1
  83. /package/model-provider/openai-compatible/{OpenAICompatibleProviderName.cjs → OpenAICompatibleApiConfiguration.cjs} +0 -0
  84. /package/model-provider/openai-compatible/{OpenAICompatibleProviderName.js → OpenAICompatibleApiConfiguration.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,89 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.128.0 - 2024-01-20
4
+
5
+ ### Changed
6
+
7
+ - **breaking change**: ModelFusion uses `Uint8Array` instead of `Buffer` for better cross-platform compatibility (see also ["Goodbye, Node.js Buffer"](https://sindresorhus.com/blog/goodbye-nodejs-buffer)). This can lead to breaking changes in your code if you use `Buffer`-specific methods.
8
+ - **breaking change**: Image content in multi-modal instruction and chat inputs (e.g. for GPT Vision) is passed in the `image` property (instead of `base64Image`) and supports both base64 strings and `Uint8Array` inputs:
9
+
10
+ ```ts
11
+ const image = fs.readFileSync(path.join("data", "example-image.png"), {
12
+ encoding: "base64",
13
+ });
14
+
15
+ const textStream = await streamText({
16
+ model: openai.ChatTextGenerator({
17
+ model: "gpt-4-vision-preview",
18
+ maxGenerationTokens: 1000,
19
+ }),
20
+
21
+ prompt: [
22
+ openai.ChatMessage.user([
23
+ { type: "text", text: "Describe the image in detail:\n\n" },
24
+ { type: "image", image, mimeType: "image/png" },
25
+ ]),
26
+ ],
27
+ });
28
+ ```
29
+
30
+ - OpenAI-compatible providers with predefined API configurations have a customized provider name that shows up in the events.
31
+
32
+ ## v0.127.0 - 2024-01-15
33
+
34
+ ### Changed
35
+
36
+ - **breaking change**: `streamStructure` returns an async iterable over deep partial objects. If you need to get the fully validated final result, you can use the `fullResponse: true` option and await the `structurePromise` value. Example:
37
+
38
+ ```ts
39
+ const { structureStream, structurePromise } = await streamStructure({
40
+ model: ollama
41
+ .ChatTextGenerator({
42
+ model: "openhermes2.5-mistral",
43
+ maxGenerationTokens: 1024,
44
+ temperature: 0,
45
+ })
46
+ .asStructureGenerationModel(jsonStructurePrompt.text()),
47
+
48
+ schema: zodSchema(
49
+ z.object({
50
+ characters: z.array(
51
+ z.object({
52
+ name: z.string(),
53
+ class: z
54
+ .string()
55
+ .describe("Character class, e.g. warrior, mage, or thief."),
56
+ description: z.string(),
57
+ })
58
+ ),
59
+ })
60
+ ),
61
+
62
+ prompt:
63
+ "Generate 3 character descriptions for a fantasy role playing game.",
64
+
65
+ fullResponse: true,
66
+ });
67
+
68
+ for await (const partialStructure of structureStream) {
69
+ console.clear();
70
+ console.log(partialStructure);
71
+ }
72
+
73
+ const structure = await structurePromise;
74
+
75
+ console.clear();
76
+ console.log("FINAL STRUCTURE");
77
+ console.log(structure);
78
+ ```
79
+
80
+ - **breaking change**: Renamed `text` value in `streamText` with `fullResponse: true` to `textPromise`.
81
+
82
+ ### Fixed
83
+
84
+ - Ollama streaming.
85
+ - Ollama structure generation and streaming.
86
+
3
87
  ## v0.126.0 - 2024-01-15
4
88
 
5
89
  ### Changed
package/README.md CHANGED
@@ -93,7 +93,7 @@ const textStream = await streamText({
93
93
  prompt: [
94
94
  openai.ChatMessage.user([
95
95
  { type: "text", text: "Describe the image in detail:" },
96
- { type: "image", base64Image: image, mimeType: "image/png" },
96
+ { type: "image", image, mimeType: "image/png" },
97
97
  ]),
98
98
  ],
99
99
  });
@@ -184,14 +184,9 @@ const structureStream = await streamStructure({
184
184
  prompt: "Generate 3 character descriptions for a fantasy role playing game.",
185
185
  });
186
186
 
187
- for await (const part of structureStream) {
188
- if (!part.isComplete) {
189
- const unknownPartialStructure = part.value;
190
- console.log("partial value", unknownPartialStructure);
191
- } else {
192
- const fullyTypedStructure = part.value;
193
- console.log("final value", fullyTypedStructure);
194
- }
187
+ for await (const partialStructure of structureStream) {
188
+ console.clear();
189
+ console.log(partialStructure);
195
190
  }
196
191
  ```
197
192
 
@@ -580,8 +575,8 @@ modelfusion.setLogFormat("detailed-object"); // log full events
580
575
  - [Embed Value](https://modelfusion.dev/guide/function/embed)
581
576
  - [Classify Value](https://modelfusion.dev/guide/function/classify)
582
577
  - [Tools](https://modelfusion.dev/guide/tools)
583
- - [Use Tool](https://modelfusion.dev/guide/tools/run-tool)
584
- - [Use Tools](https://modelfusion.dev/guide/tools/run-tools)
578
+ - [Run Tool](https://modelfusion.dev/guide/tools/run-tool)
579
+ - [Run Tools](https://modelfusion.dev/guide/tools/run-tools)
585
580
  - [Agent Loop](https://modelfusion.dev/guide/tools/agent-loop)
586
581
  - [Available Tools](https://modelfusion.dev/guide/tools/available-tools/)
587
582
  - [Custom Tools](https://modelfusion.dev/guide/tools/custom-tools)
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.postToApi = exports.postJsonToApi = exports.createAudioMpegResponseHandler = exports.createTextResponseHandler = exports.createJsonResponseHandler = exports.createTextErrorResponseHandler = exports.createJsonErrorResponseHandler = void 0;
4
+ const UInt8Utils_js_1 = require("../../util/UInt8Utils.cjs");
4
5
  const parseJSON_js_1 = require("../schema/parseJSON.cjs");
5
6
  const ApiCallError_js_1 = require("./ApiCallError.cjs");
6
7
  const createJsonErrorResponseHandler = ({ errorSchema, errorToMessage, isRetryable, }) => async ({ response, url, requestBodyValues }) => {
@@ -86,8 +87,7 @@ const createAudioMpegResponseHandler = () => async ({ response, url, requestBody
86
87
  requestBodyValues,
87
88
  });
88
89
  }
89
- const arrayBuffer = await response.arrayBuffer();
90
- return Buffer.from(arrayBuffer);
90
+ return (0, UInt8Utils_js_1.toUint8Array)(await response.arrayBuffer());
91
91
  };
92
92
  exports.createAudioMpegResponseHandler = createAudioMpegResponseHandler;
93
93
  const postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, }) => (0, exports.postToApi)({
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { Schema } from "../schema/Schema.js";
3
2
  import { ApiCallError } from "./ApiCallError.js";
4
3
  export type ResponseHandler<T> = (options: {
@@ -16,7 +15,7 @@ export declare const createTextErrorResponseHandler: ({ isRetryable, }?: {
16
15
  }) => ResponseHandler<ApiCallError>;
17
16
  export declare const createJsonResponseHandler: <T>(responseSchema: Schema<T>) => ResponseHandler<T>;
18
17
  export declare const createTextResponseHandler: () => ResponseHandler<string>;
19
- export declare const createAudioMpegResponseHandler: () => ResponseHandler<Buffer>;
18
+ export declare const createAudioMpegResponseHandler: () => ResponseHandler<Uint8Array>;
20
19
  export declare const postJsonToApi: <T>({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, }: {
21
20
  url: string;
22
21
  headers?: Record<string, string> | undefined;
@@ -29,7 +28,7 @@ export declare const postToApi: <T>({ url, headers, body, successfulResponseHand
29
28
  url: string;
30
29
  headers?: Record<string, string> | undefined;
31
30
  body: {
32
- content: string | FormData | Buffer;
31
+ content: string | FormData | Uint8Array;
33
32
  values: unknown;
34
33
  };
35
34
  failedResponseHandler: ResponseHandler<Error>;
@@ -1,3 +1,4 @@
1
+ import { toUint8Array } from "../../util/UInt8Utils.js";
1
2
  import { parseJSON, safeParseJSON } from "../schema/parseJSON.js";
2
3
  import { ApiCallError } from "./ApiCallError.js";
3
4
  export const createJsonErrorResponseHandler = ({ errorSchema, errorToMessage, isRetryable, }) => async ({ response, url, requestBodyValues }) => {
@@ -79,8 +80,7 @@ export const createAudioMpegResponseHandler = () => async ({ response, url, requ
79
80
  requestBodyValues,
80
81
  });
81
82
  }
82
- const arrayBuffer = await response.arrayBuffer();
83
- return Buffer.from(arrayBuffer);
83
+ return toUint8Array(await response.arrayBuffer());
84
84
  };
85
85
  export const postJsonToApi = async ({ url, headers, body, failedResponseHandler, successfulResponseHandler, abortSignal, }) => postToApi({
86
86
  url,
@@ -61,8 +61,8 @@ const detailedObjectObserver = {
61
61
  if (v === undefined) {
62
62
  return [k, undefined];
63
63
  }
64
- else if (v instanceof Buffer) {
65
- return [k, "omitted<Buffer>"];
64
+ else if (v instanceof Uint8Array) {
65
+ return [k, "omitted<Uint8Array>"];
66
66
  }
67
67
  else if (Array.isArray(v) &&
68
68
  v.length > 20 &&
@@ -57,8 +57,8 @@ const detailedObjectObserver = {
57
57
  if (v === undefined) {
58
58
  return [k, undefined];
59
59
  }
60
- else if (v instanceof Buffer) {
61
- return [k, "omitted<Buffer>"];
60
+ else if (v instanceof Uint8Array) {
61
+ return [k, "omitted<Uint8Array>"];
62
62
  }
63
63
  else if (Array.isArray(v) &&
64
64
  v.length > 20 &&
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateImage = void 0;
4
+ const UInt8Utils_js_1 = require("../../util/UInt8Utils.cjs");
4
5
  const executeStandardCall_js_1 = require("../executeStandardCall.cjs");
5
6
  async function generateImage({ model, prompt, fullResponse, ...options }) {
6
7
  const callResponse = await (0, executeStandardCall_js_1.executeStandardCall)({
@@ -17,7 +18,7 @@ async function generateImage({ model, prompt, fullResponse, ...options }) {
17
18
  },
18
19
  });
19
20
  const imagesBase64 = callResponse.value;
20
- const images = imagesBase64.map((imageBase64) => Buffer.from(imageBase64, "base64"));
21
+ const images = imagesBase64.map(UInt8Utils_js_1.base64ToUint8Array);
21
22
  return fullResponse
22
23
  ? {
23
24
  image: images[0],
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { FunctionOptions } from "../../core/FunctionOptions.js";
3
2
  import { ModelCallMetadata } from "../ModelCallMetadata.js";
4
3
  import { ImageGenerationModel, ImageGenerationModelSettings } from "./ImageGenerationModel.js";
@@ -23,21 +22,21 @@ import { ImageGenerationModel, ImageGenerationModelSettings } from "./ImageGener
23
22
  * @param {PROMPT} prompt - The prompt to be used for image generation.
24
23
  *
25
24
  * @returns {Promise} - Returns a promise that resolves to the generated image.
26
- * The image is a Buffer containing the image data in PNG format.
25
+ * The image is a Uint8Array containing the image data in PNG format.
27
26
  */
28
27
  export declare function generateImage<PROMPT>(args: {
29
28
  model: ImageGenerationModel<PROMPT, ImageGenerationModelSettings>;
30
29
  prompt: PROMPT;
31
30
  fullResponse?: false;
32
- } & FunctionOptions): Promise<Buffer>;
31
+ } & FunctionOptions): Promise<Uint8Array>;
33
32
  export declare function generateImage<PROMPT>(args: {
34
33
  model: ImageGenerationModel<PROMPT, ImageGenerationModelSettings>;
35
34
  prompt: PROMPT;
36
35
  fullResponse: true;
37
36
  } & FunctionOptions): Promise<{
38
- image: Buffer;
37
+ image: Uint8Array;
39
38
  imageBase64: string;
40
- images: Buffer[];
39
+ images: Uint8Array[];
41
40
  imagesBase64: string[];
42
41
  rawResponse: unknown;
43
42
  metadata: ModelCallMetadata;
@@ -1,3 +1,4 @@
1
+ import { base64ToUint8Array } from "../../util/UInt8Utils.js";
1
2
  import { executeStandardCall } from "../executeStandardCall.js";
2
3
  export async function generateImage({ model, prompt, fullResponse, ...options }) {
3
4
  const callResponse = await executeStandardCall({
@@ -14,7 +15,7 @@ export async function generateImage({ model, prompt, fullResponse, ...options })
14
15
  },
15
16
  });
16
17
  const imagesBase64 = callResponse.value;
17
- const images = imagesBase64.map((imageBase64) => Buffer.from(imageBase64, "base64"));
18
+ const images = imagesBase64.map(base64ToUint8Array);
18
19
  return fullResponse
19
20
  ? {
20
21
  image: images[0],
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { BaseModelCallFinishedEvent, BaseModelCallStartedEvent } from "../ModelCallEvent.js";
3
2
  export interface SpeechGenerationStartedEvent extends BaseModelCallStartedEvent {
4
3
  functionType: "generate-speech";
@@ -7,7 +6,7 @@ export interface SpeechGenerationStartedEvent extends BaseModelCallStartedEvent
7
6
  export type SpeechGenerationFinishedEventResult = {
8
7
  status: "success";
9
8
  rawResponse: unknown;
10
- value: Buffer;
9
+ value: Uint8Array;
11
10
  } | {
12
11
  status: "error";
13
12
  error: unknown;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { FunctionCallOptions } from "../../core/FunctionOptions.js";
3
2
  import { Delta } from "../Delta.js";
4
3
  import { Model, ModelSettings } from "../Model.js";
@@ -6,10 +5,10 @@ export interface SpeechGenerationModelSettings extends ModelSettings {
6
5
  }
7
6
  export interface SpeechGenerationModel<SETTINGS extends SpeechGenerationModelSettings = SpeechGenerationModelSettings> extends Model<SETTINGS> {
8
7
  /**
9
- * Generates an mp3 audio buffer that contains the speech for the given text.
8
+ * Generates an mp3 audio Uint8Array that contains the speech for the given text.
10
9
  */
11
- doGenerateSpeechStandard(text: string, options: FunctionCallOptions): PromiseLike<Buffer>;
10
+ doGenerateSpeechStandard(text: string, options: FunctionCallOptions): PromiseLike<Uint8Array>;
12
11
  }
13
12
  export interface StreamingSpeechGenerationModel<SETTINGS extends SpeechGenerationModelSettings = SpeechGenerationModelSettings> extends SpeechGenerationModel<SETTINGS> {
14
- doGenerateSpeechStreamDuplex(textStream: AsyncIterable<string>, options: FunctionCallOptions): PromiseLike<AsyncIterable<Delta<Buffer>>>;
13
+ doGenerateSpeechStreamDuplex(textStream: AsyncIterable<string>, options: FunctionCallOptions): PromiseLike<AsyncIterable<Delta<Uint8Array>>>;
15
14
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { FunctionOptions } from "../../core/FunctionOptions.js";
3
2
  import { ModelCallMetadata } from "../ModelCallMetadata.js";
4
3
  import { SpeechGenerationModel, SpeechGenerationModelSettings } from "./SpeechGenerationModel.js";
@@ -17,19 +16,19 @@ import { SpeechGenerationModel, SpeechGenerationModelSettings } from "./SpeechGe
17
16
  * @param {SpeechGenerationModel<SpeechGenerationModelSettings>} model - The speech generation model.
18
17
  * @param {string} text - The text to be converted to speech.
19
18
  *
20
- * @returns {Promise<Buffer>} - A promise that resolves to a buffer containing the synthesized speech.
19
+ * @returns {Promise<Uint8Array>} - A promise that resolves to a Uint8Array containing the synthesized speech.
21
20
  */
22
21
  export declare function generateSpeech(args: {
23
22
  model: SpeechGenerationModel<SpeechGenerationModelSettings>;
24
23
  text: string;
25
24
  fullResponse?: false;
26
- } & FunctionOptions): Promise<Buffer>;
25
+ } & FunctionOptions): Promise<Uint8Array>;
27
26
  export declare function generateSpeech(args: {
28
27
  model: SpeechGenerationModel<SpeechGenerationModelSettings>;
29
28
  text: string;
30
29
  fullResponse: true;
31
30
  } & FunctionOptions): Promise<{
32
- speech: Buffer;
31
+ speech: Uint8Array;
33
32
  rawResponse: unknown;
34
33
  metadata: ModelCallMetadata;
35
34
  }>;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { FunctionOptions } from "../../core/FunctionOptions.js";
3
2
  import { ModelCallMetadata } from "../ModelCallMetadata.js";
4
3
  import { SpeechGenerationModelSettings, StreamingSpeechGenerationModel } from "./SpeechGenerationModel.js";
@@ -24,18 +23,18 @@ import { SpeechGenerationModelSettings, StreamingSpeechGenerationModel } from ".
24
23
  * @param {AsyncIterable<string> | string} text - The text to be converted to speech. Can be a string or an async iterable of strings.
25
24
  * @param {FunctionOptions} [options] - Optional function options.
26
25
  *
27
- * @returns {AsyncIterableResultPromise<Buffer>} An async iterable promise that contains the synthesized speech chunks.
26
+ * @returns {AsyncIterableResultPromise<Uint8Array>} An async iterable promise that contains the synthesized speech chunks.
28
27
  */
29
28
  export declare function streamSpeech(args: {
30
29
  model: StreamingSpeechGenerationModel<SpeechGenerationModelSettings>;
31
30
  text: AsyncIterable<string> | string;
32
31
  fullResponse?: false;
33
- } & FunctionOptions): Promise<AsyncIterable<Buffer>>;
32
+ } & FunctionOptions): Promise<AsyncIterable<Uint8Array>>;
34
33
  export declare function streamSpeech(args: {
35
34
  model: StreamingSpeechGenerationModel<SpeechGenerationModelSettings>;
36
35
  text: AsyncIterable<string> | string;
37
36
  fullResponse: true;
38
37
  } & FunctionOptions): Promise<{
39
- speechStream: AsyncIterable<Buffer>;
38
+ speechStream: AsyncIterable<Uint8Array>;
40
39
  metadata: Omit<ModelCallMetadata, "durationInMs" | "finishTimestamp">;
41
40
  }>;
@@ -31,7 +31,7 @@ class StructureFromTextGenerationModel {
31
31
  }
32
32
  getModelWithJsonOutput(schema) {
33
33
  if (this.template.withJsonOutput != null) {
34
- return this.template.withJsonOutput?.({
34
+ return this.template.withJsonOutput({
35
35
  model: this.model,
36
36
  schema,
37
37
  });
@@ -40,7 +40,7 @@ class StructureFromTextGenerationModel {
40
40
  }
41
41
  async doGenerateStructure(schema, prompt, options) {
42
42
  const { rawResponse, text } = await (0, generateText_js_1.generateText)({
43
- model: this.model,
43
+ model: this.getModelWithJsonOutput(schema),
44
44
  prompt: this.template.createPrompt(prompt, schema),
45
45
  fullResponse: true,
46
46
  ...options,
@@ -28,7 +28,7 @@ export class StructureFromTextGenerationModel {
28
28
  }
29
29
  getModelWithJsonOutput(schema) {
30
30
  if (this.template.withJsonOutput != null) {
31
- return this.template.withJsonOutput?.({
31
+ return this.template.withJsonOutput({
32
32
  model: this.model,
33
33
  schema,
34
34
  });
@@ -37,7 +37,7 @@ export class StructureFromTextGenerationModel {
37
37
  }
38
38
  async doGenerateStructure(schema, prompt, options) {
39
39
  const { rawResponse, text } = await generateText({
40
- model: this.model,
40
+ model: this.getModelWithJsonOutput(schema),
41
41
  prompt: this.template.createPrompt(prompt, schema),
42
42
  fullResponse: true,
43
43
  ...options,
@@ -11,7 +11,7 @@ class StructureFromTextStreamingModel extends StructureFromTextGenerationModel_j
11
11
  }
12
12
  async doStreamStructure(schema, prompt, options) {
13
13
  const textStream = await (0, streamText_js_1.streamText)({
14
- model: this.model,
14
+ model: this.getModelWithJsonOutput(schema),
15
15
  prompt: this.template.createPrompt(prompt, schema),
16
16
  ...options,
17
17
  });
@@ -8,7 +8,7 @@ export class StructureFromTextStreamingModel extends StructureFromTextGeneration
8
8
  }
9
9
  async doStreamStructure(schema, prompt, options) {
10
10
  const textStream = await streamText({
11
- model: this.model,
11
+ model: this.getModelWithJsonOutput(schema),
12
12
  prompt: this.template.createPrompt(prompt, schema),
13
13
  ...options,
14
14
  });
@@ -10,6 +10,12 @@ async function streamStructure({ model, schema, prompt, fullResponse, ...options
10
10
  : prompt;
11
11
  let accumulatedText = "";
12
12
  let lastStructure;
13
+ let resolveStructure;
14
+ let rejectStructure;
15
+ const structurePromise = new Promise((resolve, reject) => {
16
+ resolveStructure = resolve;
17
+ rejectStructure = reject;
18
+ });
13
19
  const callResponse = await (0, executeStreamCall_js_1.executeStreamCall)({
14
20
  functionType: "stream-structure",
15
21
  input: {
@@ -29,29 +35,25 @@ async function streamStructure({ model, schema, prompt, fullResponse, ...options
29
35
  // only send a new part into the stream when the partial structure has changed:
30
36
  if (!(0, isDeepEqualData_js_1.isDeepEqualData)(lastStructure, latestStructure)) {
31
37
  lastStructure = latestStructure;
32
- return {
33
- isComplete: false,
34
- value: lastStructure,
35
- };
38
+ return lastStructure;
36
39
  }
37
40
  return undefined;
38
41
  },
39
- processFinished: () => {
42
+ onDone: () => {
40
43
  // process the final result (full type validation):
41
44
  const parseResult = schema.validate(lastStructure);
42
- if (!parseResult.success) {
43
- reportError(parseResult.error);
44
- throw parseResult.error;
45
+ if (parseResult.success) {
46
+ resolveStructure(parseResult.data);
47
+ }
48
+ else {
49
+ rejectStructure(parseResult.error);
45
50
  }
46
- return {
47
- isComplete: true,
48
- value: parseResult.data,
49
- };
50
51
  },
51
52
  });
52
53
  return fullResponse
53
54
  ? {
54
55
  structureStream: callResponse.value,
56
+ structurePromise,
55
57
  metadata: callResponse.metadata,
56
58
  }
57
59
  : callResponse.value;
@@ -1,25 +1,12 @@
1
+ import type { PartialDeep } from "type-fest";
1
2
  import { FunctionOptions } from "../../core/FunctionOptions.js";
2
3
  import { JsonSchemaProducer } from "../../core/schema/JsonSchemaProducer.js";
3
4
  import { Schema } from "../../core/schema/Schema.js";
4
5
  import { ModelCallMetadata } from "../ModelCallMetadata.js";
5
6
  import { StructureStreamingModel } from "./StructureGenerationModel.js";
6
- export type StructureStreamPart<STRUCTURE> = {
7
- isComplete: false;
8
- value: unknown;
9
- } | {
10
- isComplete: true;
11
- value: STRUCTURE;
12
- };
13
7
  /**
14
8
  * Generate and stream an object for a prompt and a structure definition.
15
9
  *
16
- * The final object is typed according to the structure definition.
17
- * The partial objects are of unknown type,
18
- * but are supposed to be partial version of the final object
19
- * (unless the underlying model returns invalid data).
20
- *
21
- * The structure definition is used as part of the final prompt.
22
- *
23
10
  * For the OpenAI chat model, this generates and parses a function call with a single function.
24
11
  *
25
12
  * @see https://modelfusion.dev/guide/function/generate-structure
@@ -44,15 +31,8 @@ export type StructureStreamPart<STRUCTURE> = {
44
31
  * ]
45
32
  * });
46
33
  *
47
- * for await (const part of structureStream) {
48
- * if (!part.isComplete) {
49
- * const unknownPartialStructure = part.value;
50
- * // use your own logic to handle partial structures, e.g. with Zod .deepPartial()
51
- * // it depends on your application at which points you want to act on the partial structures
52
- * } else {
53
- * const fullyTypedStructure = part.value;
54
- * // ...
55
- * }
34
+ * for await (const partialStructure of structureStream) {
35
+ * // ...
56
36
  * }
57
37
  *
58
38
  * @param {StructureStreamingModel<PROMPT>} structureGenerator - The model to use for streaming
@@ -60,26 +40,28 @@ export type StructureStreamPart<STRUCTURE> = {
60
40
  * @param {PROMPT | ((schema: Schema<STRUCTURE>) => PROMPT)} prompt
61
41
  * The prompt to be used.
62
42
  * You can also pass a function that takes the schema as an argument and returns the prompt.
63
- * @param {FunctionOptions} [options] - Optional function options
64
43
  *
65
44
  * @returns {AsyncIterableResultPromise<StructureStreamPart<STRUCTURE>>}
66
45
  * The async iterable result promise.
67
- * Each part of the stream is either a partial structure or the final structure.
68
- * It contains a isComplete flag to indicate whether the structure is complete,
69
- * and a value that is either the partial structure or the final structure.
46
+ * Each part of the stream is a partial structure.
70
47
  */
71
48
  export declare function streamStructure<STRUCTURE, PROMPT>(args: {
72
49
  model: StructureStreamingModel<PROMPT>;
73
50
  schema: Schema<STRUCTURE> & JsonSchemaProducer;
74
51
  prompt: PROMPT | ((schema: Schema<STRUCTURE>) => PROMPT);
75
52
  fullResponse?: false;
76
- } & FunctionOptions): Promise<AsyncIterable<StructureStreamPart<STRUCTURE>>>;
53
+ } & FunctionOptions): Promise<AsyncIterable<PartialDeep<STRUCTURE, {
54
+ recurseIntoArrays: true;
55
+ }>>>;
77
56
  export declare function streamStructure<STRUCTURE, PROMPT>(args: {
78
57
  model: StructureStreamingModel<PROMPT>;
79
58
  schema: Schema<STRUCTURE> & JsonSchemaProducer;
80
59
  prompt: PROMPT | ((schema: Schema<STRUCTURE>) => PROMPT);
81
60
  fullResponse: true;
82
61
  } & FunctionOptions): Promise<{
83
- structureStream: AsyncIterable<StructureStreamPart<STRUCTURE>>;
62
+ structureStream: AsyncIterable<PartialDeep<STRUCTURE, {
63
+ recurseIntoArrays: true;
64
+ }>>;
65
+ structurePromise: PromiseLike<STRUCTURE>;
84
66
  metadata: Omit<ModelCallMetadata, "durationInMs" | "finishTimestamp">;
85
67
  }>;
@@ -7,6 +7,12 @@ export async function streamStructure({ model, schema, prompt, fullResponse, ...
7
7
  : prompt;
8
8
  let accumulatedText = "";
9
9
  let lastStructure;
10
+ let resolveStructure;
11
+ let rejectStructure;
12
+ const structurePromise = new Promise((resolve, reject) => {
13
+ resolveStructure = resolve;
14
+ rejectStructure = reject;
15
+ });
10
16
  const callResponse = await executeStreamCall({
11
17
  functionType: "stream-structure",
12
18
  input: {
@@ -26,29 +32,25 @@ export async function streamStructure({ model, schema, prompt, fullResponse, ...
26
32
  // only send a new part into the stream when the partial structure has changed:
27
33
  if (!isDeepEqualData(lastStructure, latestStructure)) {
28
34
  lastStructure = latestStructure;
29
- return {
30
- isComplete: false,
31
- value: lastStructure,
32
- };
35
+ return lastStructure;
33
36
  }
34
37
  return undefined;
35
38
  },
36
- processFinished: () => {
39
+ onDone: () => {
37
40
  // process the final result (full type validation):
38
41
  const parseResult = schema.validate(lastStructure);
39
- if (!parseResult.success) {
40
- reportError(parseResult.error);
41
- throw parseResult.error;
42
+ if (parseResult.success) {
43
+ resolveStructure(parseResult.data);
44
+ }
45
+ else {
46
+ rejectStructure(parseResult.error);
42
47
  }
43
- return {
44
- isComplete: true,
45
- value: parseResult.data,
46
- };
47
48
  },
48
49
  });
49
50
  return fullResponse
50
51
  ? {
51
52
  structureStream: callResponse.value,
53
+ structurePromise,
52
54
  metadata: callResponse.metadata,
53
55
  }
54
56
  : callResponse.value;
@@ -1,7 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateContentIsString = void 0;
3
+ exports.validateContentIsString = exports.getImageAsBase64 = void 0;
4
+ const UInt8Utils_js_1 = require("../../../util/UInt8Utils.cjs");
4
5
  const InvalidPromptError_js_1 = require("./InvalidPromptError.cjs");
6
+ function getImageAsBase64(image) {
7
+ if (typeof image === "string") {
8
+ return image;
9
+ }
10
+ return (0, UInt8Utils_js_1.uint8ArrayToBase64)(image);
11
+ }
12
+ exports.getImageAsBase64 = getImageAsBase64;
5
13
  function validateContentIsString(content, prompt) {
6
14
  if (typeof content !== "string") {
7
15
  throw new InvalidPromptError_js_1.InvalidPromptError("Only text prompts are are supported by this prompt template.", prompt);
@@ -8,9 +8,9 @@ export interface TextPart {
8
8
  export interface ImagePart {
9
9
  type: "image";
10
10
  /**
11
- * Base-64 encoded image.
11
+ * Image data. Can either be a base64-encoded string or a Uint8Array.
12
12
  */
13
- base64Image: string;
13
+ image: string | Uint8Array;
14
14
  /**
15
15
  * Optional mime type of the image.
16
16
  */
@@ -27,4 +27,5 @@ export interface ToolResponsePart {
27
27
  id: string;
28
28
  response: unknown;
29
29
  }
30
+ export declare function getImageAsBase64(image: string | Uint8Array): string;
30
31
  export declare function validateContentIsString(content: string | unknown, prompt: unknown): string;
@@ -1,4 +1,11 @@
1
+ import { uint8ArrayToBase64 } from "../../../util/UInt8Utils.js";
1
2
  import { InvalidPromptError } from "./InvalidPromptError.js";
3
+ export function getImageAsBase64(image) {
4
+ if (typeof image === "string") {
5
+ return image;
6
+ }
7
+ return uint8ArrayToBase64(image);
8
+ }
2
9
  export function validateContentIsString(content, prompt) {
3
10
  if (typeof content !== "string") {
4
11
  throw new InvalidPromptError("Only text prompts are are supported by this prompt template.", prompt);