modelfusion 0.51.0 → 0.53.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 (50) hide show
  1. package/README.md +2 -10
  2. package/core/ExecuteFunctionEvent.cjs +2 -0
  3. package/core/ExecuteFunctionEvent.d.ts +7 -0
  4. package/core/ExecuteFunctionEvent.js +1 -0
  5. package/core/FunctionEvent.d.ts +2 -1
  6. package/core/api/loadApiKey.cjs +2 -2
  7. package/core/api/loadApiKey.js +2 -2
  8. package/core/executeFunction.cjs +19 -0
  9. package/core/executeFunction.d.ts +2 -0
  10. package/core/executeFunction.js +15 -0
  11. package/core/index.cjs +2 -0
  12. package/core/index.d.ts +2 -0
  13. package/core/index.js +2 -0
  14. package/event-source/index.cjs +0 -1
  15. package/event-source/index.d.ts +0 -1
  16. package/event-source/index.js +0 -1
  17. package/event-source/readEventSourceStream.cjs +1 -1
  18. package/event-source/readEventSourceStream.js +1 -1
  19. package/model-function/executeStreamCall.cjs +9 -3
  20. package/model-function/executeStreamCall.js +9 -3
  21. package/model-function/generate-speech/streamSpeech.cjs +1 -1
  22. package/model-function/generate-speech/streamSpeech.js +1 -1
  23. package/model-provider/anthropic/AnthropicTextGenerationModel.cjs +1 -1
  24. package/model-provider/anthropic/AnthropicTextGenerationModel.js +1 -1
  25. package/model-provider/cohere/CohereTextGenerationModel.cjs +1 -1
  26. package/model-provider/cohere/CohereTextGenerationModel.js +1 -1
  27. package/model-provider/elevenlabs/ElevenLabsSpeechModel.cjs +1 -1
  28. package/model-provider/elevenlabs/ElevenLabsSpeechModel.js +1 -1
  29. package/model-provider/llamacpp/LlamaCppTextGenerationModel.cjs +1 -1
  30. package/model-provider/llamacpp/LlamaCppTextGenerationModel.js +1 -1
  31. package/model-provider/openai/OpenAICompletionModel.cjs +1 -1
  32. package/model-provider/openai/OpenAICompletionModel.js +1 -1
  33. package/model-provider/openai/chat/OpenAIChatStreamIterable.cjs +1 -1
  34. package/model-provider/openai/chat/OpenAIChatStreamIterable.js +1 -1
  35. package/package.json +2 -2
  36. package/util/AsyncQueue.cjs +106 -0
  37. package/util/AsyncQueue.d.ts +49 -0
  38. package/util/AsyncQueue.js +102 -0
  39. package/util/AsyncQueue.test.cjs +138 -0
  40. package/util/AsyncQueue.test.d.ts +1 -0
  41. package/util/AsyncQueue.test.js +136 -0
  42. package/util/delay.cjs +7 -0
  43. package/util/delay.d.ts +1 -0
  44. package/util/delay.js +3 -0
  45. package/util/index.cjs +1 -0
  46. package/util/index.d.ts +1 -0
  47. package/util/index.js +1 -0
  48. package/event-source/AsyncQueue.cjs +0 -67
  49. package/event-source/AsyncQueue.d.ts +0 -8
  50. package/event-source/AsyncQueue.js +0 -63
package/README.md CHANGED
@@ -65,8 +65,8 @@ const textStream = await streamText(
65
65
  "Write a short story about a robot learning to love:\n\n"
66
66
  );
67
67
 
68
- for await (const textFragment of textStream) {
69
- process.stdout.write(textFragment);
68
+ for await (const textPart of textStream) {
69
+ process.stdout.write(textPart);
70
70
  }
71
71
  ```
72
72
 
@@ -664,11 +664,3 @@ Generate text on a Cloudflare Worker using ModelFusion and OpenAI.
664
664
  ### [Contributing Guide](https://github.com/lgrammel/modelfusion/blob/main/CONTRIBUTING.md)
665
665
 
666
666
  Read the [ModelFusion contributing guide](https://github.com/lgrammel/modelfusion/blob/main/CONTRIBUTING.md) to learn about the development process, how to propose bugfixes and improvements, and how to build and test your changes.
667
-
668
- ```
669
-
670
- ```
671
-
672
- ```
673
-
674
- ```
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ import { BaseFunctionFinishedEvent, BaseFunctionStartedEvent } from "./FunctionEvent.js";
2
+ export interface ExecuteFunctionStartedEvent extends BaseFunctionStartedEvent {
3
+ functionType: "execute-function";
4
+ }
5
+ export interface ExecuteFunctionFinishedEvent extends BaseFunctionFinishedEvent {
6
+ functionType: "execute-function";
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,4 @@
1
+ import { ExecuteFunctionFinishedEvent, ExecuteFunctionStartedEvent } from "./ExecuteFunctionEvent.js";
1
2
  import { GuardFinishedEvent, GuardStartedEvent } from "../guard/GuardEvent.js";
2
3
  import { ModelCallFinishedEvent, ModelCallStartedEvent } from "../model-function/ModelCallEvent.js";
3
4
  import { RetrieveFinishedEvent, RetrieveStartedEvent } from "../retriever/RetrieveEvent.js";
@@ -81,4 +82,4 @@ export interface BaseFunctionFinishedEvent extends BaseFunctionEvent {
81
82
  */
82
83
  result: BaseFunctionFinishedEventResult;
83
84
  }
84
- export type FunctionEvent = ExecuteToolStartedEvent | ExecuteToolFinishedEvent | GuardStartedEvent | GuardFinishedEvent | ModelCallStartedEvent | ModelCallFinishedEvent | RetrieveStartedEvent | RetrieveFinishedEvent | UpsertIntoVectorIndexStartedEvent | UpsertIntoVectorIndexFinishedEvent | UseToolStartedEvent | UseToolFinishedEvent | UseToolOrGenerateTextStartedEvent | UseToolOrGenerateTextFinishedEvent;
85
+ export type FunctionEvent = ExecuteFunctionStartedEvent | ExecuteFunctionFinishedEvent | ExecuteToolStartedEvent | ExecuteToolFinishedEvent | GuardStartedEvent | GuardFinishedEvent | ModelCallStartedEvent | ModelCallFinishedEvent | RetrieveStartedEvent | RetrieveFinishedEvent | UpsertIntoVectorIndexStartedEvent | UpsertIntoVectorIndexFinishedEvent | UseToolStartedEvent | UseToolFinishedEvent | UseToolOrGenerateTextStartedEvent | UseToolOrGenerateTextFinishedEvent;
@@ -6,11 +6,11 @@ function loadApiKey({ apiKey, environmentVariableName, apiKeyParameterName = "ap
6
6
  return apiKey;
7
7
  }
8
8
  if (typeof process === "undefined") {
9
- throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter. Environment variables is not supported in this environment.`);
9
+ throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter into the API configuration. Environment variables is not supported in this environment.`);
10
10
  }
11
11
  apiKey = process.env[environmentVariableName];
12
12
  if (apiKey == null) {
13
- throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter or set it as an environment variable named ${environmentVariableName}.`);
13
+ throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter into the API configuration or set it as an environment variable named ${environmentVariableName}.`);
14
14
  }
15
15
  return apiKey;
16
16
  }
@@ -3,11 +3,11 @@ export function loadApiKey({ apiKey, environmentVariableName, apiKeyParameterNam
3
3
  return apiKey;
4
4
  }
5
5
  if (typeof process === "undefined") {
6
- throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter. Environment variables is not supported in this environment.`);
6
+ throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter into the API configuration. Environment variables is not supported in this environment.`);
7
7
  }
8
8
  apiKey = process.env[environmentVariableName];
9
9
  if (apiKey == null) {
10
- throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter or set it as an environment variable named ${environmentVariableName}.`);
10
+ throw new Error(`${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter into the API configuration or set it as an environment variable named ${environmentVariableName}.`);
11
11
  }
