modelfusion 0.97.0 → 0.99.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 (105) hide show
  1. package/README.md +15 -8
  2. package/composed-function/summarize/summarizeRecursivelyWithTextGenerationAndTokenSplitting.cjs +1 -1
  3. package/composed-function/summarize/summarizeRecursivelyWithTextGenerationAndTokenSplitting.js +1 -1
  4. package/model-function/Model.d.ts +2 -2
  5. package/model-function/embed/embed.cjs +14 -2
  6. package/model-function/embed/embed.d.ts +6 -6
  7. package/model-function/embed/embed.js +14 -2
  8. package/model-function/generate-image/generateImage.cjs +10 -9
  9. package/model-function/generate-image/generateImage.d.ts +4 -6
  10. package/model-function/generate-image/generateImage.js +10 -9
  11. package/model-function/generate-speech/generateSpeech.cjs +7 -1
  12. package/model-function/generate-speech/generateSpeech.d.ts +3 -3
  13. package/model-function/generate-speech/generateSpeech.js +7 -1
  14. package/model-function/generate-speech/streamSpeech.cjs +6 -1
  15. package/model-function/generate-speech/streamSpeech.d.ts +3 -3
  16. package/model-function/generate-speech/streamSpeech.js +6 -1
  17. package/model-function/generate-structure/StructureFromTextGenerationModel.cjs +5 -5
  18. package/model-function/generate-structure/StructureFromTextGenerationModel.js +5 -5
  19. package/model-function/generate-structure/StructureFromTextStreamingModel.cjs +5 -5
  20. package/model-function/generate-structure/StructureFromTextStreamingModel.js +5 -5
  21. package/model-function/generate-structure/generateStructure.cjs +7 -1
  22. package/model-function/generate-structure/generateStructure.d.ts +3 -3
  23. package/model-function/generate-structure/generateStructure.js +7 -1
  24. package/model-function/generate-structure/streamStructure.cjs +6 -1
  25. package/model-function/generate-structure/streamStructure.d.ts +3 -3
  26. package/model-function/generate-structure/streamStructure.js +6 -1
  27. package/model-function/generate-text/PromptTemplateTextGenerationModel.cjs +2 -2
  28. package/model-function/generate-text/PromptTemplateTextGenerationModel.d.ts +2 -2
  29. package/model-function/generate-text/PromptTemplateTextGenerationModel.js +2 -2
  30. package/model-function/generate-text/TextGenerationModel.d.ts +31 -5
  31. package/model-function/generate-text/generateText.cjs +15 -3
  32. package/model-function/generate-text/generateText.d.ts +4 -3
  33. package/model-function/generate-text/generateText.js +15 -3
  34. package/model-function/generate-text/prompt-template/trimChatPrompt.cjs +1 -1
  35. package/model-function/generate-text/prompt-template/trimChatPrompt.js +1 -1
  36. package/model-function/generate-text/streamText.cjs +6 -1
  37. package/model-function/generate-text/streamText.d.ts +3 -3
  38. package/model-function/generate-text/streamText.js +6 -1
  39. package/model-function/generate-transcription/generateTranscription.cjs +1 -1
  40. package/model-function/generate-transcription/generateTranscription.d.ts +2 -2
  41. package/model-function/generate-transcription/generateTranscription.js +1 -1
  42. package/model-provider/anthropic/AnthropicTextGenerationModel.cjs +27 -31
  43. package/model-provider/anthropic/AnthropicTextGenerationModel.d.ts +2 -2
  44. package/model-provider/anthropic/AnthropicTextGenerationModel.js +27 -31
  45. package/model-provider/cohere/CohereFacade.cjs +1 -1
  46. package/model-provider/cohere/CohereFacade.d.ts +1 -1
  47. package/model-provider/cohere/CohereFacade.js +1 -1
  48. package/model-provider/cohere/CohereTextEmbeddingModel.d.ts +5 -5
  49. package/model-provider/cohere/CohereTextGenerationModel.cjs +34 -43
  50. package/model-provider/cohere/CohereTextGenerationModel.d.ts +3 -4
  51. package/model-provider/cohere/CohereTextGenerationModel.js +34 -43
  52. package/model-provider/huggingface/HuggingFaceFacade.cjs +1 -1
  53. package/model-provider/huggingface/HuggingFaceFacade.d.ts +1 -1
  54. package/model-provider/huggingface/HuggingFaceFacade.js +1 -1
  55. package/model-provider/huggingface/HuggingFaceTextGenerationModel.cjs +31 -41
  56. package/model-provider/huggingface/HuggingFaceTextGenerationModel.d.ts +3 -4
  57. package/model-provider/huggingface/HuggingFaceTextGenerationModel.js +31 -41
  58. package/model-provider/llamacpp/LlamaCppTextGenerationModel.cjs +4 -4
  59. package/model-provider/llamacpp/LlamaCppTextGenerationModel.d.ts +2 -2
  60. package/model-provider/llamacpp/LlamaCppTextGenerationModel.js +4 -4
  61. package/model-provider/mistral/MistralTextGenerationModel.cjs +5 -5
  62. package/model-provider/mistral/MistralTextGenerationModel.d.ts +2 -2
  63. package/model-provider/mistral/MistralTextGenerationModel.js +5 -5
  64. package/model-provider/ollama/OllamaTextGenerationModel.cjs +4 -4
  65. package/model-provider/ollama/OllamaTextGenerationModel.d.ts +2 -2
  66. package/model-provider/ollama/OllamaTextGenerationModel.js +4 -4
  67. package/model-provider/openai/OpenAICompletionModel.cjs +48 -53
  68. package/model-provider/openai/OpenAICompletionModel.d.ts +3 -6
  69. package/model-provider/openai/OpenAICompletionModel.js +48 -53
  70. package/model-provider/openai/OpenAIFacade.cjs +2 -2
  71. package/model-provider/openai/OpenAIFacade.d.ts +2 -2
  72. package/model-provider/openai/OpenAIFacade.js +2 -2
  73. package/model-provider/openai/chat/AbstractOpenAIChatModel.cjs +51 -55
  74. package/model-provider/openai/chat/AbstractOpenAIChatModel.d.ts +36 -8
  75. package/model-provider/openai/chat/AbstractOpenAIChatModel.js +51 -55
  76. package/model-provider/openai/chat/OpenAIChatModel.cjs +3 -3
  77. package/model-provider/openai/chat/OpenAIChatModel.d.ts +1 -1
  78. package/model-provider/openai/chat/OpenAIChatModel.js +3 -3
  79. package/model-provider/openai/chat/OpenAIChatModel.test.cjs +61 -0
  80. package/model-provider/openai/chat/OpenAIChatModel.test.d.ts +1 -0
  81. package/model-provider/openai/chat/OpenAIChatModel.test.js +59 -0
  82. package/model-provider/openai/chat/OpenAIChatStreamIterable.cjs +8 -3
  83. package/model-provider/openai/chat/OpenAIChatStreamIterable.d.ts +1 -1
  84. package/model-provider/openai/chat/OpenAIChatStreamIterable.js +8 -3
  85. package/model-provider/openai-compatible/OpenAICompatibleChatModel.cjs +2 -2
  86. package/model-provider/openai-compatible/OpenAICompatibleChatModel.js +2 -2
  87. package/model-provider/openai-compatible/OpenAICompatibleFacade.cjs +1 -1
  88. package/model-provider/openai-compatible/OpenAICompatibleFacade.d.ts +1 -1
  89. package/model-provider/openai-compatible/OpenAICompatibleFacade.js +1 -1
  90. package/package.json +1 -1
  91. package/tool/execute-tool/executeTool.cjs +1 -1
  92. package/tool/execute-tool/executeTool.d.ts +2 -2
  93. package/tool/execute-tool/executeTool.js +1 -1
  94. package/tool/generate-tool-call/TextGenerationToolCallModel.cjs +4 -4
  95. package/tool/generate-tool-call/TextGenerationToolCallModel.js +4 -4
  96. package/tool/generate-tool-call/generateToolCall.cjs +7 -1
  97. package/tool/generate-tool-call/generateToolCall.d.ts +3 -3
  98. package/tool/generate-tool-call/generateToolCall.js +7 -1
  99. package/tool/generate-tool-calls-or-text/TextGenerationToolCallsOrGenerateTextModel.cjs +4 -4
  100. package/tool/generate-tool-calls-or-text/TextGenerationToolCallsOrGenerateTextModel.js +4 -4
  101. package/tool/generate-tool-calls-or-text/generateToolCallsOrText.cjs +1 -1
  102. package/tool/generate-tool-calls-or-text/generateToolCallsOrText.d.ts +2 -2
  103. package/tool/generate-tool-calls-or-text/generateToolCallsOrText.js +1 -1
  104. package/tool/use-tools-or-generate-text/useToolsOrGenerateText.cjs +1 -1
  105. package/tool/use-tools-or-generate-text/useToolsOrGenerateText.js +1 -1
