ai 6.0.33 → 6.0.35
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/CHANGELOG.md +16 -0
- package/dist/index.d.mts +50 -21
- package/dist/index.d.ts +50 -21
- package/dist/index.js +348 -286
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +280 -219
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/internal/index.mjs +1 -1
- package/docs/02-foundations/03-prompts.mdx +2 -2
- package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/28-output.mdx +1 -1
- package/docs/07-reference/05-ai-sdk-errors/ai-ui-message-stream-error.mdx +67 -0
- package/package.json +6 -4
- package/src/agent/agent.ts +116 -0
- package/src/agent/create-agent-ui-stream-response.test.ts +258 -0
- package/src/agent/create-agent-ui-stream-response.ts +50 -0
- package/src/agent/create-agent-ui-stream.ts +73 -0
- package/src/agent/index.ts +33 -0
- package/src/agent/infer-agent-tools.ts +7 -0
- package/src/agent/infer-agent-ui-message.test-d.ts +54 -0
- package/src/agent/infer-agent-ui-message.ts +11 -0
- package/src/agent/pipe-agent-ui-stream-to-response.ts +52 -0
- package/src/agent/tool-loop-agent-on-finish-callback.ts +31 -0
- package/src/agent/tool-loop-agent-on-step-finish-callback.ts +11 -0
- package/src/agent/tool-loop-agent-settings.ts +182 -0
- package/src/agent/tool-loop-agent.test-d.ts +114 -0
- package/src/agent/tool-loop-agent.test.ts +442 -0
- package/src/agent/tool-loop-agent.ts +114 -0
- package/src/embed/__snapshots__/embed-many.test.ts.snap +191 -0
- package/src/embed/__snapshots__/embed.test.ts.snap +81 -0
- package/src/embed/embed-many-result.ts +53 -0
- package/src/embed/embed-many.test.ts +653 -0
- package/src/embed/embed-many.ts +378 -0
- package/src/embed/embed-result.ts +50 -0
- package/src/embed/embed.test.ts +298 -0
- package/src/embed/embed.ts +211 -0
- package/src/embed/index.ts +4 -0
- package/src/error/index.ts +35 -0
- package/src/error/invalid-argument-error.ts +34 -0
- package/src/error/invalid-stream-part-error.ts +28 -0
- package/src/error/invalid-tool-approval-error.ts +26 -0
- package/src/error/invalid-tool-input-error.ts +33 -0
- package/src/error/no-image-generated-error.ts +39 -0
- package/src/error/no-object-generated-error.ts +70 -0
- package/src/error/no-output-generated-error.ts +26 -0
- package/src/error/no-speech-generated-error.ts +18 -0
- package/src/error/no-such-tool-error.ts +35 -0
- package/src/error/no-transcript-generated-error.ts +20 -0
- package/src/error/tool-call-not-found-for-approval-error.ts +32 -0
- package/src/error/tool-call-repair-error.ts +30 -0
- package/src/error/ui-message-stream-error.ts +48 -0
- package/src/error/unsupported-model-version-error.ts +23 -0
- package/src/error/verify-no-object-generated-error.ts +27 -0
- package/src/generate-image/generate-image-result.ts +42 -0
- package/src/generate-image/generate-image.test.ts +1420 -0
- package/src/generate-image/generate-image.ts +360 -0
- package/src/generate-image/index.ts +18 -0
- package/src/generate-object/__snapshots__/generate-object.test.ts.snap +133 -0
- package/src/generate-object/__snapshots__/stream-object.test.ts.snap +297 -0
- package/src/generate-object/generate-object-result.ts +67 -0
- package/src/generate-object/generate-object.test-d.ts +49 -0
- package/src/generate-object/generate-object.test.ts +1191 -0
- package/src/generate-object/generate-object.ts +518 -0
- package/src/generate-object/index.ts +9 -0
- package/src/generate-object/inject-json-instruction.test.ts +181 -0
- package/src/generate-object/inject-json-instruction.ts +30 -0
- package/src/generate-object/output-strategy.ts +415 -0
- package/src/generate-object/parse-and-validate-object-result.ts +111 -0
- package/src/generate-object/repair-text.ts +12 -0
- package/src/generate-object/stream-object-result.ts +120 -0
- package/src/generate-object/stream-object.test-d.ts +74 -0
- package/src/generate-object/stream-object.test.ts +1950 -0
- package/src/generate-object/stream-object.ts +986 -0
- package/src/generate-object/validate-object-generation-input.ts +144 -0
- package/src/generate-speech/generate-speech-result.ts +30 -0
- package/src/generate-speech/generate-speech.test.ts +300 -0
- package/src/generate-speech/generate-speech.ts +190 -0
- package/src/generate-speech/generated-audio-file.ts +65 -0
- package/src/generate-speech/index.ts +3 -0
- package/src/generate-text/__snapshots__/generate-text.test.ts.snap +1872 -0
- package/src/generate-text/__snapshots__/stream-text.test.ts.snap +1255 -0
- package/src/generate-text/collect-tool-approvals.test.ts +553 -0
- package/src/generate-text/collect-tool-approvals.ts +116 -0
- package/src/generate-text/content-part.ts +25 -0
- package/src/generate-text/execute-tool-call.ts +129 -0
- package/src/generate-text/extract-reasoning-content.ts +17 -0
- package/src/generate-text/extract-text-content.ts +15 -0
- package/src/generate-text/generate-text-result.ts +168 -0
- package/src/generate-text/generate-text.test-d.ts +68 -0
- package/src/generate-text/generate-text.test.ts +7011 -0
- package/src/generate-text/generate-text.ts +1223 -0
- package/src/generate-text/generated-file.ts +70 -0
- package/src/generate-text/index.ts +57 -0
- package/src/generate-text/is-approval-needed.ts +29 -0
- package/src/generate-text/output-utils.ts +23 -0
- package/src/generate-text/output.test.ts +698 -0
- package/src/generate-text/output.ts +590 -0
- package/src/generate-text/parse-tool-call.test.ts +570 -0
- package/src/generate-text/parse-tool-call.ts +188 -0
- package/src/generate-text/prepare-step.ts +103 -0
- package/src/generate-text/prune-messages.test.ts +720 -0
- package/src/generate-text/prune-messages.ts +167 -0
- package/src/generate-text/reasoning-output.ts +20 -0
- package/src/generate-text/reasoning.ts +8 -0
- package/src/generate-text/response-message.ts +10 -0
- package/src/generate-text/run-tools-transformation.test.ts +1143 -0
- package/src/generate-text/run-tools-transformation.ts +420 -0
- package/src/generate-text/smooth-stream.test.ts +2101 -0
- package/src/generate-text/smooth-stream.ts +162 -0
- package/src/generate-text/step-result.ts +238 -0
- package/src/generate-text/stop-condition.ts +29 -0
- package/src/generate-text/stream-text-result.ts +463 -0
- package/src/generate-text/stream-text.test-d.ts +200 -0
- package/src/generate-text/stream-text.test.ts +19979 -0
- package/src/generate-text/stream-text.ts +2505 -0
- package/src/generate-text/to-response-messages.test.ts +922 -0
- package/src/generate-text/to-response-messages.ts +163 -0
- package/src/generate-text/tool-approval-request-output.ts +21 -0
- package/src/generate-text/tool-call-repair-function.ts +27 -0
- package/src/generate-text/tool-call.ts +47 -0
- package/src/generate-text/tool-error.ts +34 -0
- package/src/generate-text/tool-output-denied.ts +21 -0
- package/src/generate-text/tool-output.ts +7 -0
- package/src/generate-text/tool-result.ts +36 -0
- package/src/generate-text/tool-set.ts +14 -0
- package/src/global.ts +24 -0
- package/src/index.ts +50 -0
- package/src/logger/index.ts +6 -0
- package/src/logger/log-warnings.test.ts +351 -0
- package/src/logger/log-warnings.ts +119 -0
- package/src/middleware/__snapshots__/simulate-streaming-middleware.test.ts.snap +64 -0
- package/src/middleware/add-tool-input-examples-middleware.test.ts +476 -0
- package/src/middleware/add-tool-input-examples-middleware.ts +90 -0
- package/src/middleware/default-embedding-settings-middleware.test.ts +126 -0
- package/src/middleware/default-embedding-settings-middleware.ts +22 -0
- package/src/middleware/default-settings-middleware.test.ts +388 -0
- package/src/middleware/default-settings-middleware.ts +33 -0
- package/src/middleware/extract-json-middleware.test.ts +827 -0
- package/src/middleware/extract-json-middleware.ts +197 -0
- package/src/middleware/extract-reasoning-middleware.test.ts +1028 -0
- package/src/middleware/extract-reasoning-middleware.ts +238 -0
- package/src/middleware/index.ts +10 -0
- package/src/middleware/simulate-streaming-middleware.test.ts +911 -0
- package/src/middleware/simulate-streaming-middleware.ts +79 -0
- package/src/middleware/wrap-embedding-model.test.ts +358 -0
- package/src/middleware/wrap-embedding-model.ts +86 -0
- package/src/middleware/wrap-image-model.test.ts +423 -0
- package/src/middleware/wrap-image-model.ts +85 -0
- package/src/middleware/wrap-language-model.test.ts +518 -0
- package/src/middleware/wrap-language-model.ts +104 -0
- package/src/middleware/wrap-provider.test.ts +120 -0
- package/src/middleware/wrap-provider.ts +51 -0
- package/src/model/as-embedding-model-v3.test.ts +319 -0
- package/src/model/as-embedding-model-v3.ts +24 -0
- package/src/model/as-image-model-v3.test.ts +409 -0
- package/src/model/as-image-model-v3.ts +24 -0
- package/src/model/as-language-model-v3.test.ts +508 -0
- package/src/model/as-language-model-v3.ts +103 -0
- package/src/model/as-provider-v3.ts +36 -0
- package/src/model/as-speech-model-v3.test.ts +356 -0
- package/src/model/as-speech-model-v3.ts +24 -0
- package/src/model/as-transcription-model-v3.test.ts +529 -0
- package/src/model/as-transcription-model-v3.ts +24 -0
- package/src/model/resolve-model.test.ts +244 -0
- package/src/model/resolve-model.ts +126 -0
- package/src/prompt/call-settings.ts +148 -0
- package/src/prompt/content-part.ts +209 -0
- package/src/prompt/convert-to-language-model-prompt.test.ts +2018 -0
- package/src/prompt/convert-to-language-model-prompt.ts +442 -0
- package/src/prompt/create-tool-model-output.test.ts +508 -0
- package/src/prompt/create-tool-model-output.ts +34 -0
- package/src/prompt/data-content.test.ts +15 -0
- package/src/prompt/data-content.ts +134 -0
- package/src/prompt/index.ts +27 -0
- package/src/prompt/invalid-data-content-error.ts +29 -0
- package/src/prompt/invalid-message-role-error.ts +27 -0
- package/src/prompt/message-conversion-error.ts +28 -0
- package/src/prompt/message.ts +68 -0
- package/src/prompt/prepare-call-settings.test.ts +159 -0
- package/src/prompt/prepare-call-settings.ts +108 -0
- package/src/prompt/prepare-tools-and-tool-choice.test.ts +461 -0
- package/src/prompt/prepare-tools-and-tool-choice.ts +86 -0
- package/src/prompt/prompt.ts +43 -0
- package/src/prompt/split-data-url.ts +17 -0
- package/src/prompt/standardize-prompt.test.ts +82 -0
- package/src/prompt/standardize-prompt.ts +99 -0
- package/src/prompt/wrap-gateway-error.ts +29 -0
- package/src/registry/custom-provider.test.ts +211 -0
- package/src/registry/custom-provider.ts +155 -0
- package/src/registry/index.ts +7 -0
- package/src/registry/no-such-provider-error.ts +41 -0
- package/src/registry/provider-registry.test.ts +691 -0
- package/src/registry/provider-registry.ts +328 -0
- package/src/rerank/index.ts +2 -0
- package/src/rerank/rerank-result.ts +70 -0
- package/src/rerank/rerank.test.ts +516 -0
- package/src/rerank/rerank.ts +237 -0
- package/src/telemetry/assemble-operation-name.ts +21 -0
- package/src/telemetry/get-base-telemetry-attributes.ts +53 -0
- package/src/telemetry/get-tracer.ts +20 -0
- package/src/telemetry/noop-tracer.ts +69 -0
- package/src/telemetry/record-span.ts +63 -0
- package/src/telemetry/select-telemetry-attributes.ts +78 -0
- package/src/telemetry/select-temetry-attributes.test.ts +114 -0
- package/src/telemetry/stringify-for-telemetry.test.ts +114 -0
- package/src/telemetry/stringify-for-telemetry.ts +33 -0
- package/src/telemetry/telemetry-settings.ts +44 -0
- package/src/test/mock-embedding-model-v2.ts +35 -0
- package/src/test/mock-embedding-model-v3.ts +48 -0
- package/src/test/mock-image-model-v2.ts +28 -0
- package/src/test/mock-image-model-v3.ts +28 -0
- package/src/test/mock-language-model-v2.ts +72 -0
- package/src/test/mock-language-model-v3.ts +77 -0
- package/src/test/mock-provider-v2.ts +68 -0
- package/src/test/mock-provider-v3.ts +80 -0
- package/src/test/mock-reranking-model-v3.ts +25 -0
- package/src/test/mock-server-response.ts +69 -0
- package/src/test/mock-speech-model-v2.ts +24 -0
- package/src/test/mock-speech-model-v3.ts +24 -0
- package/src/test/mock-tracer.ts +156 -0
- package/src/test/mock-transcription-model-v2.ts +24 -0
- package/src/test/mock-transcription-model-v3.ts +24 -0
- package/src/test/mock-values.ts +4 -0
- package/src/test/not-implemented.ts +3 -0
- package/src/text-stream/create-text-stream-response.test.ts +38 -0
- package/src/text-stream/create-text-stream-response.ts +18 -0
- package/src/text-stream/index.ts +2 -0
- package/src/text-stream/pipe-text-stream-to-response.test.ts +38 -0
- package/src/text-stream/pipe-text-stream-to-response.ts +26 -0
- package/src/transcribe/index.ts +2 -0
- package/src/transcribe/transcribe-result.ts +60 -0
- package/src/transcribe/transcribe.test.ts +313 -0
- package/src/transcribe/transcribe.ts +173 -0
- package/src/types/embedding-model-middleware.ts +3 -0
- package/src/types/embedding-model.ts +18 -0
- package/src/types/image-model-middleware.ts +3 -0
- package/src/types/image-model-response-metadata.ts +16 -0
- package/src/types/image-model.ts +19 -0
- package/src/types/index.ts +29 -0
- package/src/types/json-value.ts +15 -0
- package/src/types/language-model-middleware.ts +3 -0
- package/src/types/language-model-request-metadata.ts +6 -0
- package/src/types/language-model-response-metadata.ts +21 -0
- package/src/types/language-model.ts +104 -0
- package/src/types/provider-metadata.ts +16 -0
- package/src/types/provider.ts +55 -0
- package/src/types/reranking-model.ts +6 -0
- package/src/types/speech-model-response-metadata.ts +21 -0
- package/src/types/speech-model.ts +6 -0
- package/src/types/transcription-model-response-metadata.ts +16 -0
- package/src/types/transcription-model.ts +9 -0
- package/src/types/usage.ts +200 -0
- package/src/types/warning.ts +7 -0
- package/src/ui/__snapshots__/append-response-messages.test.ts.snap +416 -0
- package/src/ui/__snapshots__/convert-to-model-messages.test.ts.snap +419 -0
- package/src/ui/__snapshots__/process-chat-text-response.test.ts.snap +142 -0
- package/src/ui/call-completion-api.ts +157 -0
- package/src/ui/chat-transport.ts +83 -0
- package/src/ui/chat.test-d.ts +233 -0
- package/src/ui/chat.test.ts +2695 -0
- package/src/ui/chat.ts +716 -0
- package/src/ui/convert-file-list-to-file-ui-parts.ts +36 -0
- package/src/ui/convert-to-model-messages.test.ts +2775 -0
- package/src/ui/convert-to-model-messages.ts +373 -0
- package/src/ui/default-chat-transport.ts +36 -0
- package/src/ui/direct-chat-transport.test.ts +446 -0
- package/src/ui/direct-chat-transport.ts +118 -0
- package/src/ui/http-chat-transport.test.ts +185 -0
- package/src/ui/http-chat-transport.ts +292 -0
- package/src/ui/index.ts +71 -0
- package/src/ui/last-assistant-message-is-complete-with-approval-responses.ts +44 -0
- package/src/ui/last-assistant-message-is-complete-with-tool-calls.test.ts +371 -0
- package/src/ui/last-assistant-message-is-complete-with-tool-calls.ts +39 -0
- package/src/ui/process-text-stream.test.ts +38 -0
- package/src/ui/process-text-stream.ts +16 -0
- package/src/ui/process-ui-message-stream.test.ts +8294 -0
- package/src/ui/process-ui-message-stream.ts +761 -0
- package/src/ui/text-stream-chat-transport.ts +23 -0
- package/src/ui/transform-text-to-ui-message-stream.test.ts +124 -0
- package/src/ui/transform-text-to-ui-message-stream.ts +27 -0
- package/src/ui/ui-messages.test.ts +48 -0
- package/src/ui/ui-messages.ts +534 -0
- package/src/ui/use-completion.ts +84 -0
- package/src/ui/validate-ui-messages.test.ts +1428 -0
- package/src/ui/validate-ui-messages.ts +476 -0
- package/src/ui-message-stream/create-ui-message-stream-response.test.ts +266 -0
- package/src/ui-message-stream/create-ui-message-stream-response.ts +32 -0
- package/src/ui-message-stream/create-ui-message-stream.test.ts +639 -0
- package/src/ui-message-stream/create-ui-message-stream.ts +124 -0
- package/src/ui-message-stream/get-response-ui-message-id.test.ts +55 -0
- package/src/ui-message-stream/get-response-ui-message-id.ts +24 -0
- package/src/ui-message-stream/handle-ui-message-stream-finish.test.ts +429 -0
- package/src/ui-message-stream/handle-ui-message-stream-finish.ts +135 -0
- package/src/ui-message-stream/index.ts +13 -0
- package/src/ui-message-stream/json-to-sse-transform-stream.ts +12 -0
- package/src/ui-message-stream/pipe-ui-message-stream-to-response.test.ts +90 -0
- package/src/ui-message-stream/pipe-ui-message-stream-to-response.ts +40 -0
- package/src/ui-message-stream/read-ui-message-stream.test.ts +122 -0
- package/src/ui-message-stream/read-ui-message-stream.ts +87 -0
- package/src/ui-message-stream/ui-message-chunks.test-d.ts +18 -0
- package/src/ui-message-stream/ui-message-chunks.ts +344 -0
- package/src/ui-message-stream/ui-message-stream-headers.ts +7 -0
- package/src/ui-message-stream/ui-message-stream-on-finish-callback.ts +32 -0
- package/src/ui-message-stream/ui-message-stream-response-init.ts +5 -0
- package/src/ui-message-stream/ui-message-stream-writer.ts +24 -0
- package/src/util/as-array.ts +3 -0
- package/src/util/async-iterable-stream.test.ts +241 -0
- package/src/util/async-iterable-stream.ts +94 -0
- package/src/util/consume-stream.ts +29 -0
- package/src/util/cosine-similarity.test.ts +57 -0
- package/src/util/cosine-similarity.ts +47 -0
- package/src/util/create-resolvable-promise.ts +30 -0
- package/src/util/create-stitchable-stream.test.ts +239 -0
- package/src/util/create-stitchable-stream.ts +112 -0
- package/src/util/data-url.ts +17 -0
- package/src/util/deep-partial.ts +84 -0
- package/src/util/detect-media-type.test.ts +670 -0
- package/src/util/detect-media-type.ts +184 -0
- package/src/util/download/download-function.ts +45 -0
- package/src/util/download/download.test.ts +69 -0
- package/src/util/download/download.ts +46 -0
- package/src/util/error-handler.ts +1 -0
- package/src/util/fix-json.test.ts +279 -0
- package/src/util/fix-json.ts +401 -0
- package/src/util/get-potential-start-index.test.ts +34 -0
- package/src/util/get-potential-start-index.ts +30 -0
- package/src/util/index.ts +11 -0
- package/src/util/is-deep-equal-data.test.ts +119 -0
- package/src/util/is-deep-equal-data.ts +48 -0
- package/src/util/is-non-empty-object.ts +5 -0
- package/src/util/job.ts +1 -0
- package/src/util/log-v2-compatibility-warning.ts +21 -0
- package/src/util/merge-abort-signals.test.ts +155 -0
- package/src/util/merge-abort-signals.ts +43 -0
- package/src/util/merge-objects.test.ts +118 -0
- package/src/util/merge-objects.ts +79 -0
- package/src/util/now.ts +4 -0
- package/src/util/parse-partial-json.test.ts +80 -0
- package/src/util/parse-partial-json.ts +30 -0
- package/src/util/prepare-headers.test.ts +51 -0
- package/src/util/prepare-headers.ts +14 -0
- package/src/util/prepare-retries.test.ts +10 -0
- package/src/util/prepare-retries.ts +47 -0
- package/src/util/retry-error.ts +41 -0
- package/src/util/retry-with-exponential-backoff.test.ts +446 -0
- package/src/util/retry-with-exponential-backoff.ts +154 -0
- package/src/util/serial-job-executor.test.ts +162 -0
- package/src/util/serial-job-executor.ts +36 -0
- package/src/util/simulate-readable-stream.test.ts +98 -0
- package/src/util/simulate-readable-stream.ts +39 -0
- package/src/util/split-array.test.ts +60 -0
- package/src/util/split-array.ts +20 -0
- package/src/util/value-of.ts +65 -0
- package/src/util/write-to-server-response.test.ts +266 -0
- package/src/util/write-to-server-response.ts +49 -0
- package/src/version.ts +5 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { DelayedPromise } from '@ai-sdk/provider-utils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { SerialJobExecutor } from './serial-job-executor';
|
|
4
|
+
|
|
5
|
+
describe('SerialJobExecutor', () => {
|
|
6
|
+
it('should execute a single job successfully', async () => {
|
|
7
|
+
const executor = new SerialJobExecutor();
|
|
8
|
+
const result = new DelayedPromise<string>();
|
|
9
|
+
|
|
10
|
+
const jobPromise = executor.run(async () => {
|
|
11
|
+
result.resolve('done');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
await jobPromise;
|
|
15
|
+
expect(await result.promise).toBe('done');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should execute multiple jobs in serial order', async () => {
|
|
19
|
+
const executor = new SerialJobExecutor();
|
|
20
|
+
const executionOrder: number[] = [];
|
|
21
|
+
const job1Promise = new DelayedPromise<void>();
|
|
22
|
+
const job2Promise = new DelayedPromise<void>();
|
|
23
|
+
const job3Promise = new DelayedPromise<void>();
|
|
24
|
+
|
|
25
|
+
// Start all jobs
|
|
26
|
+
const promise1 = executor.run(async () => {
|
|
27
|
+
executionOrder.push(1);
|
|
28
|
+
job1Promise.resolve();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const promise2 = executor.run(async () => {
|
|
32
|
+
executionOrder.push(2);
|
|
33
|
+
job2Promise.resolve();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const promise3 = executor.run(async () => {
|
|
37
|
+
executionOrder.push(3);
|
|
38
|
+
job3Promise.resolve();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Wait for all jobs to complete
|
|
42
|
+
await Promise.all([promise1, promise2, promise3]);
|
|
43
|
+
|
|
44
|
+
// Verify execution order
|
|
45
|
+
expect(executionOrder).toEqual([1, 2, 3]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should handle job errors correctly', async () => {
|
|
49
|
+
const executor = new SerialJobExecutor();
|
|
50
|
+
const error = new Error('test error');
|
|
51
|
+
|
|
52
|
+
const promise = executor.run(async () => {
|
|
53
|
+
throw error;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
await expect(promise).rejects.toThrow(error);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should execute jobs one at a time', async () => {
|
|
60
|
+
const executor = new SerialJobExecutor();
|
|
61
|
+
let concurrentJobs = 0;
|
|
62
|
+
let maxConcurrentJobs = 0;
|
|
63
|
+
const job1 = new DelayedPromise<void>();
|
|
64
|
+
const job2 = new DelayedPromise<void>();
|
|
65
|
+
|
|
66
|
+
// Start two jobs
|
|
67
|
+
const promise1 = executor.run(async () => {
|
|
68
|
+
concurrentJobs++;
|
|
69
|
+
maxConcurrentJobs = Math.max(maxConcurrentJobs, concurrentJobs);
|
|
70
|
+
await job1.promise;
|
|
71
|
+
concurrentJobs--;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const promise2 = executor.run(async () => {
|
|
75
|
+
concurrentJobs++;
|
|
76
|
+
maxConcurrentJobs = Math.max(maxConcurrentJobs, concurrentJobs);
|
|
77
|
+
await job2.promise;
|
|
78
|
+
concurrentJobs--;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Let both jobs proceed and complete
|
|
82
|
+
job1.resolve();
|
|
83
|
+
job2.resolve();
|
|
84
|
+
|
|
85
|
+
await Promise.all([promise1, promise2]);
|
|
86
|
+
|
|
87
|
+
expect(maxConcurrentJobs).toBe(1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should handle mixed success and failure jobs', async () => {
|
|
91
|
+
const executor = new SerialJobExecutor();
|
|
92
|
+
const results: string[] = [];
|
|
93
|
+
const error = new Error('test error');
|
|
94
|
+
|
|
95
|
+
// Queue multiple jobs with mixed success/failure
|
|
96
|
+
const promise1 = executor.run(async () => {
|
|
97
|
+
results.push('job1');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const promise2 = executor.run(async () => {
|
|
101
|
+
throw error;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const promise3 = executor.run(async () => {
|
|
105
|
+
results.push('job3');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// First job should succeed
|
|
109
|
+
await promise1;
|
|
110
|
+
expect(results).toEqual(['job1']);
|
|
111
|
+
|
|
112
|
+
// Second job should fail
|
|
113
|
+
await expect(promise2).rejects.toThrow(error);
|
|
114
|
+
|
|
115
|
+
// Third job should still execute and succeed
|
|
116
|
+
await promise3;
|
|
117
|
+
expect(results).toEqual(['job1', 'job3']);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should handle concurrent calls to run()', async () => {
|
|
121
|
+
const executor = new SerialJobExecutor();
|
|
122
|
+
const executionOrder: number[] = [];
|
|
123
|
+
const startOrder: number[] = [];
|
|
124
|
+
|
|
125
|
+
// Create delayed promises for controlling job execution
|
|
126
|
+
const job1 = new DelayedPromise<void>();
|
|
127
|
+
const job2 = new DelayedPromise<void>();
|
|
128
|
+
const job3 = new DelayedPromise<void>();
|
|
129
|
+
|
|
130
|
+
// Start all jobs concurrently
|
|
131
|
+
const promises = [
|
|
132
|
+
executor.run(async () => {
|
|
133
|
+
startOrder.push(1);
|
|
134
|
+
await job1.promise;
|
|
135
|
+
executionOrder.push(1);
|
|
136
|
+
}),
|
|
137
|
+
executor.run(async () => {
|
|
138
|
+
startOrder.push(2);
|
|
139
|
+
await job2.promise;
|
|
140
|
+
executionOrder.push(2);
|
|
141
|
+
}),
|
|
142
|
+
executor.run(async () => {
|
|
143
|
+
startOrder.push(3);
|
|
144
|
+
await job3.promise;
|
|
145
|
+
executionOrder.push(3);
|
|
146
|
+
}),
|
|
147
|
+
].map(p => p.catch(e => e));
|
|
148
|
+
|
|
149
|
+
// Resolve jobs in reverse order to verify execution order is maintained
|
|
150
|
+
job3.resolve();
|
|
151
|
+
job2.resolve();
|
|
152
|
+
job1.resolve();
|
|
153
|
+
|
|
154
|
+
// Wait for all jobs to complete
|
|
155
|
+
await Promise.all(promises);
|
|
156
|
+
|
|
157
|
+
// Verify that jobs were queued in the order they were submitted
|
|
158
|
+
expect(startOrder).toEqual([1, 2, 3]);
|
|
159
|
+
// Verify that jobs were executed in the order they were queued
|
|
160
|
+
expect(executionOrder).toEqual([1, 2, 3]);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Job } from './job';
|
|
2
|
+
|
|
3
|
+
export class SerialJobExecutor {
|
|
4
|
+
private queue: Array<Job> = [];
|
|
5
|
+
private isProcessing = false;
|
|
6
|
+
|
|
7
|
+
private async processQueue() {
|
|
8
|
+
if (this.isProcessing) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
this.isProcessing = true;
|
|
13
|
+
|
|
14
|
+
while (this.queue.length > 0) {
|
|
15
|
+
await this.queue[0]();
|
|
16
|
+
this.queue.shift();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
this.isProcessing = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async run(job: Job): Promise<void> {
|
|
23
|
+
return new Promise<void>((resolve, reject) => {
|
|
24
|
+
this.queue.push(async () => {
|
|
25
|
+
try {
|
|
26
|
+
await job();
|
|
27
|
+
resolve();
|
|
28
|
+
} catch (error) {
|
|
29
|
+
reject(error);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
void this.processQueue();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { simulateReadableStream } from './simulate-readable-stream';
|
|
2
|
+
import { convertReadableStreamToArray } from '@ai-sdk/provider-utils/test';
|
|
3
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
describe('simulateReadableStream', () => {
|
|
6
|
+
let delayValues: (number | null)[] = [];
|
|
7
|
+
const mockDelay = (ms: number | null) => {
|
|
8
|
+
delayValues.push(ms);
|
|
9
|
+
return Promise.resolve();
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
delayValues = [];
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should create a readable stream with provided values', async () => {
|
|
17
|
+
const values = ['a', 'b', 'c'];
|
|
18
|
+
const stream = simulateReadableStream({ chunks: values });
|
|
19
|
+
|
|
20
|
+
expect(await convertReadableStreamToArray(stream)).toEqual(values);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should respect the chunkDelayInMs setting', async () => {
|
|
24
|
+
const stream = simulateReadableStream({
|
|
25
|
+
chunks: [1, 2, 3],
|
|
26
|
+
initialDelayInMs: 500,
|
|
27
|
+
chunkDelayInMs: 100,
|
|
28
|
+
_internal: { delay: mockDelay },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await convertReadableStreamToArray(stream); // consume stream
|
|
32
|
+
|
|
33
|
+
expect(delayValues).toEqual([500, 100, 100]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should handle empty values array', async () => {
|
|
37
|
+
const stream = simulateReadableStream({ chunks: [] });
|
|
38
|
+
const reader = stream.getReader();
|
|
39
|
+
|
|
40
|
+
const { done, value } = await reader.read();
|
|
41
|
+
|
|
42
|
+
expect(done).toBe(true);
|
|
43
|
+
expect(value).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should handle different types of values', async () => {
|
|
47
|
+
const stream = simulateReadableStream({
|
|
48
|
+
chunks: [
|
|
49
|
+
{ id: 1, text: 'hello' },
|
|
50
|
+
{ id: 2, text: 'world' },
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(await convertReadableStreamToArray(stream)).toEqual([
|
|
55
|
+
{ id: 1, text: 'hello' },
|
|
56
|
+
{ id: 2, text: 'world' },
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should skip all delays when both delay settings are null', async () => {
|
|
61
|
+
const stream = simulateReadableStream({
|
|
62
|
+
chunks: [1, 2, 3],
|
|
63
|
+
initialDelayInMs: null,
|
|
64
|
+
chunkDelayInMs: null,
|
|
65
|
+
_internal: { delay: mockDelay },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await convertReadableStreamToArray(stream); // consume stream
|
|
69
|
+
|
|
70
|
+
expect(delayValues).toEqual([null, null, null]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should apply chunk delays but skip initial delay when initialDelayInMs is null', async () => {
|
|
74
|
+
const stream = simulateReadableStream({
|
|
75
|
+
chunks: [1, 2, 3],
|
|
76
|
+
initialDelayInMs: null,
|
|
77
|
+
chunkDelayInMs: 100,
|
|
78
|
+
_internal: { delay: mockDelay },
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await convertReadableStreamToArray(stream); // consume stream
|
|
82
|
+
|
|
83
|
+
expect(delayValues).toEqual([null, 100, 100]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should apply initial delay but skip chunk delays when chunkDelayInMs is null', async () => {
|
|
87
|
+
const stream = simulateReadableStream({
|
|
88
|
+
chunks: [1, 2, 3],
|
|
89
|
+
initialDelayInMs: 500,
|
|
90
|
+
chunkDelayInMs: null,
|
|
91
|
+
_internal: { delay: mockDelay },
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await convertReadableStreamToArray(stream); // consume stream
|
|
95
|
+
|
|
96
|
+
expect(delayValues).toEqual([500, null, null]);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { delay as delayFunction } from '@ai-sdk/provider-utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a ReadableStream that emits the provided values with an optional delay between each value.
|
|
5
|
+
*
|
|
6
|
+
* @param options - The configuration options
|
|
7
|
+
* @param options.chunks - Array of values to be emitted by the stream
|
|
8
|
+
* @param options.initialDelayInMs - Optional initial delay in milliseconds before emitting the first value (default: 0). Can be set to `null` to skip the initial delay. The difference between `initialDelayInMs: null` and `initialDelayInMs: 0` is that `initialDelayInMs: null` will emit the values without any delay, while `initialDelayInMs: 0` will emit the values with a delay of 0 milliseconds.
|
|
9
|
+
* @param options.chunkDelayInMs - Optional delay in milliseconds between emitting each value (default: 0). Can be set to `null` to skip the delay. The difference between `chunkDelayInMs: null` and `chunkDelayInMs: 0` is that `chunkDelayInMs: null` will emit the values without any delay, while `chunkDelayInMs: 0` will emit the values with a delay of 0 milliseconds.
|
|
10
|
+
* @returns A ReadableStream that emits the provided values
|
|
11
|
+
*/
|
|
12
|
+
export function simulateReadableStream<T>({
|
|
13
|
+
chunks,
|
|
14
|
+
initialDelayInMs = 0,
|
|
15
|
+
chunkDelayInMs = 0,
|
|
16
|
+
_internal,
|
|
17
|
+
}: {
|
|
18
|
+
chunks: T[];
|
|
19
|
+
initialDelayInMs?: number | null;
|
|
20
|
+
chunkDelayInMs?: number | null;
|
|
21
|
+
_internal?: {
|
|
22
|
+
delay?: (ms: number | null) => Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
}): ReadableStream<T> {
|
|
25
|
+
const delay = _internal?.delay ?? delayFunction;
|
|
26
|
+
|
|
27
|
+
let index = 0;
|
|
28
|
+
|
|
29
|
+
return new ReadableStream({
|
|
30
|
+
async pull(controller) {
|
|
31
|
+
if (index < chunks.length) {
|
|
32
|
+
await delay(index === 0 ? initialDelayInMs : chunkDelayInMs);
|
|
33
|
+
controller.enqueue(chunks[index++]);
|
|
34
|
+
} else {
|
|
35
|
+
controller.close();
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
import { splitArray } from './split-array';
|
|
3
|
+
|
|
4
|
+
it('should split an array into chunks of the specified size', () => {
|
|
5
|
+
const array = [1, 2, 3, 4, 5];
|
|
6
|
+
const size = 2;
|
|
7
|
+
const result = splitArray(array, size);
|
|
8
|
+
expect(result).toEqual([[1, 2], [3, 4], [5]]);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return an empty array when the input array is empty', () => {
|
|
12
|
+
const array: number[] = [];
|
|
13
|
+
const size = 2;
|
|
14
|
+
const result = splitArray(array, size);
|
|
15
|
+
expect(result).toEqual([]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return the original array when the chunk size is greater than the array length', () => {
|
|
19
|
+
const array = [1, 2, 3];
|
|
20
|
+
const size = 5;
|
|
21
|
+
const result = splitArray(array, size);
|
|
22
|
+
expect(result).toEqual([[1, 2, 3]]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return the original array when the chunk size is equal to the array length', () => {
|
|
26
|
+
const array = [1, 2, 3];
|
|
27
|
+
const size = 3;
|
|
28
|
+
const result = splitArray(array, size);
|
|
29
|
+
expect(result).toEqual([[1, 2, 3]]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should handle chunk size of 1 correctly', () => {
|
|
33
|
+
const array = [1, 2, 3];
|
|
34
|
+
const size = 1;
|
|
35
|
+
const result = splitArray(array, size);
|
|
36
|
+
expect(result).toEqual([[1], [2], [3]]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should throw an error for chunk size of 0', () => {
|
|
40
|
+
const array = [1, 2, 3];
|
|
41
|
+
const size = 0;
|
|
42
|
+
expect(() => splitArray(array, size)).toThrow(
|
|
43
|
+
'chunkSize must be greater than 0',
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should throw an error for negative chunk size', () => {
|
|
48
|
+
const array = [1, 2, 3];
|
|
49
|
+
const size = -1;
|
|
50
|
+
expect(() => splitArray(array, size)).toThrow(
|
|
51
|
+
'chunkSize must be greater than 0',
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should handle non-integer chunk size by flooring the size', () => {
|
|
56
|
+
const array = [1, 2, 3, 4, 5];
|
|
57
|
+
const size = 2.5;
|
|
58
|
+
const result = splitArray(array, Math.floor(size));
|
|
59
|
+
expect(result).toEqual([[1, 2], [3, 4], [5]]);
|
|
60
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits an array into chunks of a specified size.
|
|
3
|
+
*
|
|
4
|
+
* @template T - The type of elements in the array.
|
|
5
|
+
* @param {T[]} array - The array to split.
|
|
6
|
+
* @param {number} chunkSize - The size of each chunk.
|
|
7
|
+
* @returns {T[][]} - A new array containing the chunks.
|
|
8
|
+
*/
|
|
9
|
+
export function splitArray<T>(array: T[], chunkSize: number): T[][] {
|
|
10
|
+
if (chunkSize <= 0) {
|
|
11
|
+
throw new Error('chunkSize must be greater than 0');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const result = [];
|
|
15
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
16
|
+
result.push(array.slice(i, i + chunkSize));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// License for this File only:
|
|
2
|
+
//
|
|
3
|
+
// MIT License
|
|
4
|
+
//
|
|
5
|
+
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
|
6
|
+
// Copyright (c) Vercel, Inc. (https://vercel.com)
|
|
7
|
+
//
|
|
8
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
9
|
+
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
10
|
+
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
11
|
+
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
12
|
+
//
|
|
13
|
+
// The above copyright notice and this permission notice shall be included in all copies or substantial portions
|
|
14
|
+
// of the Software.
|
|
15
|
+
//
|
|
16
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
17
|
+
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
18
|
+
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
19
|
+
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
20
|
+
// IN THE SOFTWARE.
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
Create a union of the given object's values, and optionally specify which keys to get the values from.
|
|
24
|
+
|
|
25
|
+
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31438) if you want to have this type as a built-in in TypeScript.
|
|
26
|
+
|
|
27
|
+
@example
|
|
28
|
+
```
|
|
29
|
+
// data.json
|
|
30
|
+
{
|
|
31
|
+
'foo': 1,
|
|
32
|
+
'bar': 2,
|
|
33
|
+
'biz': 3
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// main.ts
|
|
37
|
+
import type {ValueOf} from 'type-fest';
|
|
38
|
+
import data = require('./data.json');
|
|
39
|
+
|
|
40
|
+
export function getData(name: string): ValueOf<typeof data> {
|
|
41
|
+
return data[name];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function onlyBar(name: string): ValueOf<typeof data, 'bar'> {
|
|
45
|
+
return data[name];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// file.ts
|
|
49
|
+
import {getData, onlyBar} from './main';
|
|
50
|
+
|
|
51
|
+
getData('foo');
|
|
52
|
+
//=> 1
|
|
53
|
+
|
|
54
|
+
onlyBar('foo');
|
|
55
|
+
//=> TypeError ...
|
|
56
|
+
|
|
57
|
+
onlyBar('bar');
|
|
58
|
+
//=> 2
|
|
59
|
+
```
|
|
60
|
+
* @see https://github.com/sindresorhus/type-fest/blob/main/source/value-of.d.ts
|
|
61
|
+
*/
|
|
62
|
+
export type ValueOf<
|
|
63
|
+
ObjectType,
|
|
64
|
+
ValueType extends keyof ObjectType = keyof ObjectType,
|
|
65
|
+
> = ObjectType[ValueType];
|