@opencode/ai 2.0.14 → 2.0.16
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 +399 -56
- package/dist/experimental/evaluation-client.d.ts +1 -1
- package/dist/experimental/evaluation-client.js +39 -3
- package/dist/experimental/evaluation.d.ts +4 -4
- package/dist/experimental/evaluation.js +2 -2
- package/dist/experimental/system-one.d.ts +3 -3
- package/dist/experimental/system-one.js +40 -51
- package/dist/generation.d.ts +83 -0
- package/dist/generation.js +113 -0
- package/dist/image-client.d.ts +16 -7
- package/dist/image-client.js +29 -13
- package/dist/image.d.ts +1410 -81
- package/dist/image.js +97 -67
- package/dist/index.d.ts +17 -2
- package/dist/index.js +12 -1
- package/dist/llm.d.ts +9 -1
- package/dist/media-model.d.ts +44 -0
- package/dist/media-model.js +49 -0
- package/dist/media.d.ts +213 -0
- package/dist/media.js +227 -0
- package/dist/promise.d.ts +974 -0
- package/dist/promise.js +81 -0
- package/dist/protocols/alibaba-chat.d.ts +12 -0
- package/dist/protocols/alibaba-responses.d.ts +2 -2
- package/dist/protocols/anthropic-messages.js +8 -19
- package/dist/protocols/assemblyai-transcription.d.ts +40 -0
- package/dist/protocols/assemblyai-transcription.js +138 -0
- package/dist/protocols/bedrock-converse.d.ts +4 -4
- package/dist/protocols/bedrock-converse.js +6 -17
- package/dist/protocols/bfl-images.d.ts +32 -0
- package/dist/protocols/bfl-images.js +153 -0
- package/dist/protocols/cartesia-speech.d.ts +127 -0
- package/dist/protocols/cartesia-speech.js +126 -0
- package/dist/protocols/deepgram-speech.d.ts +119 -0
- package/dist/protocols/deepgram-speech.js +92 -0
- package/dist/protocols/deepgram-transcription.d.ts +25 -0
- package/dist/protocols/deepgram-transcription.js +129 -0
- package/dist/protocols/elevenlabs-speech.d.ts +122 -0
- package/dist/protocols/elevenlabs-speech.js +115 -0
- package/dist/protocols/fal-images.d.ts +24 -0
- package/dist/protocols/fal-images.js +114 -0
- package/dist/protocols/fal-video.d.ts +29 -0
- package/dist/protocols/fal-video.js +88 -0
- package/dist/protocols/gemini.d.ts +30 -9
- package/dist/protocols/gemini.js +45 -35
- package/dist/protocols/google-images.d.ts +9 -21
- package/dist/protocols/google-images.js +158 -133
- package/dist/protocols/google-speech.d.ts +130 -0
- package/dist/protocols/google-speech.js +84 -0
- package/dist/protocols/google-transcription.d.ts +173 -0
- package/dist/protocols/google-transcription.js +138 -0
- package/dist/protocols/google-video.d.ts +26 -0
- package/dist/protocols/google-video.js +158 -0
- package/dist/protocols/meta-images.d.ts +7 -12
- package/dist/protocols/meta-images.js +85 -66
- package/dist/protocols/meta-responses.d.ts +4 -4
- package/dist/protocols/meta-responses.js +1 -1
- package/dist/protocols/mistral-chat.js +7 -6
- package/dist/protocols/open-responses.d.ts +17 -9
- package/dist/protocols/open-responses.js +24 -14
- package/dist/protocols/openai-chat.d.ts +118 -1
- package/dist/protocols/openai-chat.js +125 -44
- package/dist/protocols/openai-compatible-chat.d.ts +12 -0
- package/dist/protocols/openai-compatible-responses.d.ts +2 -2
- package/dist/protocols/openai-images.d.ts +128 -18
- package/dist/protocols/openai-images.js +177 -154
- package/dist/protocols/openai-responses.d.ts +15 -15
- package/dist/protocols/openai-responses.js +5 -6
- package/dist/protocols/openai-speech.d.ts +116 -0
- package/dist/protocols/openai-speech.js +98 -0
- package/dist/protocols/openai-transcription.d.ts +207 -0
- package/dist/protocols/openai-transcription.js +190 -0
- package/dist/protocols/replicate-images.d.ts +28 -0
- package/dist/protocols/replicate-images.js +133 -0
- package/dist/protocols/runway-video.d.ts +38 -0
- package/dist/protocols/runway-video.js +146 -0
- package/dist/protocols/shared.d.ts +27 -17
- package/dist/protocols/shared.js +52 -35
- package/dist/protocols/stability-images.d.ts +38 -0
- package/dist/protocols/stability-images.js +148 -0
- package/dist/protocols/utils/bedrock-media.d.ts +2 -3
- package/dist/protocols/utils/bedrock-media.js +4 -4
- package/dist/protocols/utils/fal-queue.d.ts +28 -0
- package/dist/protocols/utils/fal-queue.js +69 -0
- package/dist/protocols/utils/gemini-generate-content.d.ts +65 -0
- package/dist/protocols/utils/gemini-generate-content.js +65 -0
- package/dist/protocols/utils/gemini-json-schema.d.ts +3 -0
- package/dist/protocols/utils/gemini-json-schema.js +76 -0
- package/dist/protocols/utils/media-input.d.ts +18 -0
- package/dist/protocols/utils/media-input.js +35 -0
- package/dist/protocols/utils/responses-compaction.js +6 -5
- package/dist/protocols/utils/speech-stream.d.ts +49 -0
- package/dist/protocols/utils/speech-stream.js +67 -0
- package/dist/protocols/utils/tool-schema.d.ts +2 -2
- package/dist/protocols/utils/tool-schema.js +40 -17
- package/dist/protocols/utils/tool-stream.d.ts +27 -3
- package/dist/protocols/xai-images.d.ts +9 -15
- package/dist/protocols/xai-images.js +75 -84
- package/dist/protocols/xai-responses.d.ts +2 -2
- package/dist/protocols/xai-video.d.ts +34 -0
- package/dist/protocols/xai-video.js +147 -0
- package/dist/protocols/zai-chat.d.ts +13 -1
- package/dist/protocols/zai-images.d.ts +9 -13
- package/dist/protocols/zai-images.js +59 -57
- package/dist/provider-error.js +3 -0
- package/dist/providers/alibaba.d.ts +14 -2
- package/dist/providers/amazon-bedrock-mantle.d.ts +14 -2
- package/dist/providers/amazon-bedrock.d.ts +2 -2
- package/dist/providers/assemblyai.d.ts +25 -0
- package/dist/providers/assemblyai.js +29 -0
- package/dist/providers/azure.d.ts +18 -6
- package/dist/providers/baseten.d.ts +24 -0
- package/dist/providers/black-forest-labs.d.ts +25 -0
- package/dist/providers/black-forest-labs.js +28 -0
- package/dist/providers/cartesia.d.ts +24 -0
- package/dist/providers/cartesia.js +22 -0
- package/dist/providers/cerebras.d.ts +24 -0
- package/dist/providers/cerebras.js +6 -1
- package/dist/providers/cloudflare-ai-gateway.d.ts +30 -6
- package/dist/providers/cloudflare-workers-ai.d.ts +24 -0
- package/dist/providers/deepgram.d.ts +29 -0
- package/dist/providers/deepgram.js +31 -0
- package/dist/providers/deepinfra.d.ts +24 -0
- package/dist/providers/deepinfra.js +6 -1
- package/dist/providers/deepseek.d.ts +24 -0
- package/dist/providers/elevenlabs.d.ts +24 -0
- package/dist/providers/elevenlabs.js +28 -0
- package/dist/providers/fal.d.ts +29 -0
- package/dist/providers/fal.js +33 -0
- package/dist/providers/fireworks.d.ts +24 -0
- package/dist/providers/google-vertex-chat.d.ts +12 -0
- package/dist/providers/google-vertex-responses.d.ts +2 -2
- package/dist/providers/google-vertex.d.ts +10 -3
- package/dist/providers/google.d.ts +25 -3
- package/dist/providers/google.js +11 -2
- package/dist/providers/groq.d.ts +24 -0
- package/dist/providers/index.d.ts +10 -0
- package/dist/providers/index.js +10 -0
- package/dist/providers/meta.d.ts +14 -2
- package/dist/providers/minimax.d.ts +14 -2
- package/dist/providers/moonshot.d.ts +14 -2
- package/dist/providers/moonshot.js +3 -3
- package/dist/providers/openai-compatible-responses.d.ts +2 -2
- package/dist/providers/openai-compatible.d.ts +12 -0
- package/dist/providers/openai.d.ts +25 -3
- package/dist/providers/openai.js +10 -1
- package/dist/providers/openrouter.d.ts +67 -0
- package/dist/providers/openrouter.js +13 -1
- package/dist/providers/replicate.d.ts +25 -0
- package/dist/providers/replicate.js +22 -0
- package/dist/providers/runway.d.ts +24 -0
- package/dist/providers/runway.js +22 -0
- package/dist/providers/stability.d.ts +28 -0
- package/dist/providers/stability.js +23 -0
- package/dist/providers/togetherai.d.ts +24 -0
- package/dist/providers/vercel-ai-gateway.d.ts +41 -0
- package/dist/providers/vercel-ai-gateway.js +85 -0
- package/dist/providers/xai.d.ts +17 -0
- package/dist/providers/xai.js +5 -2
- package/dist/providers/zai-coding-plan.d.ts +15 -3
- package/dist/providers/zai.d.ts +13 -1
- package/dist/route/auth.d.ts +4 -1
- package/dist/route/auth.js +6 -0
- package/dist/route/client.d.ts +9 -1
- package/dist/route/endpoint.d.ts +10 -10
- package/dist/route/executor-service.d.ts +12 -0
- package/dist/route/executor-service.js +3 -0
- package/dist/route/executor.d.ts +4 -9
- package/dist/route/executor.js +3 -3
- package/dist/route/framing.d.ts +5 -1
- package/dist/route/framing.js +9 -0
- package/dist/route/index.d.ts +2 -0
- package/dist/route/index.js +2 -0
- package/dist/route/media-protocol.d.ts +158 -0
- package/dist/route/media-protocol.js +96 -0
- package/dist/route/media.d.ts +97 -0
- package/dist/route/media.js +236 -0
- package/dist/schema/errors.d.ts +13 -3
- package/dist/schema/errors.js +7 -0
- package/dist/schema/events.d.ts +557 -40
- package/dist/schema/events.js +35 -2
- package/dist/schema/messages.d.ts +95 -8
- package/dist/schema/messages.js +8 -6
- package/dist/schema/options.d.ts +6 -3
- package/dist/schema/options.js +6 -2
- package/dist/speech-client.d.ts +21 -0
- package/dist/speech-client.js +25 -0
- package/dist/speech.d.ts +1150 -0
- package/dist/speech.js +119 -0
- package/dist/testing.d.ts +72 -8
- package/dist/transcription-client.d.ts +28 -0
- package/dist/transcription-client.js +44 -0
- package/dist/transcription.d.ts +1504 -0
- package/dist/transcription.js +133 -0
- package/dist/utils/bytes.d.ts +1 -0
- package/dist/utils/bytes.js +10 -0
- package/dist/utils/media-type.d.ts +7 -0
- package/dist/utils/media-type.js +70 -0
- package/dist/utils/sanitize.js +3 -1
- package/dist/video-client.d.ts +28 -0
- package/dist/video-client.js +40 -0
- package/dist/video.d.ts +1359 -0
- package/dist/video.js +119 -0
- package/package.json +7 -3
- package/dist/protocols/utils/gemini-tool-schema.d.ts +0 -2
- package/dist/protocols/utils/gemini-tool-schema.js +0 -103
- package/dist/protocols/utils/image-input.d.ts +0 -21
- package/dist/protocols/utils/image-input.js +0 -20
package/dist/promise.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Effect, Layer, ManagedRuntime, Stream } from "effect";
|
|
2
|
+
import { Image, ImageModel, ImageRequest } from "./image.js";
|
|
3
|
+
import { ImageClient } from "./image-client.js";
|
|
4
|
+
import { LLM } from "./index.js";
|
|
5
|
+
import { LLMClient } from "./route/client.js";
|
|
6
|
+
import { RequestExecutor } from "./route/executor.js";
|
|
7
|
+
import { LanguageModel, LLMRequest } from "./schema/index.js";
|
|
8
|
+
import { Speech, SpeechModel, SpeechRequest } from "./speech.js";
|
|
9
|
+
import { SpeechClient } from "./speech-client.js";
|
|
10
|
+
import { Transcription, TranscriptionModel, TranscriptionRequest, } from "./transcription.js";
|
|
11
|
+
import { TranscriptionClient } from "./transcription-client.js";
|
|
12
|
+
import { Video, VideoModel, VideoRequest } from "./video.js";
|
|
13
|
+
import { VideoClient } from "./video-client.js";
|
|
14
|
+
const abortEffect = (signal) => signal === undefined
|
|
15
|
+
? Effect.never
|
|
16
|
+
: Effect.callback((resume) => {
|
|
17
|
+
if (signal.aborted) {
|
|
18
|
+
resume(Effect.void);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const onAbort = () => resume(Effect.void);
|
|
22
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
23
|
+
return Effect.sync(() => signal.removeEventListener("abort", onAbort));
|
|
24
|
+
});
|
|
25
|
+
export const make = (options = {}) => {
|
|
26
|
+
const runtime = ManagedRuntime.make(Layer.mergeAll(LLMClient.layer, ImageClient.layer, VideoClient.layer, SpeechClient.layer, TranscriptionClient.layer).pipe(Layer.provideMerge(options.layer ?? RequestExecutor.fetchLayer)));
|
|
27
|
+
/** Run any package Effect (for example `asset.bytes()`) inside this runtime. */
|
|
28
|
+
const run = (effect, options) => runtime.runPromise(effect, { signal: options?.signal });
|
|
29
|
+
const iterate = (stream, options) => Stream.toAsyncIterable(Stream.unwrap(runtime.contextEffect.pipe(Effect.map((context) => stream.pipe(Stream.interruptWhen(abortEffect(options?.signal)), Stream.provideContext(context))))));
|
|
30
|
+
const handle = (generation) => ({
|
|
31
|
+
...generation.snapshot,
|
|
32
|
+
token: generation.token,
|
|
33
|
+
await: (options) => run(generation.await({ poll: options?.poll }), options),
|
|
34
|
+
refresh: (options) => run(generation.refresh(), options).then(handle),
|
|
35
|
+
cancel: (options) => run(generation.cancel(), options),
|
|
36
|
+
});
|
|
37
|
+
// The typed `generate`/`stream` overloads take a concrete input or a request, not the union; normalize once here.
|
|
38
|
+
const llmRequest = (input) => (input instanceof LLMRequest ? input : LLM.request(input));
|
|
39
|
+
const imageRequest = (input) => input instanceof ImageRequest ? input : Image.request(input);
|
|
40
|
+
const videoRequest = (input) => input instanceof VideoRequest ? input : Video.request(input);
|
|
41
|
+
const speechRequest = (input) => input instanceof SpeechRequest ? input : Speech.request(input);
|
|
42
|
+
const transcriptionRequest = (input) => input instanceof TranscriptionRequest ? input : Transcription.request(input);
|
|
43
|
+
return {
|
|
44
|
+
run,
|
|
45
|
+
llm: {
|
|
46
|
+
request: LLM.request,
|
|
47
|
+
generate: (input, options) => run(LLM.generate(llmRequest(input)), options),
|
|
48
|
+
stream: (input, options) => iterate(LLM.stream(llmRequest(input)), options),
|
|
49
|
+
},
|
|
50
|
+
image: {
|
|
51
|
+
request: Image.request,
|
|
52
|
+
generate: (input, options) => run(Image.generate(imageRequest(input), { poll: options?.poll }), options),
|
|
53
|
+
stream: (input, options) => iterate(Image.stream(imageRequest(input), { poll: options?.poll }), options),
|
|
54
|
+
start: (input, options) => run(Image.start(imageRequest(input)), options).then(handle),
|
|
55
|
+
resume: (model, token, options) => run(Image.resume(model, token), options).then(handle),
|
|
56
|
+
},
|
|
57
|
+
video: {
|
|
58
|
+
request: Video.request,
|
|
59
|
+
start: (input, options) => run(Video.start(videoRequest(input)), options).then(handle),
|
|
60
|
+
generate: (input, options) => run(Video.generate(videoRequest(input), { poll: options?.poll }), options),
|
|
61
|
+
resume: (model, token, options) => run(Video.resume(model, token), options).then(handle),
|
|
62
|
+
stream: (input, options) => iterate(Video.stream(videoRequest(input), { poll: options?.poll }), options),
|
|
63
|
+
},
|
|
64
|
+
speech: {
|
|
65
|
+
request: Speech.request,
|
|
66
|
+
generate: (input, options) => run(Speech.generate(speechRequest(input)), options),
|
|
67
|
+
stream: (input, options) => iterate(Speech.stream(speechRequest(input)), options),
|
|
68
|
+
},
|
|
69
|
+
transcription: {
|
|
70
|
+
request: Transcription.request,
|
|
71
|
+
generate: (input, options) => run(Transcription.generate(transcriptionRequest(input), { poll: options?.poll }), options),
|
|
72
|
+
stream: (input, options) => iterate(Transcription.stream(transcriptionRequest(input), { poll: options?.poll }), options),
|
|
73
|
+
start: (input, options) => run(Transcription.start(transcriptionRequest(input)), options).then(handle),
|
|
74
|
+
resume: (model, token, options) => run(Transcription.resume(model, token), options).then(handle),
|
|
75
|
+
},
|
|
76
|
+
dispose: () => runtime.dispose(),
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
/** Default client over `RequestExecutor.fetchLayer` for scripts; the runtime builds its layer on first use. */
|
|
80
|
+
export const ai = make();
|
|
81
|
+
export * as AI from "./promise.js";
|
|
@@ -50,6 +50,12 @@ export declare const protocol: Protocol<{
|
|
|
50
50
|
readonly image_url: {
|
|
51
51
|
readonly url: string;
|
|
52
52
|
};
|
|
53
|
+
} | {
|
|
54
|
+
readonly type: "file";
|
|
55
|
+
readonly file: {
|
|
56
|
+
readonly filename: string;
|
|
57
|
+
readonly file_data: string;
|
|
58
|
+
};
|
|
53
59
|
})[];
|
|
54
60
|
} | {
|
|
55
61
|
readonly role: "user";
|
|
@@ -65,6 +71,12 @@ export declare const protocol: Protocol<{
|
|
|
65
71
|
readonly image_url: {
|
|
66
72
|
readonly url: string;
|
|
67
73
|
};
|
|
74
|
+
} | {
|
|
75
|
+
readonly type: "file";
|
|
76
|
+
readonly file: {
|
|
77
|
+
readonly filename: string;
|
|
78
|
+
readonly file_data: string;
|
|
79
|
+
};
|
|
68
80
|
})[];
|
|
69
81
|
} | {
|
|
70
82
|
readonly [x: string]: unknown;
|
|
@@ -77,8 +77,8 @@ export declare const protocol: Protocol<{
|
|
|
77
77
|
} | {
|
|
78
78
|
readonly type: "input_file";
|
|
79
79
|
readonly filename: string;
|
|
80
|
-
readonly detail?: string | undefined;
|
|
81
80
|
readonly file_data?: string | undefined;
|
|
81
|
+
readonly detail?: string | undefined;
|
|
82
82
|
readonly file_url?: string | undefined;
|
|
83
83
|
} | {
|
|
84
84
|
readonly type: "input_text";
|
|
@@ -114,8 +114,8 @@ export declare const protocol: Protocol<{
|
|
|
114
114
|
} | {
|
|
115
115
|
readonly type: "input_file";
|
|
116
116
|
readonly filename: string;
|
|
117
|
-
readonly detail?: string | undefined;
|
|
118
117
|
readonly file_data?: string | undefined;
|
|
118
|
+
readonly detail?: string | undefined;
|
|
119
119
|
readonly file_url?: string | undefined;
|
|
120
120
|
} | {
|
|
121
121
|
readonly type: "input_text";
|
|
@@ -537,7 +537,7 @@ const citationsFromMetadata = (metadata) => {
|
|
|
537
537
|
};
|
|
538
538
|
const isHttpUrl = (value) => /^https?:\/\//i.test(value.trim());
|
|
539
539
|
const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part, breakpoints) {
|
|
540
|
-
const mime = part.mediaType.toLowerCase();
|
|
540
|
+
const mime = part.media.mediaType.toLowerCase();
|
|
541
541
|
const cacheControlValue = breakpoints ? cacheControl(breakpoints, part.cache) : undefined;
|
|
542
542
|
const fileId = fileIdFromMetadata(part.metadata);
|
|
543
543
|
// SDK file sources: FileImageSource:2350 / FileDocumentSource:2344 {type:"file", file_id}
|
|
@@ -564,9 +564,9 @@ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part, br
|
|
|
564
564
|
: { citations: citationsFromMetadata(part.metadata) }),
|
|
565
565
|
};
|
|
566
566
|
}
|
|
567
|
-
const rawString =
|
|
567
|
+
const rawString = ProviderShared.mediaUrl(part.media)?.trim();
|
|
568
568
|
// SDK URL sources: URLImageSource:3817 / URLPDFSource:3823 {type:"url", url}
|
|
569
|
-
if (rawString && isHttpUrl(rawString)
|
|
569
|
+
if (rawString && isHttpUrl(rawString)) {
|
|
570
570
|
if (mime.startsWith("image/"))
|
|
571
571
|
return {
|
|
572
572
|
type: "image",
|
|
@@ -590,19 +590,10 @@ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part, br
|
|
|
590
590
|
: { citations: citationsFromMetadata(part.metadata) }),
|
|
591
591
|
};
|
|
592
592
|
}
|
|
593
|
+
const media = yield* ProviderShared.requireInlineMedia("Anthropic Messages", part.media);
|
|
593
594
|
// SDK PlainTextSource:2716 {type:"text", media_type:"text/plain", data}
|
|
594
595
|
if (mime === "text/plain") {
|
|
595
|
-
const textData =
|
|
596
|
-
? Buffer.from(part.data).toString("utf8")
|
|
597
|
-
: part.data.startsWith("data:")
|
|
598
|
-
? (() => {
|
|
599
|
-
const comma = part.data.indexOf(",");
|
|
600
|
-
const payload = comma >= 0 ? part.data.slice(comma + 1) : part.data;
|
|
601
|
-
return part.data.includes(";base64")
|
|
602
|
-
? Buffer.from(payload, "base64").toString("utf8")
|
|
603
|
-
: decodeURIComponent(payload);
|
|
604
|
-
})()
|
|
605
|
-
: part.data;
|
|
596
|
+
const textData = Buffer.from(media.base64, "base64").toString("utf8");
|
|
606
597
|
return {
|
|
607
598
|
type: "document",
|
|
608
599
|
source: { type: "text", media_type: "text/plain", data: textData },
|
|
@@ -616,7 +607,6 @@ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part, br
|
|
|
616
607
|
: { citations: citationsFromMetadata(part.metadata) }),
|
|
617
608
|
};
|
|
618
609
|
}
|
|
619
|
-
const media = ProviderShared.normalizeMedia(part);
|
|
620
610
|
if (media.mime === "application/pdf")
|
|
621
611
|
return {
|
|
622
612
|
type: "document",
|
|
@@ -635,7 +625,7 @@ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part, br
|
|
|
635
625
|
: { citations: citationsFromMetadata(part.metadata) }),
|
|
636
626
|
};
|
|
637
627
|
if (!media.mime.startsWith("image/"))
|
|
638
|
-
return yield* invalid(`Anthropic Messages does not support media type ${part.mediaType}`);
|
|
628
|
+
return yield* invalid(`Anthropic Messages does not support media type ${part.media.mediaType}`);
|
|
639
629
|
return {
|
|
640
630
|
type: "image",
|
|
641
631
|
source: {
|
|
@@ -654,7 +644,7 @@ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part, br
|
|
|
654
644
|
const lowerToolResultContentItem = Effect.fnUntraced(function* (item) {
|
|
655
645
|
if (item.type === "text")
|
|
656
646
|
return { type: "text", text: item.text };
|
|
657
|
-
return yield* lowerMedia(
|
|
647
|
+
return yield* lowerMedia(ProviderShared.toolFileMedia(item));
|
|
658
648
|
});
|
|
659
649
|
const lowerToolResultContent = Effect.fnUntraced(function* (part) {
|
|
660
650
|
// Text / json / error results stay as a string for backward compatibility
|
|
@@ -907,7 +897,6 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
|
|
|
907
897
|
const format = outputConfig?.format ?? undefined;
|
|
908
898
|
const updates = resolveEffortUpdates(request, options.effort ?? outputConfig?.effort ?? undefined);
|
|
909
899
|
const generation = request.generation;
|
|
910
|
-
const toolSchemaCompatibility = request.model.compatibility?.toolSchema;
|
|
911
900
|
// Allocate the 4-breakpoint budget in invalidation order: tools → system →
|
|
912
901
|
// messages. Tools live highest in the cache hierarchy, so when callers
|
|
913
902
|
// over-mark we keep their tool hints and shed the message-tail ones first.
|
|
@@ -915,7 +904,7 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
|
|
|
915
904
|
const flattened = ProviderShared.flattenToolRequest(updates.request);
|
|
916
905
|
const tools = flattened.tools.length === 0
|
|
917
906
|
? undefined
|
|
918
|
-
: flattened.tools.map((tool) => lowerTool(breakpoints, tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema,
|
|
907
|
+
: flattened.tools.map((tool) => lowerTool(breakpoints, tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, request.model)));
|
|
919
908
|
// Anthropic rejects tool_choice when tools are absent; "none" is only meaningful with tools present.
|
|
920
909
|
const toolChoice = tools === undefined || !request.toolChoice ? undefined : yield* lowerToolChoice(request.toolChoice);
|
|
921
910
|
const systemParts = request.system.filter((part) => part.text.length > 0);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
3
|
+
import { MediaRoute } from "../route/media.js";
|
|
4
|
+
import { TranscriptionModel, TranscriptionResponse, type TranscriptionRequestFor } from "../transcription.js";
|
|
5
|
+
export declare const DEFAULT_BASE_URL = "https://api.assemblyai.com";
|
|
6
|
+
export declare const PATH = "/v2/transcript";
|
|
7
|
+
export declare const UPLOAD_PATH = "/v2/upload";
|
|
8
|
+
export type AssemblyAITranscriptionOptions = {
|
|
9
|
+
readonly keyterms_prompt?: ReadonlyArray<string>;
|
|
10
|
+
readonly punctuate?: boolean;
|
|
11
|
+
readonly format_text?: boolean;
|
|
12
|
+
readonly disfluencies?: boolean;
|
|
13
|
+
readonly filter_profanity?: boolean;
|
|
14
|
+
readonly temperature?: number;
|
|
15
|
+
readonly speaker_options?: {
|
|
16
|
+
readonly min_speakers_expected?: number;
|
|
17
|
+
readonly max_speakers_expected?: number;
|
|
18
|
+
};
|
|
19
|
+
readonly language_detection_options?: {
|
|
20
|
+
readonly expected_languages?: ReadonlyArray<string>;
|
|
21
|
+
readonly fallback_language?: string;
|
|
22
|
+
readonly code_switching?: boolean;
|
|
23
|
+
};
|
|
24
|
+
readonly speech_models?: ReadonlyArray<"universal-3-5-pro" | "universal-2" | (string & {})>;
|
|
25
|
+
} & Record<string, unknown>;
|
|
26
|
+
export type Request = TranscriptionRequestFor<AssemblyAITranscriptionOptions>;
|
|
27
|
+
export declare const Token: Schema.Struct<{
|
|
28
|
+
readonly transcriptID: Schema.String;
|
|
29
|
+
}>;
|
|
30
|
+
export type Token = Schema.Schema.Type<typeof Token>;
|
|
31
|
+
export declare const protocol: MediaProtocol.Queued<Request, TranscriptionResponse, {
|
|
32
|
+
readonly transcriptID: string;
|
|
33
|
+
}>;
|
|
34
|
+
export declare const model: (input: MediaRoute.ModelInput) => TranscriptionModel<AssemblyAITranscriptionOptions>;
|
|
35
|
+
export declare const AssemblyAITranscription: {
|
|
36
|
+
readonly protocol: MediaProtocol.Queued<Request, TranscriptionResponse, {
|
|
37
|
+
readonly transcriptID: string;
|
|
38
|
+
}>;
|
|
39
|
+
readonly model: (input: MediaRoute.ModelInput) => TranscriptionModel<AssemblyAITranscriptionOptions>;
|
|
40
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { Media } from "../media.js";
|
|
3
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
4
|
+
import { MediaRoute } from "../route/media.js";
|
|
5
|
+
import { ProviderID, mergeJsonRecords } from "../schema/index.js";
|
|
6
|
+
import { TranscriptionModel, TranscriptionResponse } from "../transcription.js";
|
|
7
|
+
import { ProviderShared, optionalNull } from "./shared.js";
|
|
8
|
+
import { MediaInput } from "./utils/media-input.js";
|
|
9
|
+
const ADAPTER = "assemblyai-transcription";
|
|
10
|
+
const NAME = "AssemblyAI";
|
|
11
|
+
const PROVIDER = ProviderID.make("assemblyai");
|
|
12
|
+
export const DEFAULT_BASE_URL = "https://api.assemblyai.com";
|
|
13
|
+
export const PATH = "/v2/transcript";
|
|
14
|
+
export const UPLOAD_PATH = "/v2/upload";
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// 2. Token and response schemas
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
export const Token = Schema.Struct({ transcriptID: Schema.String });
|
|
19
|
+
const Upload = Schema.Struct({ upload_url: Schema.String });
|
|
20
|
+
/** Word and utterance times are milliseconds. */
|
|
21
|
+
const Transcript = Schema.Struct({
|
|
22
|
+
id: Schema.String,
|
|
23
|
+
status: Schema.String,
|
|
24
|
+
text: optionalNull(Schema.String),
|
|
25
|
+
words: optionalNull(Schema.Array(Schema.Struct({
|
|
26
|
+
text: Schema.String,
|
|
27
|
+
start: Schema.Number,
|
|
28
|
+
end: Schema.Number,
|
|
29
|
+
confidence: optionalNull(Schema.Number),
|
|
30
|
+
speaker: optionalNull(Schema.String),
|
|
31
|
+
}))),
|
|
32
|
+
utterances: optionalNull(Schema.Array(Schema.Struct({
|
|
33
|
+
text: Schema.String,
|
|
34
|
+
start: Schema.Number,
|
|
35
|
+
end: Schema.Number,
|
|
36
|
+
speaker: optionalNull(Schema.String),
|
|
37
|
+
}))),
|
|
38
|
+
language_code: optionalNull(Schema.String),
|
|
39
|
+
audio_duration: optionalNull(Schema.Number),
|
|
40
|
+
speech_model_used: optionalNull(Schema.String),
|
|
41
|
+
error: optionalNull(Schema.String),
|
|
42
|
+
});
|
|
43
|
+
const STATUS = {
|
|
44
|
+
queued: "queued",
|
|
45
|
+
processing: "running",
|
|
46
|
+
completed: "completed",
|
|
47
|
+
error: "failed",
|
|
48
|
+
};
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// 5. Request body construction
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
const decodeUpload = MediaProtocol.decodeJson(ADAPTER, NAME, Upload);
|
|
53
|
+
/** `/v2/transcript` only takes a URL, so inline audio is uploaded to `/v2/upload` first. */
|
|
54
|
+
const prepare = Effect.fn("AssemblyAITranscription.prepare")(function* (request, send) {
|
|
55
|
+
if (request.audio.source.type !== "bytes" && request.audio.source.type !== "base64")
|
|
56
|
+
return request;
|
|
57
|
+
const audio = yield* MediaInput.inlineBytes(ADAPTER, request.audio);
|
|
58
|
+
const uploaded = yield* send(UPLOAD_PATH, MediaProtocol.binary(audio, "application/octet-stream")).pipe(Effect.flatMap(decodeUpload));
|
|
59
|
+
return { ...request, audio: Media.url(uploaded.value.upload_url, { mediaType: request.audio.mediaType }) };
|
|
60
|
+
});
|
|
61
|
+
const fromRequest = Effect.fn("AssemblyAITranscription.fromRequest")(function* (request) {
|
|
62
|
+
const audio = yield* ProviderShared.mediaReference(request.audio, PROVIDER, NAME);
|
|
63
|
+
return MediaProtocol.json(mergeJsonRecords({
|
|
64
|
+
audio_url: audio.value,
|
|
65
|
+
speech_models: [request.model.id],
|
|
66
|
+
language_code: request.language,
|
|
67
|
+
language_detection: request.language === undefined ? true : undefined,
|
|
68
|
+
prompt: request.prompt,
|
|
69
|
+
// Turn-level `utterances`, the only segments AssemblyAI returns, require speaker labels.
|
|
70
|
+
speaker_labels: request.diarize === true || request.timestamps === "segment" ? true : undefined,
|
|
71
|
+
speakers_expected: request.speakers,
|
|
72
|
+
}, request.providerOptions, request.http?.body) ?? {});
|
|
73
|
+
});
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// 6. Response decoding
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
const decodeTranscript = MediaProtocol.decodeJson(ADAPTER, NAME, Transcript);
|
|
78
|
+
const decodeStart = Effect.fn("AssemblyAITranscription.decodeStart")(function* (response) {
|
|
79
|
+
const output = yield* decodeTranscript(response);
|
|
80
|
+
const status = yield* MediaProtocol.status(STATUS, output.value.status, output);
|
|
81
|
+
return { token: { transcriptID: output.value.id }, snapshot: { id: output.value.id, status } };
|
|
82
|
+
});
|
|
83
|
+
const decodeStatus = Effect.fn("AssemblyAITranscription.decodeStatus")(function* (response, context) {
|
|
84
|
+
const output = yield* decodeTranscript(response);
|
|
85
|
+
const status = yield* MediaProtocol.status(STATUS, output.value.status, output);
|
|
86
|
+
return { id: context.token.transcriptID, status };
|
|
87
|
+
});
|
|
88
|
+
const seconds = (milliseconds) => milliseconds / 1000;
|
|
89
|
+
const decodeResult = Effect.fn("AssemblyAITranscription.decodeResult")(function* (response, context) {
|
|
90
|
+
const output = yield* decodeTranscript(response);
|
|
91
|
+
const transcript = output.value;
|
|
92
|
+
const status = yield* MediaProtocol.status(STATUS, transcript.status, output);
|
|
93
|
+
const error = transcript.error ?? undefined;
|
|
94
|
+
if (status === "failed")
|
|
95
|
+
return yield* output.ended("failed", `${NAME} transcription failed${error === undefined ? "" : `: ${error}`}`);
|
|
96
|
+
if (status !== "completed")
|
|
97
|
+
return yield* output.invalid(`${NAME} transcript ${context.token.transcriptID} has not finished`);
|
|
98
|
+
const duration = transcript.audio_duration ?? undefined;
|
|
99
|
+
return new TranscriptionResponse({
|
|
100
|
+
text: transcript.text ?? "",
|
|
101
|
+
segments: transcript.utterances?.map((utterance) => ({
|
|
102
|
+
text: utterance.text,
|
|
103
|
+
startSeconds: seconds(utterance.start),
|
|
104
|
+
endSeconds: seconds(utterance.end),
|
|
105
|
+
speaker: utterance.speaker ?? undefined,
|
|
106
|
+
})),
|
|
107
|
+
words: transcript.words?.map((word) => ({
|
|
108
|
+
text: word.text,
|
|
109
|
+
startSeconds: seconds(word.start),
|
|
110
|
+
endSeconds: seconds(word.end),
|
|
111
|
+
speaker: word.speaker ?? undefined,
|
|
112
|
+
confidence: word.confidence ?? undefined,
|
|
113
|
+
})),
|
|
114
|
+
language: transcript.language_code?.toLowerCase(),
|
|
115
|
+
durationSeconds: duration,
|
|
116
|
+
usage: duration === undefined ? undefined : { type: "seconds", seconds: duration },
|
|
117
|
+
providerMetadata: {
|
|
118
|
+
assemblyai: { transcriptId: transcript.id, speechModel: transcript.speech_model_used ?? undefined },
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// 7. Protocol and route
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
const transcriptPath = (token) => `${PATH}/${token.transcriptID}`;
|
|
126
|
+
export const protocol = MediaProtocol.queued({
|
|
127
|
+
id: ADAPTER,
|
|
128
|
+
name: NAME,
|
|
129
|
+
token: Token,
|
|
130
|
+
start: { prepare, body: { from: fromRequest }, decode: decodeStart },
|
|
131
|
+
status: { path: transcriptPath, decode: decodeStatus },
|
|
132
|
+
result: { path: transcriptPath, decode: decodeResult },
|
|
133
|
+
});
|
|
134
|
+
export const model = (input) => TranscriptionModel.fromRoute({ id: ADAPTER, provider: PROVIDER, protocol, baseURL: DEFAULT_BASE_URL, path: PATH }, input);
|
|
135
|
+
export const AssemblyAITranscription = {
|
|
136
|
+
protocol,
|
|
137
|
+
model,
|
|
138
|
+
};
|
|
@@ -157,7 +157,7 @@ export declare const protocol: Protocol<{
|
|
|
157
157
|
};
|
|
158
158
|
} | {
|
|
159
159
|
readonly document: {
|
|
160
|
-
readonly format: "pdf" | "
|
|
160
|
+
readonly format: "pdf" | "txt" | "md" | "csv" | "doc" | "docx" | "xls" | "xlsx" | "html";
|
|
161
161
|
readonly name: string;
|
|
162
162
|
readonly source: {
|
|
163
163
|
readonly bytes: string;
|
|
@@ -176,7 +176,7 @@ export declare const protocol: Protocol<{
|
|
|
176
176
|
};
|
|
177
177
|
} | {
|
|
178
178
|
readonly document: {
|
|
179
|
-
readonly format: "pdf" | "
|
|
179
|
+
readonly format: "pdf" | "txt" | "md" | "csv" | "doc" | "docx" | "xls" | "xlsx" | "html";
|
|
180
180
|
readonly name: string;
|
|
181
181
|
readonly source: {
|
|
182
182
|
readonly bytes: string;
|
|
@@ -386,7 +386,7 @@ export declare const route: Route<{
|
|
|
386
386
|
};
|
|
387
387
|
} | {
|
|
388
388
|
readonly document: {
|
|
389
|
-
readonly format: "pdf" | "
|
|
389
|
+
readonly format: "pdf" | "txt" | "md" | "csv" | "doc" | "docx" | "xls" | "xlsx" | "html";
|
|
390
390
|
readonly name: string;
|
|
391
391
|
readonly source: {
|
|
392
392
|
readonly bytes: string;
|
|
@@ -405,7 +405,7 @@ export declare const route: Route<{
|
|
|
405
405
|
};
|
|
406
406
|
} | {
|
|
407
407
|
readonly document: {
|
|
408
|
-
readonly format: "pdf" | "
|
|
408
|
+
readonly format: "pdf" | "txt" | "md" | "csv" | "doc" | "docx" | "xls" | "xlsx" | "html";
|
|
409
409
|
readonly name: string;
|
|
410
410
|
readonly source: {
|
|
411
411
|
readonly bytes: string;
|
|
@@ -13,6 +13,7 @@ import { Lifecycle } from "./utils/lifecycle.js";
|
|
|
13
13
|
import { MistralToolID } from "./utils/mistral-tool-id.js";
|
|
14
14
|
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
15
15
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
16
|
+
import { concatBytes } from "../utils/bytes.js";
|
|
16
17
|
const ADAPTER = "bedrock-converse";
|
|
17
18
|
// =============================================================================
|
|
18
19
|
// Request Body Schema
|
|
@@ -162,10 +163,10 @@ const lowerToolSpec = (tool, inputSchema) => ({
|
|
|
162
163
|
inputSchema: { json: inputSchema },
|
|
163
164
|
},
|
|
164
165
|
});
|
|
165
|
-
const lowerTools = (
|
|
166
|
+
const lowerTools = (model, breakpoints, tools) => {
|
|
166
167
|
const result = [];
|
|
167
168
|
for (const tool of tools) {
|
|
168
|
-
result.push(lowerToolSpec(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema,
|
|
169
|
+
result.push(lowerToolSpec(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, model)));
|
|
169
170
|
const cachePoint = BedrockCache.block(breakpoints, tool.cache);
|
|
170
171
|
if (cachePoint)
|
|
171
172
|
result.push(cachePoint);
|
|
@@ -221,12 +222,7 @@ const lowerToolResultContent = Effect.fn("BedrockConverse.lowerToolResultContent
|
|
|
221
222
|
content.push({ text: item.text });
|
|
222
223
|
continue;
|
|
223
224
|
}
|
|
224
|
-
const media = yield* BedrockMedia.lower(
|
|
225
|
-
type: "media",
|
|
226
|
-
mediaType: item.mime,
|
|
227
|
-
data: item.uri,
|
|
228
|
-
filename: item.name,
|
|
229
|
-
}, documentNames);
|
|
225
|
+
const media = yield* BedrockMedia.lower(ProviderShared.toolFileMedia(item), documentNames);
|
|
230
226
|
content.push(...media);
|
|
231
227
|
}
|
|
232
228
|
return content;
|
|
@@ -353,7 +349,7 @@ const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request)
|
|
|
353
349
|
if (flattened.tools.length === 0)
|
|
354
350
|
return undefined;
|
|
355
351
|
return {
|
|
356
|
-
tools: lowerTools(request.model
|
|
352
|
+
tools: lowerTools(request.model, breakpoints, flattened.tools),
|
|
357
353
|
// Converse has no native "none". Keep definitions stable for prompt
|
|
358
354
|
// caching and omit only the unsupported choice.
|
|
359
355
|
toolChoice,
|
|
@@ -418,14 +414,7 @@ const mapUsage = (usage, providerMetadataKey) => {
|
|
|
418
414
|
providerMetadata: { [providerMetadataKey]: usage },
|
|
419
415
|
});
|
|
420
416
|
};
|
|
421
|
-
const encodeRedactedContent = (chunks) =>
|
|
422
|
-
const bytes = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.length, 0));
|
|
423
|
-
chunks.reduce((offset, chunk) => {
|
|
424
|
-
bytes.set(chunk, offset);
|
|
425
|
-
return offset + chunk.length;
|
|
426
|
-
}, 0);
|
|
427
|
-
return Encoding.encodeBase64(bytes);
|
|
428
|
-
};
|
|
417
|
+
const encodeRedactedContent = (chunks) => Encoding.encodeBase64(concatBytes(chunks));
|
|
429
418
|
const step = (state, event) => Effect.gen(function* () {
|
|
430
419
|
if (event.contentBlockStart?.start?.toolUse) {
|
|
431
420
|
const index = event.contentBlockStart.contentBlockIndex;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js";
|
|
3
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
4
|
+
import { MediaRoute } from "../route/media.js";
|
|
5
|
+
export declare const DEFAULT_BASE_URL = "https://api.bfl.ai";
|
|
6
|
+
export type BlackForestLabsImageOptions = {
|
|
7
|
+
readonly safety_tolerance?: number;
|
|
8
|
+
readonly prompt_upsampling?: boolean;
|
|
9
|
+
readonly disable_pup?: boolean;
|
|
10
|
+
readonly raw?: boolean;
|
|
11
|
+
readonly guidance?: number;
|
|
12
|
+
readonly steps?: number;
|
|
13
|
+
} & Record<string, unknown>;
|
|
14
|
+
export type Request = ImageRequestFor<BlackForestLabsImageOptions>;
|
|
15
|
+
/** Regional clusters answer on different hosts, so the returned `polling_url` is followed verbatim. */
|
|
16
|
+
export declare const Token: Schema.Struct<{
|
|
17
|
+
readonly id: Schema.String;
|
|
18
|
+
readonly pollingURL: Schema.String;
|
|
19
|
+
}>;
|
|
20
|
+
export type Token = Schema.Schema.Type<typeof Token>;
|
|
21
|
+
export declare const protocol: MediaProtocol.Queued<Request, ImageResponse, {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly pollingURL: string;
|
|
24
|
+
}>;
|
|
25
|
+
export declare const model: (input: MediaRoute.ModelInput) => ImageModel<BlackForestLabsImageOptions>;
|
|
26
|
+
export declare const BlackForestLabsImages: {
|
|
27
|
+
readonly protocol: MediaProtocol.Queued<Request, ImageResponse, {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly pollingURL: string;
|
|
30
|
+
}>;
|
|
31
|
+
readonly model: (input: MediaRoute.ModelInput) => ImageModel<BlackForestLabsImageOptions>;
|
|
32
|
+
};
|