@@ -32,20 +32,48 @@ export interface AbstractOpenAIChatCallSettings {
32
32
  name: string;
33
33
  };
34
34
  };
35
- stop?: string | string[];
36
- maxTokens?: number;
35
+ /**
36
+ * `temperature`: Controls the randomness and creativity in the model's responses.
37
+ * A lower temperature (close to 0) results in more predictable, conservative text, while a higher temperature (close to 1) produces more varied and creative output.
38
+ * Adjust this to balance between consistency and creativity in the model's replies.
39
+ * Example: temperature: 0.5
40
+ */
37
41
  temperature?: number;
42
+ /**
43
+ * This parameter sets a threshold for token selection based on probability.
44
+ * The model will only consider the most likely tokens that cumulatively exceed this threshold while generating a response.
45
+ * It's a way to control the randomness of the output, balancing between diverse responses and sticking to more likely words.
46
+ * This means a topP of .1 will be far less random than one at .9
47
+ * Example: topP: 0.2
48
+ */
38
49
  topP?: number;
50
+ /**
51
+ * Used to set the initial state for the random number generator in the model.
52
+ * Providing a specific seed value ensures consistent outputs for the same inputs across different runs - useful for testing and reproducibility.
53
+ * A `null` value (or not setting it) results in varied, non-repeatable outputs each time.
54
+ * Example: seed: 89 (or) seed: null
55
+ */
39
56
  seed?: number | null;
