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.
- package/README.md +2 -10
- package/core/ExecuteFunctionEvent.cjs +2 -0
- package/core/ExecuteFunctionEvent.d.ts +7 -0
- package/core/ExecuteFunctionEvent.js +1 -0
- package/core/FunctionEvent.d.ts +2 -1
- package/core/api/loadApiKey.cjs +2 -2
- package/core/api/loadApiKey.js +2 -2
- package/core/executeFunction.cjs +19 -0
- package/core/executeFunction.d.ts +2 -0
- package/core/executeFunction.js +15 -0
- package/core/index.cjs +2 -0
- package/core/index.d.ts +2 -0
- package/core/index.js +2 -0
- package/event-source/index.cjs +0 -1
- package/event-source/index.d.ts +0 -1
- package/event-source/index.js +0 -1
- package/event-source/readEventSourceStream.cjs +1 -1
- package/event-source/readEventSourceStream.js +1 -1
- package/model-function/executeStreamCall.cjs +9 -3
- package/model-function/executeStreamCall.js +9 -3
- package/model-function/generate-speech/streamSpeech.cjs +1 -1
- package/model-function/generate-speech/streamSpeech.js +1 -1
- package/model-provider/anthropic/AnthropicTextGenerationModel.cjs +1 -1
- package/model-provider/anthropic/AnthropicTextGenerationModel.js +1 -1
- package/model-provider/cohere/CohereTextGenerationModel.cjs +1 -1
- package/model-provider/cohere/CohereTextGenerationModel.js +1 -1
- package/model-provider/elevenlabs/ElevenLabsSpeechModel.cjs +1 -1
- package/model-provider/elevenlabs/ElevenLabsSpeechModel.js +1 -1
- package/model-provider/llamacpp/LlamaCppTextGenerationModel.cjs +1 -1
- package/model-provider/llamacpp/LlamaCppTextGenerationModel.js +1 -1
- package/model-provider/openai/OpenAICompletionModel.cjs +1 -1
- package/model-provider/openai/OpenAICompletionModel.js +1 -1
- package/model-provider/openai/chat/OpenAIChatStreamIterable.cjs +1 -1
- package/model-provider/openai/chat/OpenAIChatStreamIterable.js +1 -1
- package/package.json +2 -2
- package/util/AsyncQueue.cjs +106 -0
- package/util/AsyncQueue.d.ts +49 -0
- package/util/AsyncQueue.js +102 -0
- package/util/AsyncQueue.test.cjs +138 -0
- package/util/AsyncQueue.test.d.ts +1 -0
- package/util/AsyncQueue.test.js +136 -0
- package/util/delay.cjs +7 -0
- package/util/delay.d.ts +1 -0
- package/util/delay.js +3 -0
- package/util/index.cjs +1 -0
- package/util/index.d.ts +1 -0
- package/util/index.js +1 -0
- package/event-source/AsyncQueue.cjs +0 -67
- package/event-source/AsyncQueue.d.ts +0 -8
- 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
|
69
|
-
process.stdout.write(
|
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,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 {};
|
package/core/FunctionEvent.d.ts
CHANGED
@@ -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;
|
package/core/api/loadApiKey.cjs
CHANGED
@@ -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
|
}
|
package/core/api/loadApiKey.js
CHANGED
@@ -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,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";
|
package/event-source/index.cjs
CHANGED
@@ -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);
|
package/event-source/index.d.ts
CHANGED
package/event-source/index.js
CHANGED
@@ -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("
|
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 "
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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("../../
|
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
|
/**
|
@@ -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("../../
|
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 "../../
|
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("../../
|
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 "../../
|
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("../../
|
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 "../../
|
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("../../
|
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 "../../
|
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("../../../
|
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 "../../../
|
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.
|
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
|
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
package/util/delay.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export declare function delay(ms: number): Promise<void>;
|
package/util/delay.js
ADDED
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
package/util/index.js
CHANGED
@@ -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,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
|
-
}
|