ai 6.0.32 → 6.0.34
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.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -2
- 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/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 +34 -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/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 +8052 -0
- package/src/ui/process-ui-message-stream.ts +713 -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,185 @@
|
|
|
1
|
+
import { createTestServer } from '@ai-sdk/test-server/with-vitest';
|
|
2
|
+
import { UIMessageChunk } from '../ui-message-stream/ui-message-chunks';
|
|
3
|
+
import {
|
|
4
|
+
HttpChatTransport,
|
|
5
|
+
HttpChatTransportInitOptions,
|
|
6
|
+
} from './http-chat-transport';
|
|
7
|
+
import { UIMessage } from './ui-messages';
|
|
8
|
+
import { describe, it, expect } from 'vitest';
|
|
9
|
+
|
|
10
|
+
class MockHttpChatTransport extends HttpChatTransport<UIMessage> {
|
|
11
|
+
constructor(options: HttpChatTransportInitOptions<UIMessage> = {}) {
|
|
12
|
+
super(options);
|
|
13
|
+
}
|
|
14
|
+
protected processResponseStream(
|
|
15
|
+
stream: ReadableStream<Uint8Array<ArrayBufferLike>>,
|
|
16
|
+
): ReadableStream<UIMessageChunk> {
|
|
17
|
+
return new ReadableStream();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const server = createTestServer({
|
|
22
|
+
'http://localhost/api/chat': {},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('HttpChatTransport', () => {
|
|
26
|
+
describe('body', () => {
|
|
27
|
+
it('should include the body in the request by default', async () => {
|
|
28
|
+
server.urls['http://localhost/api/chat'].response = {
|
|
29
|
+
type: 'stream-chunks',
|
|
30
|
+
chunks: [],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const transport = new MockHttpChatTransport({
|
|
34
|
+
api: 'http://localhost/api/chat',
|
|
35
|
+
body: { someData: true },
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await transport.sendMessages({
|
|
39
|
+
chatId: 'c123',
|
|
40
|
+
messageId: 'm123',
|
|
41
|
+
trigger: 'submit-message',
|
|
42
|
+
messages: [
|
|
43
|
+
{
|
|
44
|
+
id: 'm123',
|
|
45
|
+
role: 'user',
|
|
46
|
+
parts: [{ text: 'Hello, world!', type: 'text' }],
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
abortSignal: new AbortController().signal,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(`
|
|
53
|
+
{
|
|
54
|
+
"id": "c123",
|
|
55
|
+
"messageId": "m123",
|
|
56
|
+
"messages": [
|
|
57
|
+
{
|
|
58
|
+
"id": "m123",
|
|
59
|
+
"parts": [
|
|
60
|
+
{
|
|
61
|
+
"text": "Hello, world!",
|
|
62
|
+
"type": "text",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
"role": "user",
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
"someData": true,
|
|
69
|
+
"trigger": "submit-message",
|
|
70
|
+
}
|
|
71
|
+
`);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should include the body in the request when a function is provided', async () => {
|
|
75
|
+
server.urls['http://localhost/api/chat'].response = {
|
|
76
|
+
type: 'stream-chunks',
|
|
77
|
+
chunks: [],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const transport = new MockHttpChatTransport({
|
|
81
|
+
api: 'http://localhost/api/chat',
|
|
82
|
+
body: () => ({ someData: true }),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await transport.sendMessages({
|
|
86
|
+
chatId: 'c123',
|
|
87
|
+
messageId: 'm123',
|
|
88
|
+
trigger: 'submit-message',
|
|
89
|
+
messages: [
|
|
90
|
+
{
|
|
91
|
+
id: 'm123',
|
|
92
|
+
role: 'user',
|
|
93
|
+
parts: [{ text: 'Hello, world!', type: 'text' }],
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
abortSignal: new AbortController().signal,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(`
|
|
100
|
+
{
|
|
101
|
+
"id": "c123",
|
|
102
|
+
"messageId": "m123",
|
|
103
|
+
"messages": [
|
|
104
|
+
{
|
|
105
|
+
"id": "m123",
|
|
106
|
+
"parts": [
|
|
107
|
+
{
|
|
108
|
+
"text": "Hello, world!",
|
|
109
|
+
"type": "text",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
"role": "user",
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
"someData": true,
|
|
116
|
+
"trigger": "submit-message",
|
|
117
|
+
}
|
|
118
|
+
`);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('headers', () => {
|
|
123
|
+
it('should include headers in the request by default', async () => {
|
|
124
|
+
server.urls['http://localhost/api/chat'].response = {
|
|
125
|
+
type: 'stream-chunks',
|
|
126
|
+
chunks: [],
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const transport = new MockHttpChatTransport({
|
|
130
|
+
api: 'http://localhost/api/chat',
|
|
131
|
+
headers: { 'X-Test-Header': 'test-value' },
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
await transport.sendMessages({
|
|
135
|
+
chatId: 'c123',
|
|
136
|
+
messageId: 'm123',
|
|
137
|
+
trigger: 'submit-message',
|
|
138
|
+
messages: [
|
|
139
|
+
{
|
|
140
|
+
id: 'm123',
|
|
141
|
+
role: 'user',
|
|
142
|
+
parts: [{ text: 'Hello, world!', type: 'text' }],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
abortSignal: new AbortController().signal,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
expect(server.calls[0].requestHeaders['x-test-header']).toBe(
|
|
149
|
+
'test-value',
|
|
150
|
+
);
|
|
151
|
+
expect(server.calls[0].requestUserAgent).toContain('ai-sdk/');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should include headers in the request when a function is provided', async () => {
|
|
155
|
+
server.urls['http://localhost/api/chat'].response = {
|
|
156
|
+
type: 'stream-chunks',
|
|
157
|
+
chunks: [],
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const transport = new MockHttpChatTransport({
|
|
161
|
+
api: 'http://localhost/api/chat',
|
|
162
|
+
headers: () => ({ 'X-Test-Header': 'test-value-fn' }),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
await transport.sendMessages({
|
|
166
|
+
chatId: 'c123',
|
|
167
|
+
messageId: 'm123',
|
|
168
|
+
trigger: 'submit-message',
|
|
169
|
+
messages: [
|
|
170
|
+
{
|
|
171
|
+
id: 'm123',
|
|
172
|
+
role: 'user',
|
|
173
|
+
parts: [{ text: 'Hello, world!', type: 'text' }],
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
abortSignal: new AbortController().signal,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(server.calls[0].requestHeaders['x-test-header']).toBe(
|
|
180
|
+
'test-value-fn',
|
|
181
|
+
);
|
|
182
|
+
expect(server.calls[0].requestUserAgent).toContain('ai-sdk/');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FetchFunction,
|
|
3
|
+
Resolvable,
|
|
4
|
+
normalizeHeaders,
|
|
5
|
+
resolve,
|
|
6
|
+
withUserAgentSuffix,
|
|
7
|
+
getRuntimeEnvironmentUserAgent,
|
|
8
|
+
} from '@ai-sdk/provider-utils';
|
|
9
|
+
import { UIMessageChunk } from '../ui-message-stream/ui-message-chunks';
|
|
10
|
+
import { ChatTransport } from './chat-transport';
|
|
11
|
+
import { UIMessage } from './ui-messages';
|
|
12
|
+
import { VERSION } from '../version';
|
|
13
|
+
|
|
14
|
+
export type PrepareSendMessagesRequest<UI_MESSAGE extends UIMessage> = (
|
|
15
|
+
options: {
|
|
16
|
+
id: string;
|
|
17
|
+
messages: UI_MESSAGE[];
|
|
18
|
+
requestMetadata: unknown;
|
|
19
|
+
body: Record<string, any> | undefined;
|
|
20
|
+
credentials: RequestCredentials | undefined;
|
|
21
|
+
headers: HeadersInit | undefined;
|
|
22
|
+
api: string;
|
|
23
|
+
} & {
|
|
24
|
+
trigger: 'submit-message' | 'regenerate-message';
|
|
25
|
+
messageId: string | undefined;
|
|
26
|
+
},
|
|
27
|
+
) =>
|
|
28
|
+
| {
|
|
29
|
+
body: object;
|
|
30
|
+
headers?: HeadersInit;
|
|
31
|
+
credentials?: RequestCredentials;
|
|
32
|
+
api?: string;
|
|
33
|
+
}
|
|
34
|
+
| PromiseLike<{
|
|
35
|
+
body: object;
|
|
36
|
+
headers?: HeadersInit;
|
|
37
|
+
credentials?: RequestCredentials;
|
|
38
|
+
api?: string;
|
|
39
|
+
}>;
|
|
40
|
+
|
|
41
|
+
export type PrepareReconnectToStreamRequest = (options: {
|
|
42
|
+
id: string;
|
|
43
|
+
requestMetadata: unknown;
|
|
44
|
+
body: Record<string, any> | undefined;
|
|
45
|
+
credentials: RequestCredentials | undefined;
|
|
46
|
+
headers: HeadersInit | undefined;
|
|
47
|
+
api: string;
|
|
48
|
+
}) =>
|
|
49
|
+
| {
|
|
50
|
+
headers?: HeadersInit;
|
|
51
|
+
credentials?: RequestCredentials;
|
|
52
|
+
api?: string;
|
|
53
|
+
}
|
|
54
|
+
| PromiseLike<{
|
|
55
|
+
headers?: HeadersInit;
|
|
56
|
+
credentials?: RequestCredentials;
|
|
57
|
+
api?: string;
|
|
58
|
+
}>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Options for the `HttpChatTransport` class.
|
|
62
|
+
*
|
|
63
|
+
* @param UI_MESSAGE - The type of message to be used in the chat.
|
|
64
|
+
*/
|
|
65
|
+
export type HttpChatTransportInitOptions<UI_MESSAGE extends UIMessage> = {
|
|
66
|
+
/**
|
|
67
|
+
* The API URL to be used for the chat transport.
|
|
68
|
+
* Defaults to '/api/chat'.
|
|
69
|
+
*/
|
|
70
|
+
api?: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The credentials mode to be used for the fetch request.
|
|
74
|
+
* Possible values are: 'omit', 'same-origin', 'include'.
|
|
75
|
+
* Defaults to 'same-origin'.
|
|
76
|
+
*/
|
|
77
|
+
credentials?: Resolvable<RequestCredentials>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* HTTP headers to be sent with the API request.
|
|
81
|
+
*/
|
|
82
|
+
headers?: Resolvable<Record<string, string> | Headers>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Extra body object to be sent with the API request.
|
|
86
|
+
* @example
|
|
87
|
+
* Send a `sessionId` to the API along with the messages.
|
|
88
|
+
* ```js
|
|
89
|
+
* useChat({
|
|
90
|
+
* body: {
|
|
91
|
+
* sessionId: '123',
|
|
92
|
+
* }
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
body?: Resolvable<object>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
Custom fetch implementation. You can use it as a middleware to intercept requests,
|
|
100
|
+
or to provide a custom fetch implementation for e.g. testing.
|
|
101
|
+
*/
|
|
102
|
+
fetch?: FetchFunction;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* When a function is provided, it will be used
|
|
106
|
+
* to prepare the request body for the chat API. This can be useful for
|
|
107
|
+
* customizing the request body based on the messages and data in the chat.
|
|
108
|
+
*
|
|
109
|
+
* @param id The id of the chat.
|
|
110
|
+
* @param messages The current messages in the chat.
|
|
111
|
+
* @param requestBody The request body object passed in the chat request.
|
|
112
|
+
*/
|
|
113
|
+
prepareSendMessagesRequest?: PrepareSendMessagesRequest<UI_MESSAGE>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* When a function is provided, it will be used
|
|
117
|
+
* to prepare the request body for the chat API. This can be useful for
|
|
118
|
+
* customizing the request body based on the messages and data in the chat.
|
|
119
|
+
*
|
|
120
|
+
* @param id The id of the chat.
|
|
121
|
+
* @param messages The current messages in the chat.
|
|
122
|
+
* @param requestBody The request body object passed in the chat request.
|
|
123
|
+
*/
|
|
124
|
+
prepareReconnectToStreamRequest?: PrepareReconnectToStreamRequest;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export abstract class HttpChatTransport<UI_MESSAGE extends UIMessage>
|
|
128
|
+
implements ChatTransport<UI_MESSAGE>
|
|
129
|
+
{
|
|
130
|
+
protected api: string;
|
|
131
|
+
protected credentials: HttpChatTransportInitOptions<UI_MESSAGE>['credentials'];
|
|
132
|
+
protected headers: HttpChatTransportInitOptions<UI_MESSAGE>['headers'];
|
|
133
|
+
protected body: HttpChatTransportInitOptions<UI_MESSAGE>['body'];
|
|
134
|
+
protected fetch?: FetchFunction;
|
|
135
|
+
protected prepareSendMessagesRequest?: PrepareSendMessagesRequest<UI_MESSAGE>;
|
|
136
|
+
protected prepareReconnectToStreamRequest?: PrepareReconnectToStreamRequest;
|
|
137
|
+
|
|
138
|
+
constructor({
|
|
139
|
+
api = '/api/chat',
|
|
140
|
+
credentials,
|
|
141
|
+
headers,
|
|
142
|
+
body,
|
|
143
|
+
fetch,
|
|
144
|
+
prepareSendMessagesRequest,
|
|
145
|
+
prepareReconnectToStreamRequest,
|
|
146
|
+
}: HttpChatTransportInitOptions<UI_MESSAGE>) {
|
|
147
|
+
this.api = api;
|
|
148
|
+
this.credentials = credentials;
|
|
149
|
+
this.headers = headers;
|
|
150
|
+
this.body = body;
|
|
151
|
+
this.fetch = fetch;
|
|
152
|
+
this.prepareSendMessagesRequest = prepareSendMessagesRequest;
|
|
153
|
+
this.prepareReconnectToStreamRequest = prepareReconnectToStreamRequest;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async sendMessages({
|
|
157
|
+
abortSignal,
|
|
158
|
+
...options
|
|
159
|
+
}: Parameters<ChatTransport<UI_MESSAGE>['sendMessages']>[0]) {
|
|
160
|
+
const resolvedBody = await resolve(this.body);
|
|
161
|
+
const resolvedHeaders = await resolve(this.headers);
|
|
162
|
+
const resolvedCredentials = await resolve(this.credentials);
|
|
163
|
+
|
|
164
|
+
const baseHeaders = {
|
|
165
|
+
...normalizeHeaders(resolvedHeaders),
|
|
166
|
+
...normalizeHeaders(options.headers),
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const preparedRequest = await this.prepareSendMessagesRequest?.({
|
|
170
|
+
api: this.api,
|
|
171
|
+
id: options.chatId,
|
|
172
|
+
messages: options.messages,
|
|
173
|
+
body: { ...resolvedBody, ...options.body },
|
|
174
|
+
headers: baseHeaders,
|
|
175
|
+
credentials: resolvedCredentials,
|
|
176
|
+
requestMetadata: options.metadata,
|
|
177
|
+
trigger: options.trigger,
|
|
178
|
+
messageId: options.messageId,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const api = preparedRequest?.api ?? this.api;
|
|
182
|
+
const headers =
|
|
183
|
+
preparedRequest?.headers !== undefined
|
|
184
|
+
? normalizeHeaders(preparedRequest.headers)
|
|
185
|
+
: baseHeaders;
|
|
186
|
+
const body =
|
|
187
|
+
preparedRequest?.body !== undefined
|
|
188
|
+
? preparedRequest.body
|
|
189
|
+
: {
|
|
190
|
+
...resolvedBody,
|
|
191
|
+
...options.body,
|
|
192
|
+
id: options.chatId,
|
|
193
|
+
messages: options.messages,
|
|
194
|
+
trigger: options.trigger,
|
|
195
|
+
messageId: options.messageId,
|
|
196
|
+
};
|
|
197
|
+
const credentials = preparedRequest?.credentials ?? resolvedCredentials;
|
|
198
|
+
|
|
199
|
+
// avoid caching globalThis.fetch in case it is patched by other libraries
|
|
200
|
+
const fetch = this.fetch ?? globalThis.fetch;
|
|
201
|
+
|
|
202
|
+
const response = await fetch(api, {
|
|
203
|
+
method: 'POST',
|
|
204
|
+
headers: withUserAgentSuffix(
|
|
205
|
+
{
|
|
206
|
+
'Content-Type': 'application/json',
|
|
207
|
+
...headers,
|
|
208
|
+
},
|
|
209
|
+
`ai-sdk/${VERSION}`,
|
|
210
|
+
getRuntimeEnvironmentUserAgent(),
|
|
211
|
+
),
|
|
212
|
+
body: JSON.stringify(body),
|
|
213
|
+
credentials,
|
|
214
|
+
signal: abortSignal,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (!response.ok) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
(await response.text()) ?? 'Failed to fetch the chat response.',
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!response.body) {
|
|
224
|
+
throw new Error('The response body is empty.');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return this.processResponseStream(response.body);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async reconnectToStream(
|
|
231
|
+
options: Parameters<ChatTransport<UI_MESSAGE>['reconnectToStream']>[0],
|
|
232
|
+
): Promise<ReadableStream<UIMessageChunk> | null> {
|
|
233
|
+
const resolvedBody = await resolve(this.body);
|
|
234
|
+
const resolvedHeaders = await resolve(this.headers);
|
|
235
|
+
const resolvedCredentials = await resolve(this.credentials);
|
|
236
|
+
|
|
237
|
+
const baseHeaders = {
|
|
238
|
+
...normalizeHeaders(resolvedHeaders),
|
|
239
|
+
...normalizeHeaders(options.headers),
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const preparedRequest = await this.prepareReconnectToStreamRequest?.({
|
|
243
|
+
api: this.api,
|
|
244
|
+
id: options.chatId,
|
|
245
|
+
body: { ...resolvedBody, ...options.body },
|
|
246
|
+
headers: baseHeaders,
|
|
247
|
+
credentials: resolvedCredentials,
|
|
248
|
+
requestMetadata: options.metadata,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const api = preparedRequest?.api ?? `${this.api}/${options.chatId}/stream`;
|
|
252
|
+
const headers =
|
|
253
|
+
preparedRequest?.headers !== undefined
|
|
254
|
+
? normalizeHeaders(preparedRequest.headers)
|
|
255
|
+
: baseHeaders;
|
|
256
|
+
const credentials = preparedRequest?.credentials ?? resolvedCredentials;
|
|
257
|
+
|
|
258
|
+
// avoid caching globalThis.fetch in case it is patched by other libraries
|
|
259
|
+
const fetch = this.fetch ?? globalThis.fetch;
|
|
260
|
+
|
|
261
|
+
const response = await fetch(api, {
|
|
262
|
+
method: 'GET',
|
|
263
|
+
headers: withUserAgentSuffix(
|
|
264
|
+
headers,
|
|
265
|
+
`ai-sdk/${VERSION}`,
|
|
266
|
+
getRuntimeEnvironmentUserAgent(),
|
|
267
|
+
),
|
|
268
|
+
credentials,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// no active stream found, so we do not resume
|
|
272
|
+
if (response.status === 204) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!response.ok) {
|
|
277
|
+
throw new Error(
|
|
278
|
+
(await response.text()) ?? 'Failed to fetch the chat response.',
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (!response.body) {
|
|
283
|
+
throw new Error('The response body is empty.');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return this.processResponseStream(response.body);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
protected abstract processResponseStream(
|
|
290
|
+
stream: ReadableStream<Uint8Array<ArrayBufferLike>>,
|
|
291
|
+
): ReadableStream<UIMessageChunk>;
|
|
292
|
+
}
|
package/src/ui/index.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export { callCompletionApi } from './call-completion-api';
|
|
2
|
+
export {
|
|
3
|
+
AbstractChat,
|
|
4
|
+
type ChatAddToolApproveResponseFunction,
|
|
5
|
+
type ChatInit,
|
|
6
|
+
type ChatOnDataCallback,
|
|
7
|
+
type ChatOnErrorCallback,
|
|
8
|
+
type ChatOnFinishCallback,
|
|
9
|
+
type ChatOnToolCallCallback,
|
|
10
|
+
type ChatRequestOptions,
|
|
11
|
+
type ChatState,
|
|
12
|
+
type ChatStatus,
|
|
13
|
+
type CreateUIMessage,
|
|
14
|
+
type InferUIDataParts,
|
|
15
|
+
type UIDataPartSchemas,
|
|
16
|
+
} from './chat';
|
|
17
|
+
export { type ChatTransport } from './chat-transport';
|
|
18
|
+
export { convertFileListToFileUIParts } from './convert-file-list-to-file-ui-parts';
|
|
19
|
+
export { convertToModelMessages } from './convert-to-model-messages';
|
|
20
|
+
export { DefaultChatTransport } from './default-chat-transport';
|
|
21
|
+
export {
|
|
22
|
+
DirectChatTransport,
|
|
23
|
+
type DirectChatTransportOptions,
|
|
24
|
+
} from './direct-chat-transport';
|
|
25
|
+
export {
|
|
26
|
+
HttpChatTransport,
|
|
27
|
+
type HttpChatTransportInitOptions,
|
|
28
|
+
type PrepareReconnectToStreamRequest,
|
|
29
|
+
type PrepareSendMessagesRequest,
|
|
30
|
+
} from './http-chat-transport';
|
|
31
|
+
export { lastAssistantMessageIsCompleteWithApprovalResponses } from './last-assistant-message-is-complete-with-approval-responses';
|
|
32
|
+
export { lastAssistantMessageIsCompleteWithToolCalls } from './last-assistant-message-is-complete-with-tool-calls';
|
|
33
|
+
export { TextStreamChatTransport } from './text-stream-chat-transport';
|
|
34
|
+
export {
|
|
35
|
+
getStaticToolName,
|
|
36
|
+
getToolName,
|
|
37
|
+
getToolOrDynamicToolName,
|
|
38
|
+
isDataUIPart,
|
|
39
|
+
isFileUIPart,
|
|
40
|
+
isReasoningUIPart,
|
|
41
|
+
isStaticToolUIPart,
|
|
42
|
+
isTextUIPart,
|
|
43
|
+
isToolOrDynamicToolUIPart,
|
|
44
|
+
isToolUIPart,
|
|
45
|
+
type DataUIPart,
|
|
46
|
+
type DynamicToolUIPart,
|
|
47
|
+
type FileUIPart,
|
|
48
|
+
type InferUITool,
|
|
49
|
+
type InferUITools,
|
|
50
|
+
type ReasoningUIPart,
|
|
51
|
+
type SourceDocumentUIPart,
|
|
52
|
+
type SourceUrlUIPart,
|
|
53
|
+
type StepStartUIPart,
|
|
54
|
+
type TextUIPart,
|
|
55
|
+
type ToolUIPart,
|
|
56
|
+
type UIDataTypes,
|
|
57
|
+
type UIMessage,
|
|
58
|
+
type UIMessagePart,
|
|
59
|
+
type UITool,
|
|
60
|
+
type UIToolInvocation,
|
|
61
|
+
type UITools,
|
|
62
|
+
} from './ui-messages';
|
|
63
|
+
export {
|
|
64
|
+
type CompletionRequestOptions,
|
|
65
|
+
type UseCompletionOptions,
|
|
66
|
+
} from './use-completion';
|
|
67
|
+
export {
|
|
68
|
+
safeValidateUIMessages,
|
|
69
|
+
validateUIMessages,
|
|
70
|
+
type SafeValidateUIMessagesResult,
|
|
71
|
+
} from './validate-ui-messages';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isToolUIPart, type UIMessage } from './ui-messages';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Check if the last message is an assistant message with completed tool call approvals.
|
|
5
|
+
The last step of the message must have at least one tool approval response and
|
|
6
|
+
all tool approvals must have a response.
|
|
7
|
+
*/
|
|
8
|
+
export function lastAssistantMessageIsCompleteWithApprovalResponses({
|
|
9
|
+
messages,
|
|
10
|
+
}: {
|
|
11
|
+
messages: UIMessage[];
|
|
12
|
+
}): boolean {
|
|
13
|
+
const message = messages[messages.length - 1];
|
|
14
|
+
|
|
15
|
+
if (!message) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (message.role !== 'assistant') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const lastStepStartIndex = message.parts.reduce((lastIndex, part, index) => {
|
|
24
|
+
return part.type === 'step-start' ? index : lastIndex;
|
|
25
|
+
}, -1);
|
|
26
|
+
|
|
27
|
+
const lastStepToolInvocations = message.parts
|
|
28
|
+
.slice(lastStepStartIndex + 1)
|
|
29
|
+
.filter(isToolUIPart)
|
|
30
|
+
.filter(part => !part.providerExecuted);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
// has at least one tool approval response
|
|
34
|
+
lastStepToolInvocations.filter(part => part.state === 'approval-responded')
|
|
35
|
+
.length > 0 &&
|
|
36
|
+
// all tool approvals must have a response
|
|
37
|
+
lastStepToolInvocations.every(
|
|
38
|
+
part =>
|
|
39
|
+
part.state === 'output-available' ||
|
|
40
|
+
part.state === 'output-error' ||
|
|
41
|
+
part.state === 'approval-responded',
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
}
|