57
+ /**
58
+ * Discourages the model from repeating the same information or context already mentioned in the conversation or prompt.
59
+ * Increasing this value encourages the model to introduce new topics or ideas, rather than reiterating what has been said.
60
+ * This is useful for maintaining a diverse and engaging conversation or for brainstorming sessions where varied ideas are needed.
61
+ * Example: presencePenalty: 1.0 // Strongly discourages repeating the same content.
62
+ */
63
+ presencePenalty?: number;
64
+ /**
65
+ * This parameter reduces the likelihood of the model repeatedly using the same words or phrases in its responses.
66
+ * A higher frequency penalty promotes a wider variety of language and expressions in the output.
67
+ * This is particularly useful in creative writing or content generation tasks where diversity in language is desirable.
68
+ * Example: frequencyPenalty: 0.5 // Moderately discourages repetitive language.
69
+ */
70
+ frequencyPenalty?: number;
40
71
  responseFormat?: {
41
72
  type?: "text" | "json_object";
42
73
  };
43
- n?: number;
44
- presencePenalty?: number;
45
- frequencyPenalty?: number;
46
74
  logitBias?: Record<number, number>;
47
75
  }
48
- export interface AbstractOpenAIChatSettings extends TextGenerationModelSettings, Omit<AbstractOpenAIChatCallSettings, "stop" | "maxTokens"> {
76
+ export interface AbstractOpenAIChatSettings extends TextGenerationModelSettings, AbstractOpenAIChatCallSettings {
49
77
  isUserIdForwardingEnabled?: boolean;
50
78
  }
51
79
  export type OpenAIChatPrompt = OpenAIChatMessage[];
@@ -64,7 +92,7 @@ export declare abstract class AbstractOpenAIChatModel<SETTINGS extends AbstractO
64
92
  tools?: AbstractOpenAIChatCallSettings["tools"];
65
93
  toolChoice?: AbstractOpenAIChatCallSettings["toolChoice"];
66
94
  }): Promise<RESULT>;