12
12
  return apiKey;
13
13
  }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeFunction = void 0;
4
+ const executeFunctionCall_js_1 = require("./executeFunctionCall.cjs");
5
+ async function executeFunction(fn, input, options) {
6
+ return (0, executeFunctionCall_js_1.executeFunctionCall)({
7
+ options,
8
+ input,
9
+ functionType: "execute-function",
10
+ execute: async (options) => fn(input, {
11
+ // omit functionId
12
+ logging: options?.logging,
13
+ observers: options?.observers,
14
+ run: options?.run,
15
+ parentCallId: options?.parentCallId,
16
+ }),
17
+ });
18
+ }
19
+ exports.executeFunction = executeFunction;
@@ -0,0 +1,2 @@
1
+ import { FunctionOptions } from "./FunctionOptions.js";
2
+ export declare function executeFunction<INPUT, OUTPUT>(fn: (input: INPUT, options?: FunctionOptions) => PromiseLike<OUTPUT>, input: INPUT, options?: FunctionOptions): Promise<OUTPUT>;
@@ -0,0 +1,15 @@
1
+ import { executeFunctionCall } from "./executeFunctionCall.js";
2
+ export async function executeFunction(fn, input, options) {
3
+ return executeFunctionCall({
4
+ options,
5
+ input,
6
+ functionType: "execute-function",
7
+ execute: async (options) => fn(input, {
8
+ // omit functionId
9
+ logging: options?.logging,
10
+ observers: options?.observers,
11
+ run: options?.run,
12
+ parentCallId: options?.parentCallId,
13
+ }),
14
+ });
15
+ }
package/core/index.cjs CHANGED
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./DefaultRun.cjs"), exports);
18
+ __exportStar(require("./ExecuteFunctionEvent.cjs"), exports);
18
19
  __exportStar(require("./FunctionEvent.cjs"), exports);
19
20
  __exportStar(require("./FunctionEventSource.cjs"), exports);
20
21
  __exportStar(require("./FunctionObserver.cjs"), exports);
@@ -24,5 +25,6 @@ __exportStar(require("./GlobalFunctionObservers.cjs"), exports);
24
25
  __exportStar(require("./Run.cjs"), exports);
25
26
  __exportStar(require("./Vector.cjs"), exports);
26
27
  __exportStar(require("./api/index.cjs"), exports);
28
+ __exportStar(require("./executeFunction.cjs"), exports);
27
29
  __exportStar(require("./getRun.cjs"), exports);
28
30
  __exportStar(require("./structure/index.cjs"), exports);
package/core/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./DefaultRun.js";
2
+ export * from "./ExecuteFunctionEvent.js";
2
3
  export * from "./FunctionEvent.js";
3
4
  export * from "./FunctionEventSource.js";
4
5
  export * from "./FunctionObserver.js";
@@ -8,5 +9,6 @@ export * from "./GlobalFunctionObservers.js";
8
9
  export * from "./Run.js";
9
10
  export * from "./Vector.js";
10
11
  export * from "./api/index.js";
12
+ export * from "./executeFunction.js";
11
13
  export * from "./getRun.js";
12
14
  export * from "./structure/index.js";
package/core/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./DefaultRun.js";
2
+ export * from "./ExecuteFunctionEvent.js";
2
3
  export * from "./FunctionEvent.js";
3
4
  export * from "./FunctionEventSource.js";
4
5
  export * from "./FunctionObserver.js";
@@ -8,5 +9,6 @@ export * from "./GlobalFunctionObservers.js";
8
9
  export * from "./Run.js";
9
10
  export * from "./Vector.js";
10
11
  export * from "./api/index.js";
12
+ export * from "./executeFunction.js";
11
13
  export * from "./getRun.js";
12
14
  export * from "./structure/index.js";
@@ -14,7 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./AsyncQueue.cjs"), exports);
18
17
  __exportStar(require("./createEventSourceStream.cjs"), exports);
19
18
  __exportStar(require("./readEventSource.cjs"), exports);
20
19
  __exportStar(require("./readEventSourceStream.cjs"), exports);
@@ -1,4 +1,3 @@
1
- export * from "./AsyncQueue.js";
2
1
  export * from "./createEventSourceStream.js";
3
2
  export * from "./readEventSource.js";
4
3
  export * from "./readEventSourceStream.js";
@@ -1,4 +1,3 @@
1
- export * from "./AsyncQueue.js";
2
1
  export * from "./createEventSourceStream.js";
3
2
  export * from "./readEventSource.js";
4
3
  export * from "./readEventSourceStream.js";
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readEventSourceStream = void 0;
4
4
  const parseJSON_js_1 = require("../util/parseJSON.cjs");
5
- const AsyncQueue_js_1 = require("./AsyncQueue.cjs");
5
+ const AsyncQueue_js_1 = require("../util/AsyncQueue.cjs");
6
6
  const parseEventSourceStream_js_1 = require("./parseEventSourceStream.cjs");