67
- doGenerateText(prompt: OpenAIChatPrompt, options?: FunctionOptions): Promise<{
95
+ doGenerateTexts(prompt: OpenAIChatPrompt, options?: FunctionOptions): Promise<{
68
96
  response: {
69
97
  object: "chat.completion";
70
98
  usage: {
@@ -98,7 +126,7 @@ export declare abstract class AbstractOpenAIChatModel<SETTINGS extends AbstractO
98
126
  }[];
99
127
  system_fingerprint?: string | null | undefined;
100
128
  };
101
- text: string;
129
+ texts: string[];
102
130
  usage: {
103
131
  promptTokens: number;
104
132
  completionTokens: number;
@@ -17,38 +17,67 @@ export class AbstractOpenAIChatModel extends AbstractModel {
17
17
  super({ settings });
18
18
  }
19
19
  async callAPI(messages, options) {
20
+ const api = this.settings.api ?? new OpenAIApiConfiguration();
21
+ const responseFormat = options.responseFormat;
22
+ const abortSignal = options.run?.abortSignal;
23
+ const user = this.settings.isUserIdForwardingEnabled
24
+ ? options.run?.userId
25
+ : undefined;
26
+ const openAIResponseFormat = this.settings.responseFormat;
27
+ // function & tool calling:
28
+ const functions = options.functions ?? this.settings.functions;
29
+ const functionCall = options.functionCall ?? this.settings.functionCall;
30
+ const tools = options.tools ?? this.settings.tools;
31
+ const toolChoice = options.toolChoice ?? this.settings.toolChoice;
32
+ let { stopSequences } = this.settings;
20
33
  return callWithRetryAndThrottle({
21
34
  retry: this.settings.api?.retry,
22
35
  throttle: this.settings.api?.throttle,
23
- call: async () => callOpenAIChatCompletionAPI({
24
- ...this.settings,
25
- // function & tool calling:
26
- functions: options.functions ?? this.settings.functions,
27
- functionCall: options.functionCall ?? this.settings.functionCall,
28
- tools: options.tools ?? this.settings.tools,
29
- toolChoice: options.toolChoice ?? this.settings.toolChoice,
30
- // map to OpenAI API names:
31
- stop: this.settings.stopSequences,
32
- maxTokens: this.settings.maxCompletionTokens,
33
- openAIResponseFormat: this.settings.responseFormat,
34
- // other settings:
35
- user: this.settings.isUserIdForwardingEnabled
36
- ? options.run?.userId
37
- : undefined,
38
- abortSignal: options.run?.abortSignal,
39
- responseFormat: options.responseFormat,
40
- messages,
41
- }),
36
+ call: async () => {
37
+ // empty arrays are not allowed for stopSequences:
38
+ if (stopSequences != null &&
39
+ Array.isArray(stopSequences) &&
40
+ stopSequences.length === 0) {
41
+ stopSequences = undefined;
42
+ }
43
+ return postJsonToApi({
44
+ url: api.assembleUrl("/chat/completions"),
45
+ headers: api.headers,
46
+ body: {
47
+ stream: responseFormat.stream,
48
+ model: this.settings.model,
49
+ messages,
50
+ functions,
51
+ function_call: functionCall,
52
+ tools,
53
+ tool_choice: toolChoice,
54
+ temperature: this.settings.temperature,
55
+ top_p: this.settings.topP,
56
+ n: this.settings.numberOfGenerations,
57
+ stop: this.settings.stopSequences,
58
+ max_tokens: this.settings.maxGenerationTokens,
59
+ presence_penalty: this.settings.presencePenalty,
60
+ frequency_penalty: this.settings.frequencyPenalty,
61
+ logit_bias: this.settings.logitBias,
62
+ seed: this.settings.seed,
63
+ response_format: openAIResponseFormat,
64
+ user,
65
+ },
66
+ failedResponseHandler: failedOpenAICallResponseHandler,
67
+ successfulResponseHandler: responseFormat.handler,
68
+ abortSignal,
69
+ });
70
+ },
42
71
  });
43
72
  }
44
- async doGenerateText(prompt, options) {
73
+ async doGenerateTexts(prompt, options) {
45
74
  const response = await this.callAPI(prompt, {
46
75
  ...options,
47
76
  responseFormat: OpenAIChatResponseFormat.json,
48
77
  });
49
78
  return {
50
79
  response,
51
- text: response.choices[0].message.content,
80
+ texts: response.choices.map((choice) => choice.message.content ?? ""),
52
81
  usage: this.extractUsage(response),
53
82
  };
54
83
  }
@@ -169,39 +198,6 @@ const openAIChatResponseSchema = z.object({
169
198
  total_tokens: z.number(),
170
199
  }),
171
200
  });
172
- async function callOpenAIChatCompletionAPI({ api = new OpenAIApiConfiguration(), abortSignal, responseFormat, model, messages, functions, functionCall, tools, toolChoice, temperature, topP, n, stop, maxTokens, presencePenalty, frequencyPenalty, logitBias, user, openAIResponseFormat, seed, }) {
173
- // empty arrays are not allowed for stop:
174
- if (stop != null && Array.isArray(stop) && stop.length === 0) {
175
- stop = undefined;
176
- }
177
- return postJsonToApi({
178
- url: api.assembleUrl("/chat/completions"),
179
- headers: api.headers,
180
- body: {
181
- stream: responseFormat.stream,
182
- model,
183
- messages,
184
- functions,
185
- function_call: functionCall,
186
- tools,
187
- tool_choice: toolChoice,
188
- temperature,
189
- top_p: topP,
190
- n,
191
- stop,
192
- max_tokens: maxTokens,
193
- presence_penalty: presencePenalty,
194
- frequency_penalty: frequencyPenalty,
195
- logit_bias: logitBias,
196
- seed,
197
- response_format: openAIResponseFormat,
198
- user,
199
- },
200
- failedResponseHandler: failedOpenAICallResponseHandler,
201
- successfulResponseHandler: responseFormat.handler,
202
- abortSignal,
203
- });
204
- }
205
201
  export const OpenAIChatResponseFormat = {
206
202
  /**
207
203
  * Returns the response as a JSON object.
@@ -215,7 +211,7 @@ export const OpenAIChatResponseFormat = {
215
211
  */
216
212
  textDeltaIterable: {
217
213
  stream: true,
218
- handler: async ({ response }) => createOpenAIChatDeltaIterableQueue(response.body, (delta) => delta[0]?.delta.content ?? ""),
214
+ handler: async ({ response }) => createOpenAIChatDeltaIterableQueue(response.body, (delta) => delta[0]?.delta?.content ?? ""),
219
215
  },
220
216
  structureDeltaIterable: {
221
217
  stream: true,
@@ -144,7 +144,7 @@ exports.calculateOpenAIChatCostInMillicents = calculateOpenAIChatCostInMillicent
144
144
  * const model = new OpenAIChatModel({
145
145
  * model: "gpt-3.5-turbo",
146
146
  * temperature: 0.7,
147
- * maxCompletionTokens: 500,
147
+ * maxGenerationTokens: 500,
148
148
  * });
149
149
  *
150
150
  * const text = await generateText([
@@ -196,13 +196,13 @@ class OpenAIChatModel extends AbstractOpenAIChatModel_js_1.AbstractOpenAIChatMod
196
196
  }
197
197
  get settingsForEvent() {
198
198
  const eventSettingProperties = [
199
+ "maxGenerationTokens",
199
200
  "stopSequences",
200
- "maxCompletionTokens",
201
+ "numberOfGenerations",
201
202
  "functions",
202
203
  "functionCall",
203
204
  "temperature",
204
205
  "topP",
205
- "n",
206
206
  "presencePenalty",
207
207
  "frequencyPenalty",
208
208
  "logitBias",
@@ -117,7 +117,7 @@ export interface OpenAIChatSettings extends TextGenerationModelSettings, Omit<Op
117
117
  * const model = new OpenAIChatModel({
118
118
  * model: "gpt-3.5-turbo",
119
119
  * temperature: 0.7,
120
- * maxCompletionTokens: 500,
120
+ * maxGenerationTokens: 500,
121
121
  * });
122
122
  *
123
123
  * const text = await generateText([
@@ -138,7 +138,7 @@ export const calculateOpenAIChatCostInMillicents = ({ model, response, }) => {
138
138
  * const model = new OpenAIChatModel({
139
139
  * model: "gpt-3.5-turbo",
140
140
  * temperature: 0.7,
141
- * maxCompletionTokens: 500,
141
+ * maxGenerationTokens: 500,
142
142
  * });
143
143
  *
144
144
  * const text = await generateText([
@@ -190,13 +190,13 @@ export class OpenAIChatModel extends AbstractOpenAIChatModel {
190
190
  }
191
191
  get settingsForEvent() {
192
192
  const eventSettingProperties = [
193
+ "maxGenerationTokens",
193
194
  "stopSequences",
194
- "maxCompletionTokens",
195
+ "numberOfGenerations",
195
196
  "functions",
196
197
  "functionCall",
197
198
  "temperature",
198
199
  "topP",
199
- "n",
200
200
  "presencePenalty",
201
201
  "frequencyPenalty",
202
202
  "logitBias",
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const msw_1 = require("msw");
4
+ const node_1 = require("msw/node");
5
+ const streamText_js_1 = require("../../../model-function/generate-text/streamText.cjs");
6
+ const OpenAIChatModel_js_1 = require("./OpenAIChatModel.cjs");
7
+ const OpenAIApiConfiguration_js_1 = require("../OpenAIApiConfiguration.cjs");
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ let responseChunks = [];
10
+ const server = (0, node_1.setupServer)(msw_1.http.post("https://api.openai.com/v1/chat/completions", () => {
11
+ const encoder = new TextEncoder();
12
+ const stream = new ReadableStream({
13
+ async start(controller) {
14
+ try {
15
+ for (const chunk of responseChunks) {
16
+ controller.enqueue(encoder.encode(chunk));
17
+ }
18
+ }
19
+ finally {
20
+ controller.close();
21
+ }
22
+ },
23
+ });
24
+ return new msw_1.HttpResponse(stream, {
25
+ status: 200,
26
+ headers: {
27
+ "Content-Type": "text/event-stream",
28
+ "Cache-Control": "no-cache",
29
+ Connection: "keep-alive",
30
+ },
31
+ });
32
+ }));
33
+ beforeAll(() => server.listen());
34
+ beforeEach(() => {
35
+ responseChunks = [];
36
+ });
37
+ afterEach(() => server.resetHandlers());
38
+ afterAll(() => server.close());
39
+ describe("streamText", () => {
40
+ it("should return only values from the first choice when using streamText", async () => {
41
+ responseChunks = [
42
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}\n\n`,
43
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"A"},"finish_reason":null}]}\n\n`,
44
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":1,"delta":{"role":"assistant","content":""},"finish_reason":null}]}\n\n`,
45
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":1,"delta":{"content":"B"},"finish_reason":null}]}\n\n`,
46
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}\n\n`,
47
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":1,"delta":{},"finish_reason":"stop"}]}\n\n`,
48
+ "data: [DONE]\n\n",
49
+ ];
50
+ const stream = await (0, streamText_js_1.streamText)(new OpenAIChatModel_js_1.OpenAIChatModel({
51
+ api: new OpenAIApiConfiguration_js_1.OpenAIApiConfiguration({ apiKey: "test" }),
52
+ model: "gpt-3.5-turbo",
53
+ numberOfGenerations: 2,
54
+ }).withTextPrompt(), "test prompt");
55
+ const chunks = [];
56
+ for await (const part of stream) {
57
+ chunks.push(part);
58
+ }
59
+ expect(chunks).toStrictEqual(["A"]);
60
+ });
61
+ });
@@ -0,0 +1,59 @@
1
+ import { HttpResponse, http } from "msw";
2
+ import { setupServer } from "msw/node";
3
+ import { streamText } from "../../../model-function/generate-text/streamText.js";
4
+ import { OpenAIChatModel } from "./OpenAIChatModel.js";
5
+ import { OpenAIApiConfiguration } from "../OpenAIApiConfiguration.js";
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ let responseChunks = [];
8
+ const server = setupServer(http.post("https://api.openai.com/v1/chat/completions", () => {
9
+ const encoder = new TextEncoder();
10
+ const stream = new ReadableStream({
11
+ async start(controller) {
12
+ try {
13
+ for (const chunk of responseChunks) {
14
+ controller.enqueue(encoder.encode(chunk));
15
+ }
16
+ }
17
+ finally {
18
+ controller.close();
19
+ }
20
+ },
21
+ });
22
+ return new HttpResponse(stream, {
23
+ status: 200,
24
+ headers: {
25
+ "Content-Type": "text/event-stream",
26
+ "Cache-Control": "no-cache",
27
+ Connection: "keep-alive",
28
+ },
29
+ });
30
+ }));
31
+ beforeAll(() => server.listen());
32
+ beforeEach(() => {
33
+ responseChunks = [];
34
+ });
35
+ afterEach(() => server.resetHandlers());
36
+ afterAll(() => server.close());
37
+ describe("streamText", () => {
38
+ it("should return only values from the first choice when using streamText", async () => {
39
+ responseChunks = [
40
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}\n\n`,
41
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"A"},"finish_reason":null}]}\n\n`,
42
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":1,"delta":{"role":"assistant","content":""},"finish_reason":null}]}\n\n`,
43
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":1,"delta":{"content":"B"},"finish_reason":null}]}\n\n`,
44
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}\n\n`,
45
+ `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1702657020,"model":"gpt-3.5-turbo-0613","system_fingerprint":null,"choices":[{"index":1,"delta":{},"finish_reason":"stop"}]}\n\n`,
46
+ "data: [DONE]\n\n",
47
+ ];
48
+ const stream = await streamText(new OpenAIChatModel({
49
+ api: new OpenAIApiConfiguration({ apiKey: "test" }),
50
+ model: "gpt-3.5-turbo",
51
+ numberOfGenerations: 2,
52
+ }).withTextPrompt(), "test prompt");
53
+ const chunks = [];
54
+ for await (const part of stream) {
55
+ chunks.push(part);
56
+ }
57
+ expect(chunks).toStrictEqual(["A"]);
58
+ });
59
+ });
@@ -87,18 +87,23 @@ async function createOpenAIChatDeltaIterableQueue(stream, extractDeltaValue) {
87
87
  continue;
88
88
  }
89
89
  const completionChunk = eventData;
90
+ // reset delta for all existing streamDeltas
91
+ for (const delta of streamDelta) {
92
+ delta.delta = undefined;
93
+ }
90
94
  for (let i = 0; i < completionChunk.choices.length; i++) {
91
95
  const eventChoice = completionChunk.choices[i];
96
+ const index = eventChoice.index;
92
97
  const delta = eventChoice.delta;
93
- if (streamDelta[i] == null) {
94
- streamDelta[i] = {
98
+ if (streamDelta[index] == null) {
99
+ streamDelta[index] = {
95
100
  role: undefined,
96
101
  content: "",
97
102
  isComplete: false,
98
103
  delta,
99
104
  };
100
105
  }
101
- const choice = streamDelta[i];
106
+ const choice = streamDelta[index];
102
107
  choice.delta = delta;
103
108
  if (eventChoice.finish_reason != null) {
104
109
  choice.isComplete = true;
@@ -14,6 +14,6 @@ export type OpenAIChatDelta = Array<{
14
14
  name?: string;
15
15
  arguments?: string;
16
16
  };
17
- };
17
+ } | undefined;
18
18
  }>;
19
19
  export declare function createOpenAIChatDeltaIterableQueue<VALUE>(stream: ReadableStream<Uint8Array>, extractDeltaValue: (delta: OpenAIChatDelta) => VALUE): Promise<AsyncIterable<Delta<VALUE>>>;
@@ -84,18 +84,23 @@ export async function createOpenAIChatDeltaIterableQueue(stream, extractDeltaVal
84
84
  continue;
85
85
  }
86
86
  const completionChunk = eventData;
87
+ // reset delta for all existing streamDeltas
88
+ for (const delta of streamDelta) {
89
+ delta.delta = undefined;
90
+ }
87
91
  for (let i = 0; i < completionChunk.choices.length; i++) {
88
92
  const eventChoice = completionChunk.choices[i];
93
+ const index = eventChoice.index;
89
94
  const delta = eventChoice.delta;
90
- if (streamDelta[i] == null) {
91
- streamDelta[i] = {
95
+ if (streamDelta[index] == null) {
96
+ streamDelta[index] = {
92
97
  role: undefined,
93
98
  content: "",
94
99
  isComplete: false,
95
100
  delta,
96
101
  };
97
102
  }
98
- const choice = streamDelta[i];
103
+ const choice = streamDelta[index];
99
104
  choice.delta = delta;
100
105
  if (eventChoice.finish_reason != null) {
101
106
  choice.isComplete = true;
@@ -44,12 +44,12 @@ class OpenAICompatibleChatModel extends AbstractOpenAIChatModel_js_1.AbstractOpe
44
44
  get settingsForEvent() {
45
45
  const eventSettingProperties = [
46
46
  "stopSequences",
47
- "maxCompletionTokens",
47
+ "maxGenerationTokens",
48
+ "numberOfGenerations",
48
49
  "functions",
49
50
  "functionCall",
50
51
  "temperature",
51
52
  "topP",
52
- "n",
53
53
  "presencePenalty",
54
54
  "frequencyPenalty",
55
55
  "logitBias",
@@ -41,12 +41,12 @@ export class OpenAICompatibleChatModel extends AbstractOpenAIChatModel {
41
41
  get settingsForEvent() {
42
42
  const eventSettingProperties = [
43
43
  "stopSequences",
44
- "maxCompletionTokens",
44
+ "maxGenerationTokens",
45
+ "numberOfGenerations",
45
46
  "functions",
46
47
  "functionCall",
47
48
  "temperature",
48
49
  "topP",
49
- "n",
50
50
  "presencePenalty",
51
51
  "frequencyPenalty",
52
52
  "logitBias",
@@ -14,7 +14,7 @@ const OpenAICompatibleChatModel_js_1 = require("./OpenAICompatibleChatModel.cjs"
14
14
  * const model = openaicompatible.ChatTextGenerator({
15
15
  * model: "provider-specific-model-name",
16
16
  * temperature: 0.7,
17
- * maxCompletionTokens: 500,
17
+ * maxGenerationTokens: 500,
18
18
  * });
19
19
  *
20
20
  * const text = await generateText([
@@ -11,7 +11,7 @@ import { OpenAICompatibleChatModel, OpenAICompatibleChatSettings } from "./OpenA
11
11
  * const model = openaicompatible.ChatTextGenerator({
12
12
  * model: "provider-specific-model-name",
13
13
  * temperature: 0.7,
14
- * maxCompletionTokens: 500,
14
+ * maxGenerationTokens: 500,
15
15
  * });
16
16
  *
17
17
  * const text = await generateText([
@@ -11,7 +11,7 @@ import { OpenAICompatibleChatModel, } from "./OpenAICompatibleChatModel.js";
11
11
  * const model = openaicompatible.ChatTextGenerator({
12
12
  * model: "provider-specific-model-name",
13
13
  * temperature: 0.7,
14
- * maxCompletionTokens: 500,
14
+ * maxGenerationTokens: 500,
15
15
  * });
16
16
  *
17
17
  * const text = await generateText([
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modelfusion",
3
3
  "description": "The TypeScript library for building multi-modal AI applications.",
4
- "version": "0.97.0",
4
+ "version": "0.99.0",
5
5
  "author": "Lars Grammel",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -13,7 +13,7 @@ const ToolExecutionError_js_1 = require("../ToolExecutionError.cjs");
13
13
  async function executeTool(// eslint-disable-line @typescript-eslint/no-explicit-any
14
14
  tool, args, options) {
15
15
  const fullResponse = await doExecuteTool(tool, args, options);
16
- return options?.returnType === "full" ? fullResponse : fullResponse.output;
16
+ return options?.fullResponse ? fullResponse : fullResponse.output;
17
17
  }
18
18
  exports.executeTool = executeTool;
19
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -15,11 +15,11 @@ export type ExecuteToolMetadata = {
15
15
  */
16
16
  export declare function executeTool<TOOL extends Tool<any, any, any>>(// eslint-disable-line @typescript-eslint/no-explicit-any
17
17
  tool: TOOL, args: TOOL["parameters"]["_type"], options?: FunctionOptions & {
18
- returnType?: "output";
18
+ fullResponse?: false;
19
19
  }): Promise<ReturnType<TOOL["execute"]>>;
20
20
  export declare function executeTool<TOOL extends Tool<any, any, any>>(// eslint-disable-line @typescript-eslint/no-explicit-any
21
21
  tool: TOOL, args: TOOL["parameters"]["_type"], options: FunctionOptions & {
22
- returnType: "full";
22
+ fullResponse: true;
23
23
  }): Promise<{
24
24
  output: Awaited<ReturnType<TOOL["execute"]>>;
25
25
  metadata: ExecuteToolMetadata;
@@ -10,7 +10,7 @@ import { ToolExecutionError } from "../ToolExecutionError.js";
10
10
  export async function executeTool(// eslint-disable-line @typescript-eslint/no-explicit-any
11
11
  tool, args, options) {
12
12
  const fullResponse = await doExecuteTool(tool, args, options);
13
- return options?.returnType === "full" ? fullResponse : fullResponse.output;
13
+ return options?.fullResponse ? fullResponse : fullResponse.output;
14
14
  }
15
15
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
16
  async function doExecuteTool(tool, args, options) {
@@ -30,21 +30,21 @@ class TextGenerationToolCallModel {
30
30
  return this.model.settingsForEvent;
31
31
  }
32
32
  async doGenerateToolCall(tool, prompt, options) {
33
- const { response, value, metadata } = await (0, generateText_js_1.generateText)(this.model, this.format.createPrompt(prompt, tool), {
33
+ const { response, text, metadata } = await (0, generateText_js_1.generateText)(this.model, this.format.createPrompt(prompt, tool), {
34
34
  ...options,
35
- returnType: "full",
35
+ fullResponse: true,
36
36
  });
37
37
  try {
38
38
  return {
39
39
  response,
40
- toolCall: this.format.extractToolCall(value),
40
+ toolCall: this.format.extractToolCall(text),
41
41
  usage: metadata?.usage,
42
42
  };
43
43
  }
44
44
  catch (error) {
45
45
  throw new ToolCallParseError_js_1.ToolCallParseError({
46
46
  toolName: tool.name,
47
- valueText: value,
47
+ valueText: text,
48
48
  cause: error,
49
49
  });
50
50
  }
@@ -27,21 +27,21 @@ export class TextGenerationToolCallModel {
27
27
  return this.model.settingsForEvent;
28
28
  }
29
29
  async doGenerateToolCall(tool, prompt, options) {
30
- const { response, value, metadata } = await generateText(this.model, this.format.createPrompt(prompt, tool), {
30
+ const { response, text, metadata } = await generateText(this.model, this.format.createPrompt(prompt, tool), {
31
31
  ...options,
32
- returnType: "full",
32
+ fullResponse: true,
33
33
  });
34
34
  try {
35
35
  return {
36
36
  response,
37
- toolCall: this.format.extractToolCall(value),
37
+ toolCall: this.format.extractToolCall(text),
38
38
  usage: metadata?.usage,
39
39
  };
40
40
  }
41
41
  catch (error) {
42
42
  throw new ToolCallParseError({
43
43
  toolName: tool.name,
44
- valueText: value,
44
+ valueText: text,
45
45
  cause: error,
46
46
  });
47
47
  }
@@ -54,6 +54,12 @@ async function generateToolCall(model, tool, prompt, options) {
54
54
  }
55
55
  },
56
56
  });
57
- return options?.returnType === "full" ? fullResponse : fullResponse.value;
57
+ return options?.fullResponse
58
+ ? {
59
+ toolCall: fullResponse.value,
60
+ response: fullResponse.response,
61
+ metadata: fullResponse.metadata,
62
+ }
63
+ : fullResponse.value;
58
64
  }
59
65
  exports.generateToolCall = generateToolCall;