7
7
  function readEventSourceStream({ stream, schema, errorHandler, }) {
8
8
  const queue = new AsyncQueue_js_1.AsyncQueue();
@@ -1,5 +1,5 @@
1
1
  import { safeParseJsonWithSchema } from "../util/parseJSON.js";
2
- import { AsyncQueue } from "./AsyncQueue.js";
2
+ import { AsyncQueue } from "../util/AsyncQueue.js";
3
3
  import { parseEventSourceStream } from "./parseEventSourceStream.js";
4
4
  export function readEventSourceStream({ stream, schema, errorHandler, }) {
5
5
  const queue = new AsyncQueue();
@@ -8,6 +8,7 @@ const GlobalFunctionObservers_js_1 = require("../core/GlobalFunctionObservers.cj
8
8
  const AbortError_js_1 = require("../core/api/AbortError.cjs");
9
9
  const getFunctionCallLogger_js_1 = require("../core/getFunctionCallLogger.cjs");
10
10
  const getRun_js_1 = require("../core/getRun.cjs");
11
+ const AsyncQueue_js_1 = require("../util/AsyncQueue.cjs");
11
12
  const DurationMeasurement_js_1 = require("../util/DurationMeasurement.cjs");
12
13
  const runSafe_js_1 = require("../util/runSafe.cjs");
13
14
  async function executeStreamCall({ model, options, input, functionType, startStream, processDelta, processFinished, getResult, }) {
@@ -50,7 +51,10 @@ async function executeStreamCall({ model, options, input, functionType, startStr
50
51
  run,
51
52
  parentCallId: startMetadata.callId,
52
53
  });
53
- return (async function* () {
54
+ // Return a queue that can be iterated over several times:
55
+ const responseQueue = new AsyncQueue_js_1.AsyncQueue();
56
+ // run async:
57
+ (async function () {
54
58
  for await (const event of deltaIterable) {
55
59
  if (event?.type === "error") {
56
60
  const error = event.error;
@@ -74,16 +78,17 @@ async function executeStreamCall({ model, options, input, functionType, startStr
74
78
  if (event?.type === "delta") {
75
79
  const value = processDelta(event);
76
80
  if (value !== undefined) {
77
- yield value;
81
+ responseQueue.push(value);
78
82
  }
79
83
  }
80
84
  }
81
85
  if (processFinished != null) {
82
86
  const value = processFinished();
83
87
  if (value !== undefined) {
84
- yield value;
88
+ responseQueue.push(value);
85
89
  }
86
90
  }
91
+ responseQueue.close();
87
92
  const finishMetadata = {
88
93
  eventType: "finished",
89
94
  ...startMetadata,
@@ -98,6 +103,7 @@ async function executeStreamCall({ model, options, input, functionType, startStr
98
103
  },
99
104
  });
100
105
  })();
106
+ return responseQueue;
101
107
  });
102
108
  if (!result.ok) {
103
109
  const finishMetadata = {
@@ -5,6 +5,7 @@ import { getGlobalFunctionObservers } from "../core/GlobalFunctionObservers.js";
5
5
  import { AbortError } from "../core/api/AbortError.js";
6
6
  import { getFunctionCallLogger } from "../core/getFunctionCallLogger.js";
7
7
  import { getRun } from "../core/getRun.js";
8
+ import { AsyncQueue } from "../util/AsyncQueue.js";
8
9
  import { startDurationMeasurement } from "../util/DurationMeasurement.js";
9
10
  import { runSafe } from "../util/runSafe.js";
10
11
  export async function executeStreamCall({ model, options, input, functionType, startStream, processDelta, processFinished, getResult, }) {
@@ -47,7 +48,10 @@ export async function executeStreamCall({ model, options, input, functionType, s
47
48
  run,
48
49
  parentCallId: startMetadata.callId,
49
50
  });
50
- return (async function* () {
51
+ // Return a queue that can be iterated over several times:
52
+ const responseQueue = new AsyncQueue();
53
+ // run async:
54
+ (async function () {
51
55
  for await (const event of deltaIterable) {
52
56
  if (event?.type === "error") {
53
57
  const error = event.error;
@@ -71,16 +75,17 @@ export async function executeStreamCall({ model, options, input, functionType, s
71
75
  if (event?.type === "delta") {
72
76
  const value = processDelta(event);
73
77
  if (value !== undefined) {
74
- yield value;
78
+ responseQueue.push(value);
75
79
  }
76
80
  }
77
81
  }
78
82
  if (processFinished != null) {
79
83
  const value = processFinished();
80
84
  if (value !== undefined) {
81
- yield value;
85
+ responseQueue.push(value);
82
86
  }
83
87
  }
88
+ responseQueue.close();
84
89
  const finishMetadata = {
85
90
  eventType: "finished",
86
91
  ...startMetadata,
@@ -95,6 +100,7 @@ export async function executeStreamCall({ model, options, input, functionType, s
95
100
  },
96
101
  });
97
102
  })();
103
+ return responseQueue;
98
104
  });
99
105
  if (!result.ok) {
100
106
  const finishMetadata = {
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.streamSpeech = void 0;
4
- const AsyncQueue_js_1 = require("../../event-source/AsyncQueue.cjs");
4
+ const AsyncQueue_js_1 = require("../../util/AsyncQueue.cjs");
5
5
  const AsyncIterableResultPromise_js_1 = require("../AsyncIterableResultPromise.cjs");
6
6
  const executeStreamCall_js_1 = require("../executeStreamCall.cjs");
7
7
  /**
@@ -1,4 +1,4 @@
1
- import { AsyncQueue } from "../../event-source/AsyncQueue.js";
1
+ import { AsyncQueue } from "../../util/AsyncQueue.js";
2
2
  import { AsyncIterableResultPromise } from "../AsyncIterableResultPromise.js";
3
3
  import { executeStreamCall } from "../executeStreamCall.js";
4
4
  /**
@@ -4,10 +4,10 @@ exports.AnthropicTextGenerationResponseFormat = exports.AnthropicTextGenerationM
4
4
  const zod_1 = require("zod");
5
5
  const callWithRetryAndThrottle_js_1 = require("../../core/api/callWithRetryAndThrottle.cjs");
6
6
  const postToApi_js_1 = require("../../core/api/postToApi.cjs");
7
- const AsyncQueue_js_1 = require("../../event-source/AsyncQueue.cjs");
8
7
  const parseEventSourceStream_js_1 = require("../../event-source/parseEventSourceStream.cjs");
9
8
  const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
10
9
  const PromptFormatTextStreamingModel_js_1 = require("../../model-function/generate-text/PromptFormatTextStreamingModel.cjs");
10
+ const AsyncQueue_js_1 = require("../../util/AsyncQueue.cjs");
11
11
  const parseJSON_js_1 = require("../../util/parseJSON.cjs");
12
12
  const AnthropicApiConfiguration_js_1 = require("./AnthropicApiConfiguration.cjs");
13
13
  const AnthropicError_js_1 = require("./AnthropicError.cjs");
@@ -1,10 +1,10 @@
1
1
  import { z } from "zod";
2
2
  import { callWithRetryAndThrottle } from "../../core/api/callWithRetryAndThrottle.js";
3
3
  import { createJsonResponseHandler, postJsonToApi, } from "../../core/api/postToApi.js";
4
- import { AsyncQueue } from "../../event-source/AsyncQueue.js";
5
4
  import { parseEventSourceStream } from "../../event-source/parseEventSourceStream.js";
6
5
  import { AbstractModel } from "../../model-function/AbstractModel.js";
7
6
  import { PromptFormatTextStreamingModel } from "../../model-function/generate-text/PromptFormatTextStreamingModel.js";
7
+ import { AsyncQueue } from "../../util/AsyncQueue.js";
8
8
  import { parseJsonWithZod } from "../../util/parseJSON.js";
9
9
  import { AnthropicApiConfiguration } from "./AnthropicApiConfiguration.js";
10
10
  import { failedAnthropicCallResponseHandler } from "./AnthropicError.js";
@@ -4,7 +4,7 @@ exports.CohereTextGenerationResponseFormat = exports.CohereTextGenerationModel =
4
4
  const zod_1 = require("zod");
5
5
  const callWithRetryAndThrottle_js_1 = require("../../core/api/callWithRetryAndThrottle.cjs");
6
6
  const postToApi_js_1 = require("../../core/api/postToApi.cjs");
7
- const AsyncQueue_js_1 = require("../../event-source/AsyncQueue.cjs");
7
+ const AsyncQueue_js_1 = require("../../util/AsyncQueue.cjs");
8
8
  const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
9
9
  const PromptFormatTextStreamingModel_js_1 = require("../../model-function/generate-text/PromptFormatTextStreamingModel.cjs");
10
10
  const TextPromptFormat_js_1 = require("../../model-function/generate-text/TextPromptFormat.cjs");
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { callWithRetryAndThrottle } from "../../core/api/callWithRetryAndThrottle.js";
3
3
  import { createJsonResponseHandler, postJsonToApi, } from "../../core/api/postToApi.js";
4
- import { AsyncQueue } from "../../event-source/AsyncQueue.js";
4
+ import { AsyncQueue } from "../../util/AsyncQueue.js";
5
5
  import { AbstractModel } from "../../model-function/AbstractModel.js";
6
6
  import { PromptFormatTextStreamingModel } from "../../model-function/generate-text/PromptFormatTextStreamingModel.js";
7
7
  import { mapChatPromptToTextFormat, mapInstructionPromptToTextFormat, } from "../../model-function/generate-text/TextPromptFormat.js";
@@ -4,7 +4,7 @@ exports.ElevenLabsSpeechModel = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const callWithRetryAndThrottle_js_1 = require("../../core/api/callWithRetryAndThrottle.cjs");
6
6
  const postToApi_js_1 = require("../../core/api/postToApi.cjs");
7
- const AsyncQueue_js_1 = require("../../event-source/AsyncQueue.cjs");
7
+ const AsyncQueue_js_1 = require("../../util/AsyncQueue.cjs");
8
8
  const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
9
9
  const SimpleWebSocket_js_1 = require("../../util/SimpleWebSocket.cjs");
10
10
  const parseJSON_js_1 = require("../../util/parseJSON.cjs");
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { callWithRetryAndThrottle } from "../../core/api/callWithRetryAndThrottle.js";
3
3
  import { createAudioMpegResponseHandler, postJsonToApi, } from "../../core/api/postToApi.js";
4
- import { AsyncQueue } from "../../event-source/AsyncQueue.js";
4
+ import { AsyncQueue } from "../../util/AsyncQueue.js";
5
5
  import { AbstractModel } from "../../model-function/AbstractModel.js";
6
6
  import { createSimpleWebSocket } from "../../util/SimpleWebSocket.js";
7
7
  import { safeParseJsonWithZod } from "../../util/parseJSON.js";
@@ -4,7 +4,7 @@ exports.LlamaCppTextGenerationResponseFormat = exports.LlamaCppTextGenerationMod
4
4
  const zod_1 = require("zod");
5
5
  const callWithRetryAndThrottle_js_1 = require("../../core/api/callWithRetryAndThrottle.cjs");
6
6
  const postToApi_js_1 = require("../../core/api/postToApi.cjs");
7
- const AsyncQueue_js_1 = require("../../event-source/AsyncQueue.cjs");
7
+ const AsyncQueue_js_1 = require("../../util/AsyncQueue.cjs");
8
8
  const parseEventSourceStream_js_1 = require("../../event-source/parseEventSourceStream.cjs");
9
9
  const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
10
10
  const PromptFormatTextStreamingModel_js_1 = require("../../model-function/generate-text/PromptFormatTextStreamingModel.cjs");
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { callWithRetryAndThrottle } from "../../core/api/callWithRetryAndThrottle.js";
3
3
  import { createJsonResponseHandler, postJsonToApi, } from "../../core/api/postToApi.js";
4
- import { AsyncQueue } from "../../event-source/AsyncQueue.js";
4
+ import { AsyncQueue } from "../../util/AsyncQueue.js";
5
5
  import { parseEventSourceStream } from "../../event-source/parseEventSourceStream.js";
6
6
  import { AbstractModel } from "../../model-function/AbstractModel.js";
7
7
  import { PromptFormatTextStreamingModel } from "../../model-function/generate-text/PromptFormatTextStreamingModel.js";
@@ -4,7 +4,7 @@ exports.OpenAITextResponseFormat = exports.OpenAICompletionModel = exports.calcu
4
4
  const zod_1 = require("zod");
5
5
  const callWithRetryAndThrottle_js_1 = require("../../core/api/callWithRetryAndThrottle.cjs");
6
6
  const postToApi_js_1 = require("../../core/api/postToApi.cjs");
7
- const AsyncQueue_js_1 = require("../../event-source/AsyncQueue.cjs");
7
+ const AsyncQueue_js_1 = require("../../util/AsyncQueue.cjs");
8
8
  const parseEventSourceStream_js_1 = require("../../event-source/parseEventSourceStream.cjs");
9
9
  const AbstractModel_js_1 = require("../../model-function/AbstractModel.cjs");
10
10
  const PromptFormatTextStreamingModel_js_1 = require("../../model-function/generate-text/PromptFormatTextStreamingModel.cjs");
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { callWithRetryAndThrottle } from "../../core/api/callWithRetryAndThrottle.js";
3
3
  import { createJsonResponseHandler, postJsonToApi, } from "../../core/api/postToApi.js";
4
- import { AsyncQueue } from "../../event-source/AsyncQueue.js";
4
+ import { AsyncQueue } from "../../util/AsyncQueue.js";
5
5
  import { parseEventSourceStream } from "../../event-source/parseEventSourceStream.js";
6
6
  import { AbstractModel } from "../../model-function/AbstractModel.js";
7
7
  import { PromptFormatTextStreamingModel } from "../../model-function/generate-text/PromptFormatTextStreamingModel.js";
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createOpenAIChatDeltaIterableQueue = void 0;
4
4
  const zod_1 = require("zod");
5
- const AsyncQueue_js_1 = require("../../../event-source/AsyncQueue.cjs");
5
+ const AsyncQueue_js_1 = require("../../../util/AsyncQueue.cjs");
6
6
  const parseEventSourceStream_js_1 = require("../../../event-source/parseEventSourceStream.cjs");
7
7
  const parseJSON_js_1 = require("../../../util/parseJSON.cjs");
8
8
  const chatResponseStreamEventSchema = zod_1.z.object({
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { AsyncQueue } from "../../../event-source/AsyncQueue.js";
2
+ import { AsyncQueue } from "../../../util/AsyncQueue.js";
3
3
  import { parseEventSourceStream } from "../../../event-source/parseEventSourceStream.js";
4
4
  import { safeParseJsonWithZod } from "../../../util/parseJSON.js";
5
5
  const chatResponseStreamEventSchema = z.object({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modelfusion",
3
3
  "description": "Build multimodal applications, chatbots, and agents with JavaScript and TypeScript.",
4
- "version": "0.51.0",
4
+ "version": "0.53.0",
5
5
  "author": "Lars Grammel",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -48,7 +48,7 @@
48
48
  "build:esm": "tsc --outDir dist/",
49
49
  "build:cjs": "tsc --outDir build/cjs/ -p tsconfig.cjs.json && node bin/prepare-cjs.js",
50
50
  "test": "vitest run src",
51
- "test-interactive": "vitest run",
51
+ "test-interactive": "vitest watch",
52
52
  "dist": "npm run clean && npm run lint && npm run test && npm run build && npm run dist:copy-files",
53
53
  "dist:copy-files": "copyfiles package.json README.md LICENSE dist"
54
54
  },
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AsyncQueue = void 0;
4
+ /**
5
+ * `AsyncQueue` is a class that represents an asynchronous queue.
6
+ * It allows values to be pushed onto it and consumed (pulled) by an iterator.
7
+ * The queue is async-iterable, making it compatible with async/await syntax.
8
+ *
9
+ * @template T The type of elements contained in the queue.
10
+ * @example
11
+ * const queue = new AsyncQueue<number>();
12
+ * queue.push(1);
13
+ * (async () => {
14
+ * for await (const value of queue) {
15
+ * console.log(value);
16
+ * }
17
+ * })();
18
+ */
19
+ class AsyncQueue {
20
+ constructor() {
21
+ Object.defineProperty(this, "values", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: []
26
+ });
27
+ Object.defineProperty(this, "pendingResolvers", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: []
32
+ });
33
+ Object.defineProperty(this, "closed", {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: false
38
+ });
39
+ }
40
+ /**
41
+ * Pushes an element onto the queue. If the queue is closed, an error is thrown.
42
+ *
43
+ * @param {T} value - The element to add to the queue.
44
+ * @throws {Error} Throws an error if the queue is closed.
45
+ * @example
46
+ * queue.push(2);
47
+ */
48
+ push(value) {
49
+ if (this.closed) {
50
+ throw new Error("Cannot push value to closed queue. The queue has been closed and is no longer accepting new items.");
51
+ }
52
+ this.values.push(value);
53
+ while (this.pendingResolvers.length > 0) {
54
+ this.pendingResolvers.shift()?.();
55
+ }
56
+ }
57
+ /**
58
+ * Closes the queue, preventing more elements from being pushed onto it.
59
+ *
60
+ * @example
61
+ * queue.close();
62
+ */
63
+ close() {
64
+ this.closed = true;
65
+ while (this.pendingResolvers.length > 0) {
66
+ this.pendingResolvers.shift()?.();
67
+ }
68
+ }
69
+ /**
70
+ * Creates and returns an async iterator that allows the queue to be consumed.
71
+ * You can create multiple iterators for the same queue.
72
+ *
73
+ * @returns {AsyncIterator<T>} An async iterator for the queue.
74
+ * @example
75
+ * (async () => {
76
+ * for await (const value of queue) {
77
+ * console.log(value);
78
+ * }
79
+ * })();
80
+ */
81
+ [Symbol.asyncIterator]() {
82
+ let position = 0;
83
+ return {
84
+ next: () => new Promise((resolve) => {
85
+ const attemptResolve = () => {
86
+ if (position < this.values.length) {
87
+ // There's an available value, resolve it immediately.
88
+ resolve({ value: this.values[position++], done: false });
89
+ }
90
+ else if (this.closed) {
91
+ // The queue is closed, and there are no more values. Complete the iteration.
92
+ resolve({ value: undefined, done: true }); // eslint-disable-line @typescript-eslint/no-explicit-any
93
+ }
94
+ else {
95
+ // No values are currently available, and the queue is not closed.
96
+ // The consumer is now pending and will be resolved when a new value is pushed
97
+ // or when the queue is closed.
98
+ this.pendingResolvers.push(attemptResolve);
99
+ }
100
+ };
101
+ attemptResolve();
102
+ }),
103
+ };
104
+ }
105
+ }
106
+ exports.AsyncQueue = AsyncQueue;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * `AsyncQueue` is a class that represents an asynchronous queue.
3
+ * It allows values to be pushed onto it and consumed (pulled) by an iterator.
4
+ * The queue is async-iterable, making it compatible with async/await syntax.
5
+ *
6
+ * @template T The type of elements contained in the queue.
7
+ * @example
8
+ * const queue = new AsyncQueue<number>();
9
+ * queue.push(1);
10
+ * (async () => {
11
+ * for await (const value of queue) {
12
+ * console.log(value);
13
+ * }
14
+ * })();
15
+ */
16
+ export declare class AsyncQueue<T> implements AsyncIterable<T> {
17
+ private values;
18
+ private pendingResolvers;
19
+ private closed;
20
+ /**
21
+ * Pushes an element onto the queue. If the queue is closed, an error is thrown.
22
+ *
23
+ * @param {T} value - The element to add to the queue.
24
+ * @throws {Error} Throws an error if the queue is closed.
25
+ * @example
26
+ * queue.push(2);
27
+ */
28
+ push(value: T): void;
29
+ /**
30
+ * Closes the queue, preventing more elements from being pushed onto it.
31
+ *
32
+ * @example
33
+ * queue.close();
34
+ */
35
+ close(): void;
36
+ /**
37
+ * Creates and returns an async iterator that allows the queue to be consumed.
38
+ * You can create multiple iterators for the same queue.
39
+ *
40
+ * @returns {AsyncIterator<T>} An async iterator for the queue.
41
+ * @example
42
+ * (async () => {
43
+ * for await (const value of queue) {
44
+ * console.log(value);
45
+ * }
46
+ * })();
47
+ */
48
+ [Symbol.asyncIterator](): AsyncIterator<T>;
49
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * `AsyncQueue` is a class that represents an asynchronous queue.
3
+ * It allows values to be pushed onto it and consumed (pulled) by an iterator.
4
+ * The queue is async-iterable, making it compatible with async/await syntax.
5
+ *
6
+ * @template T The type of elements contained in the queue.
7
+ * @example
8
+ * const queue = new AsyncQueue<number>();
9
+ * queue.push(1);
10
+ * (async () => {
11
+ * for await (const value of queue) {
12
+ * console.log(value);
13
+ * }
14
+ * })();
15
+ */
16
+ export class AsyncQueue {
17
+ constructor() {
18
+ Object.defineProperty(this, "values", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: []
23
+ });
24
+ Object.defineProperty(this, "pendingResolvers", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: []
29
+ });
30
+ Object.defineProperty(this, "closed", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: false
35
+ });
36
+ }
37
+ /**
38
+ * Pushes an element onto the queue. If the queue is closed, an error is thrown.
39
+ *
40
+ * @param {T} value - The element to add to the queue.
41
+ * @throws {Error} Throws an error if the queue is closed.
42
+ * @example
43
+ * queue.push(2);
44
+ */
45
+ push(value) {
46
+ if (this.closed) {
47
+ throw new Error("Cannot push value to closed queue. The queue has been closed and is no longer accepting new items.");
48
+ }
49
+ this.values.push(value);
50
+ while (this.pendingResolvers.length > 0) {
51
+ this.pendingResolvers.shift()?.();
52
+ }
53
+ }
54
+ /**
55
+ * Closes the queue, preventing more elements from being pushed onto it.
56
+ *
57
+ * @example
58
+ * queue.close();
59
+ */
60
+ close() {
61
+ this.closed = true;
62
+ while (this.pendingResolvers.length > 0) {
63
+ this.pendingResolvers.shift()?.();
64
+ }
65
+ }
66
+ /**
67
+ * Creates and returns an async iterator that allows the queue to be consumed.
68
+ * You can create multiple iterators for the same queue.
69
+ *
70
+ * @returns {AsyncIterator<T>} An async iterator for the queue.
71
+ * @example
72
+ * (async () => {
73
+ * for await (const value of queue) {
74
+ * console.log(value);
75
+ * }
76
+ * })();
77
+ */
78
+ [Symbol.asyncIterator]() {
79
+ let position = 0;
80
+ return {
81
+ next: () => new Promise((resolve) => {
82
+ const attemptResolve = () => {
83
+ if (position < this.values.length) {
84
+ // There's an available value, resolve it immediately.
85
+ resolve({ value: this.values[position++], done: false });
86
+ }
87
+ else if (this.closed) {
88
+ // The queue is closed, and there are no more values. Complete the iteration.
89
+ resolve({ value: undefined, done: true }); // eslint-disable-line @typescript-eslint/no-explicit-any
90
+ }
91
+ else {
92
+ // No values are currently available, and the queue is not closed.
93
+ // The consumer is now pending and will be resolved when a new value is pushed
94
+ // or when the queue is closed.
95
+ this.pendingResolvers.push(attemptResolve);
96
+ }
97
+ };
98
+ attemptResolve();
99
+ }),
100
+ };
101
+ }
102
+ }
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const delay_js_1 = require("./delay.cjs");
5
+ const AsyncQueue_js_1 = require("./AsyncQueue.cjs");
6
+ (0, vitest_1.test)("receive values in order for single iterator created before pushing", async () => {
7
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
8
+ const receivedValues = [];
9
+ const receiveValuesPromise = (async () => {
10
+ for await (const value of asyncQueue) {
11
+ receivedValues.push(value);
12
+ }
13
+ })();
14
+ asyncQueue.push(1);
15
+ asyncQueue.push(2);
16
+ asyncQueue.push(3);
17
+ asyncQueue.close();
18
+ await receiveValuesPromise;
19
+ (0, vitest_1.expect)(receivedValues).toEqual([1, 2, 3]);
20
+ });
21
+ (0, vitest_1.test)("receive values in order for single iterator created after closing", async () => {
22
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
23
+ asyncQueue.push(1);
24
+ asyncQueue.push(2);
25
+ asyncQueue.push(3);
26
+ asyncQueue.close();
27
+ const receivedValues = [];
28
+ const receiveValuesPromise = (async () => {
29
+ for await (const value of asyncQueue) {
30
+ receivedValues.push(value);
31
+ }
32
+ })();
33
+ await receiveValuesPromise;
34
+ (0, vitest_1.expect)(receivedValues).toEqual([1, 2, 3]);
35
+ });
36
+ (0, vitest_1.test)("handle delayed pushing", async () => {
37
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
38
+ setTimeout(() => {
39
+ asyncQueue.push(1);
40
+ asyncQueue.push(2);
41
+ asyncQueue.close();
42
+ }, 5);
43
+ const receivedValues = [];
44
+ for await (const value of asyncQueue) {
45
+ receivedValues.push(value);
46
+ }
47
+ (0, vitest_1.expect)(receivedValues).toEqual([1, 2]);
48
+ });
49
+ (0, vitest_1.test)("error handling in consumer", async () => {
50
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
51
+ asyncQueue.push(1);
52
+ await (0, vitest_1.expect)((async () => {
53
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
54
+ for await (const _value of asyncQueue) {
55
+ throw new Error("Consumer error");
56
+ }
57
+ })()).rejects.toThrow("Consumer error");
58
+ // Check the queue is still operational after an error in the consumer
59
+ asyncQueue.push(2);
60
+ asyncQueue.close();
61
+ const receivedValues = [];
62
+ for await (const value of asyncQueue) {
63
+ receivedValues.push(value);
64
+ }
65
+ (0, vitest_1.expect)(receivedValues).toEqual([1, 2]);
66
+ });
67
+ (0, vitest_1.test)("behavior on empty queue closing", async () => {
68
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
69
+ asyncQueue.close();
70
+ const receivedValues = [];
71
+ for await (const value of asyncQueue) {
72
+ receivedValues.push(value);
73
+ }
74
+ (0, vitest_1.expect)(receivedValues).toEqual([]);
75
+ });
76
+ (0, vitest_1.test)("multiple closings", async () => {
77
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
78
+ asyncQueue.close();
79
+ (0, vitest_1.expect)(() => asyncQueue.close()).not.toThrow();
80
+ });
81
+ (0, vitest_1.test)("receive all values in multiple independent consumers", async () => {
82
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
83
+ const consumerPromises = [1, 2].map(async () => {
84
+ const receivedValues = [];
85
+ for await (const value of asyncQueue) {
86
+ receivedValues.push(value);
87
+ }
88
+ return receivedValues;
89
+ });
90
+ await (0, delay_js_1.delay)(5);
91
+ asyncQueue.push(1);
92
+ await (0, delay_js_1.delay)(5);
93
+ asyncQueue.push(2);
94
+ await (0, delay_js_1.delay)(5);
95
+ asyncQueue.push(3);
96
+ await (0, delay_js_1.delay)(5);
97
+ asyncQueue.close();
98
+ const allReceivedValues = await Promise.all(consumerPromises);
99
+ allReceivedValues.forEach((receivedValues) => {
100
+ (0, vitest_1.expect)(receivedValues).toEqual([1, 2, 3]);
101
+ });
102
+ });
103
+ (0, vitest_1.test)("each consumer receives all pushed values under varying conditions", async () => {
104
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
105
+ // Start the first consumer, which will await values.
106
+ const receivedValues1 = [];
107
+ const consumer1 = (async () => {
108
+ for await (const value of asyncQueue) {
109
+ receivedValues1.push(value);
110
+ }
111
+ })();
112
+ // Simulate some operation delay, then push the first value.
113
+ await (0, delay_js_1.delay)(5); // Delay is necessary to simulate real-world async operations.
114
+ asyncQueue.push(1);
115
+ // Start the second consumer after the first value was pushed.
116
+ const receivedValues2 = [];
117
+ const consumer2 = (async () => {
118
+ for await (const value of asyncQueue) {
119
+ receivedValues2.push(value);
120
+ }
121
+ })();
122
+ // Push the remaining values with some delays.
123
+ await (0, delay_js_1.delay)(5);
124
+ asyncQueue.push(2);
125
+ asyncQueue.push(3);
126
+ // Close the queue and wait for consumers to finish processing.
127
+ await (0, delay_js_1.delay)(5);
128
+ asyncQueue.close();
129
+ await Promise.all([consumer1, consumer2]);
130
+ // Both consumers should have received all values, even if they started at different times.
131
+ (0, vitest_1.expect)(receivedValues1).toEqual([1, 2, 3]);
132
+ (0, vitest_1.expect)(receivedValues2).toEqual([1, 2, 3]); // This will likely fail because consumer2 started late.
133
+ });
134
+ (0, vitest_1.test)("throw error when pushing to a closed queue", async () => {
135
+ const asyncQueue = new AsyncQueue_js_1.AsyncQueue();
136
+ asyncQueue.close();
137
+ (0, vitest_1.expect)(() => asyncQueue.push(1)).toThrowError("Cannot push value to closed queue. The queue has been closed and is no longer accepting new items.");
138
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,136 @@
1
+ import { expect, test } from "vitest";
2
+ import { delay } from "./delay.js";
3
+ import { AsyncQueue } from "./AsyncQueue.js";
4
+ test("receive values in order for single iterator created before pushing", async () => {
5
+ const asyncQueue = new AsyncQueue();
6
+ const receivedValues = [];
7
+ const receiveValuesPromise = (async () => {
8
+ for await (const value of asyncQueue) {
9
+ receivedValues.push(value);
10
+ }
11
+ })();
12
+ asyncQueue.push(1);
13
+ asyncQueue.push(2);
14
+ asyncQueue.push(3);
15
+ asyncQueue.close();
16
+ await receiveValuesPromise;
17
+ expect(receivedValues).toEqual([1, 2, 3]);
18
+ });
19
+ test("receive values in order for single iterator created after closing", async () => {
20
+ const asyncQueue = new AsyncQueue();
21
+ asyncQueue.push(1);
22
+ asyncQueue.push(2);
23
+ asyncQueue.push(3);
24
+ asyncQueue.close();
25
+ const receivedValues = [];
26
+ const receiveValuesPromise = (async () => {
27
+ for await (const value of asyncQueue) {
28
+ receivedValues.push(value);
29
+ }
30
+ })();
31
+ await receiveValuesPromise;
32
+ expect(receivedValues).toEqual([1, 2, 3]);
33
+ });
34
+ test("handle delayed pushing", async () => {
35
+ const asyncQueue = new AsyncQueue();
36
+ setTimeout(() => {
37
+ asyncQueue.push(1);
38
+ asyncQueue.push(2);
39
+ asyncQueue.close();
40
+ }, 5);
41
+ const receivedValues = [];
42
+ for await (const value of asyncQueue) {
43
+ receivedValues.push(value);
44
+ }
45
+ expect(receivedValues).toEqual([1, 2]);
46
+ });
47
+ test("error handling in consumer", async () => {
48
+ const asyncQueue = new AsyncQueue();
49
+ asyncQueue.push(1);
50
+ await expect((async () => {
51
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
52
+ for await (const _value of asyncQueue) {
53
+ throw new Error("Consumer error");
54
+ }
55
+ })()).rejects.toThrow("Consumer error");
56
+ // Check the queue is still operational after an error in the consumer
57
+ asyncQueue.push(2);
58
+ asyncQueue.close();
59
+ const receivedValues = [];
60
+ for await (const value of asyncQueue) {
61
+ receivedValues.push(value);
62
+ }
63
+ expect(receivedValues).toEqual([1, 2]);
64
+ });
65
+ test("behavior on empty queue closing", async () => {
66
+ const asyncQueue = new AsyncQueue();
67
+ asyncQueue.close();
68
+ const receivedValues = [];
69
+ for await (const value of asyncQueue) {
70
+ receivedValues.push(value);
71
+ }
72
+ expect(receivedValues).toEqual([]);
73
+ });
74
+ test("multiple closings", async () => {
75
+ const asyncQueue = new AsyncQueue();
76
+ asyncQueue.close();
77
+ expect(() => asyncQueue.close()).not.toThrow();
78
+ });
79
+ test("receive all values in multiple independent consumers", async () => {
80
+ const asyncQueue = new AsyncQueue();
81
+ const consumerPromises = [1, 2].map(async () => {
82
+ const receivedValues = [];
83
+ for await (const value of asyncQueue) {
84
+ receivedValues.push(value);
85
+ }
86
+ return receivedValues;
87
+ });
88
+ await delay(5);
89
+ asyncQueue.push(1);
90
+ await delay(5);
91
+ asyncQueue.push(2);
92
+ await delay(5);
93
+ asyncQueue.push(3);
94
+ await delay(5);
95
+ asyncQueue.close();
96
+ const allReceivedValues = await Promise.all(consumerPromises);
97
+ allReceivedValues.forEach((receivedValues) => {
98
+ expect(receivedValues).toEqual([1, 2, 3]);
99
+ });
100
+ });
101
+ test("each consumer receives all pushed values under varying conditions", async () => {
102
+ const asyncQueue = new AsyncQueue();
103
+ // Start the first consumer, which will await values.
104
+ const receivedValues1 = [];
105
+ const consumer1 = (async () => {
106
+ for await (const value of asyncQueue) {
107
+ receivedValues1.push(value);
108
+ }
109
+ })();
110
+ // Simulate some operation delay, then push the first value.
111
+ await delay(5); // Delay is necessary to simulate real-world async operations.
112
+ asyncQueue.push(1);
113
+ // Start the second consumer after the first value was pushed.
114
+ const receivedValues2 = [];
115
+ const consumer2 = (async () => {
116
+ for await (const value of asyncQueue) {
117
+ receivedValues2.push(value);
118
+ }
119
+ })();
120
+ // Push the remaining values with some delays.
121
+ await delay(5);
122
+ asyncQueue.push(2);
123
+ asyncQueue.push(3);
124
+ // Close the queue and wait for consumers to finish processing.
125
+ await delay(5);
126
+ asyncQueue.close();
127
+ await Promise.all([consumer1, consumer2]);
128
+ // Both consumers should have received all values, even if they started at different times.
129
+ expect(receivedValues1).toEqual([1, 2, 3]);
130
+ expect(receivedValues2).toEqual([1, 2, 3]); // This will likely fail because consumer2 started late.
131
+ });
132
+ test("throw error when pushing to a closed queue", async () => {
133
+ const asyncQueue = new AsyncQueue();
134
+ asyncQueue.close();
135
+ expect(() => asyncQueue.push(1)).toThrowError("Cannot push value to closed queue. The queue has been closed and is no longer accepting new items.");
136
+ });
package/util/delay.cjs ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.delay = void 0;
4
+ async function delay(ms) {
5
+ return new Promise((resolve) => setTimeout(resolve, ms));
6
+ }
7
+ exports.delay = delay;
@@ -0,0 +1 @@
1
+ export declare function delay(ms: number): Promise<void>;
package/util/delay.js ADDED
@@ -0,0 +1,3 @@
1
+ export async function delay(ms) {
2
+ return new Promise((resolve) => setTimeout(resolve, ms));
3
+ }
package/util/index.cjs CHANGED
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./AsyncQueue.cjs"), exports);
17
18
  __exportStar(require("./JSONParseError.cjs"), exports);
18
19
  __exportStar(require("./cosineSimilarity.cjs"), exports);
19
20
  __exportStar(require("./getAudioFileExtension.cjs"), exports);
package/util/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./AsyncQueue.js";
1
2
  export * from "./JSONParseError.js";
2
3
  export * from "./cosineSimilarity.js";
3
4
  export * from "./getAudioFileExtension.js";
package/util/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./AsyncQueue.js";
1
2
  export * from "./JSONParseError.js";
2
3
  export * from "./cosineSimilarity.js";
3
4
  export * from "./getAudioFileExtension.js";
@@ -1,67 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AsyncQueue = void 0;
4
- class AsyncQueue {
5
- constructor() {
6
- Object.defineProperty(this, "queue", {
7
- enumerable: true,
8
- configurable: true,
9
- writable: true,
10
- value: []
11
- });
12
- Object.defineProperty(this, "resolvers", {
13
- enumerable: true,
14
- configurable: true,
15
- writable: true,
16
- value: []
17
- });
18
- Object.defineProperty(this, "closed", {
19
- enumerable: true,
20
- configurable: true,
21
- writable: true,
22
- value: false
23
- });
24
- }
25
- push(value) {
26
- if (this.closed) {
27
- throw new Error("Pushing to a closed queue");
28
- }
29
- const resolve = this.resolvers.shift();
30
- if (resolve) {
31
- resolve({ value, done: false });
32
- }
33
- else {
34
- this.queue.push(value);
35
- }
36
- }
37
- close() {
38
- while (this.resolvers.length) {
39
- const resolve = this.resolvers.shift();
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- resolve?.({ value: undefined, done: true });
42
- }
43
- this.closed = true;
44
- }
45
- [Symbol.asyncIterator]() {
46
- return {
47
- next: () => {
48
- if (this.queue.length > 0) {
49
- return Promise.resolve({
50
- value: this.queue.shift(),
51
- done: false,
52
- });
53
- }
54
- else if (this.closed) {
55
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
- return Promise.resolve({ value: undefined, done: true });
57
- }
58
- else {
59
- return new Promise((resolve) => {
60
- this.resolvers.push(resolve);
61
- });
62
- }
63
- },
64
- };
65
- }
66
- }
67
- exports.AsyncQueue = AsyncQueue;
@@ -1,8 +0,0 @@
1
- export declare class AsyncQueue<T> implements AsyncIterable<T> {
2
- private queue;
3
- private resolvers;
4
- private closed;
5
- push(value: T): void;
6
- close(): void;
7
- [Symbol.asyncIterator](): AsyncIterator<T>;
8
- }
@@ -1,63 +0,0 @@
1
- export class AsyncQueue {
2
- constructor() {
3
- Object.defineProperty(this, "queue", {
4
- enumerable: true,
5
- configurable: true,
6
- writable: true,
7
- value: []
8
- });
9
- Object.defineProperty(this, "resolvers", {
10
- enumerable: true,
11
- configurable: true,
12
- writable: true,
13
- value: []
14
- });
15
- Object.defineProperty(this, "closed", {
16
- enumerable: true,
17
- configurable: true,
18
- writable: true,
19
- value: false
20
- });
21
- }
22
- push(value) {
23
- if (this.closed) {
24
- throw new Error("Pushing to a closed queue");
25
- }
26
- const resolve = this.resolvers.shift();
27
- if (resolve) {
28
- resolve({ value, done: false });
29
- }
30
- else {
31
- this.queue.push(value);
32
- }
33
- }
34
- close() {
35
- while (this.resolvers.length) {
36
- const resolve = this.resolvers.shift();
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- resolve?.({ value: undefined, done: true });
39
- }
40
- this.closed = true;
41
- }
42
- [Symbol.asyncIterator]() {
43
- return {
44
- next: () => {
45
- if (this.queue.length > 0) {
46
- return Promise.resolve({
47
- value: this.queue.shift(),
48
- done: false,
49
- });
50
- }
51
- else if (this.closed) {
52
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
- return Promise.resolve({ value: undefined, done: true });
54
- }
55
- else {
56
- return new Promise((resolve) => {
57
- this.resolvers.push(resolve);
58
- });
59
- }
60
- },
61
- };
62
- }
63
- }