@opencode/ai 2.0.15 → 2.0.17
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 +441 -99
- package/dist/ai-client.d.ts +8 -0
- package/dist/ai-client.js +12 -0
- package/dist/experimental/evaluation-client.d.ts +3 -3
- package/dist/experimental/evaluation-client.js +1 -1
- package/dist/experimental/evaluation.js +1 -1
- package/dist/generation.d.ts +39 -29
- package/dist/generation.js +62 -36
- package/dist/image-client.d.ts +59 -17
- package/dist/image-client.js +16 -24
- package/dist/image.d.ts +394 -55
- package/dist/image.js +48 -57
- package/dist/index.d.ts +15 -2
- package/dist/index.js +10 -0
- package/dist/llm.d.ts +7 -5
- package/dist/llm.js +10 -4
- package/dist/media-client.d.ts +30 -0
- package/dist/media-client.js +51 -0
- package/dist/media-model.d.ts +43 -0
- package/dist/media-model.js +47 -0
- package/dist/media.d.ts +10 -9
- package/dist/media.js +11 -12
- package/dist/promise.d.ts +473 -15
- package/dist/promise.js +71 -13
- package/dist/protocols/alibaba-chat.d.ts +12 -0
- package/dist/protocols/alibaba-chat.js +4 -1
- package/dist/protocols/alibaba-messages.d.ts +1 -1
- package/dist/protocols/alibaba-messages.js +6 -4
- package/dist/protocols/alibaba-responses.d.ts +2 -2
- package/dist/protocols/anthropic-messages.d.ts +34 -34
- package/dist/protocols/anthropic-messages.js +14 -9
- package/dist/protocols/assemblyai-transcription.d.ts +41 -0
- package/dist/protocols/assemblyai-transcription.js +136 -0
- package/dist/protocols/bedrock-converse.d.ts +7 -0
- package/dist/protocols/bedrock-converse.js +39 -19
- package/dist/protocols/bfl-images.d.ts +38 -0
- package/dist/protocols/bfl-images.js +153 -0
- package/dist/protocols/cartesia-speech.d.ts +143 -0
- package/dist/protocols/cartesia-speech.js +120 -0
- package/dist/protocols/deepgram-speech.d.ts +135 -0
- package/dist/protocols/deepgram-speech.js +91 -0
- package/dist/protocols/deepgram-transcription.d.ts +26 -0
- package/dist/protocols/deepgram-transcription.js +125 -0
- package/dist/protocols/elevenlabs-speech.d.ts +138 -0
- package/dist/protocols/elevenlabs-speech.js +111 -0
- package/dist/protocols/fal-images.d.ts +25 -0
- package/dist/protocols/fal-images.js +104 -0
- package/dist/protocols/fal-video.d.ts +29 -0
- package/dist/protocols/fal-video.js +73 -0
- package/dist/protocols/gemini.d.ts +22 -22
- package/dist/protocols/gemini.js +19 -36
- package/dist/protocols/google-images.d.ts +3 -3
- package/dist/protocols/google-images.js +12 -34
- package/dist/protocols/google-speech.d.ts +146 -0
- package/dist/protocols/google-speech.js +88 -0
- package/dist/protocols/google-transcription.d.ts +174 -0
- package/dist/protocols/google-transcription.js +126 -0
- package/dist/protocols/google-video.d.ts +26 -0
- package/dist/protocols/google-video.js +142 -0
- package/dist/protocols/meta-images.d.ts +3 -4
- package/dist/protocols/meta-images.js +13 -29
- package/dist/protocols/meta-messages.d.ts +5 -5
- package/dist/protocols/meta-responses.d.ts +4 -4
- package/dist/protocols/meta-responses.js +6 -4
- package/dist/protocols/open-responses.d.ts +10 -9
- package/dist/protocols/open-responses.js +4 -9
- package/dist/protocols/openai-chat.d.ts +84 -0
- package/dist/protocols/openai-chat.js +28 -17
- 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 +130 -7
- package/dist/protocols/openai-images.js +143 -91
- package/dist/protocols/openai-responses.d.ts +20 -20
- package/dist/protocols/openai-responses.js +31 -31
- package/dist/protocols/openai-speech.d.ts +136 -0
- package/dist/protocols/openai-speech.js +97 -0
- package/dist/protocols/openai-transcription.d.ts +211 -0
- package/dist/protocols/openai-transcription.js +202 -0
- package/dist/protocols/replicate-images.d.ts +28 -0
- package/dist/protocols/replicate-images.js +127 -0
- package/dist/protocols/runway-video.d.ts +38 -0
- package/dist/protocols/runway-video.js +140 -0
- package/dist/protocols/shared.d.ts +21 -17
- package/dist/protocols/shared.js +27 -36
- package/dist/protocols/stability-images.d.ts +39 -0
- package/dist/protocols/stability-images.js +136 -0
- package/dist/protocols/utils/fal-queue.d.ts +26 -0
- package/dist/protocols/utils/fal-queue.js +67 -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 +23 -1
- package/dist/protocols/utils/media-input.js +40 -0
- package/dist/protocols/utils/responses-checkpoint.js +3 -7
- package/dist/protocols/utils/responses-compaction.d.ts +3 -1
- package/dist/protocols/utils/responses-compaction.js +16 -3
- package/dist/protocols/utils/speech-stream.d.ts +49 -0
- package/dist/protocols/utils/speech-stream.js +64 -0
- package/dist/protocols/utils/tool-schema.d.ts +2 -2
- package/dist/protocols/utils/tool-schema.js +62 -19
- package/dist/protocols/xai-images.d.ts +4 -4
- package/dist/protocols/xai-images.js +14 -40
- package/dist/protocols/xai-responses.d.ts +2 -2
- package/dist/protocols/xai-responses.js +1 -1
- package/dist/protocols/xai-video.d.ts +34 -0
- package/dist/protocols/xai-video.js +141 -0
- package/dist/protocols/zai-chat.d.ts +13 -1
- package/dist/protocols/zai-images.d.ts +2 -2
- package/dist/protocols/zai-images.js +11 -14
- package/dist/protocols/zai-messages.d.ts +1 -1
- package/dist/provider-error.js +10 -1
- package/dist/providers/alibaba.d.ts +15 -3
- package/dist/providers/amazon-bedrock-mantle.d.ts +14 -2
- package/dist/providers/amazon-bedrock.d.ts +2 -0
- package/dist/providers/amazon-bedrock.js +1 -0
- package/dist/providers/anthropic-compatible.d.ts +5 -5
- package/dist/providers/anthropic.d.ts +5 -5
- package/dist/providers/assemblyai.d.ts +25 -0
- package/dist/providers/assemblyai.js +24 -0
- package/dist/providers/azure.d.ts +20 -8
- package/dist/providers/azure.js +2 -2
- 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 +23 -0
- package/dist/providers/cartesia.d.ts +24 -0
- package/dist/providers/cartesia.js +17 -0
- package/dist/providers/cerebras.d.ts +24 -0
- package/dist/providers/cloudflare-ai-gateway.d.ts +42 -18
- package/dist/providers/cloudflare-workers-ai.d.ts +24 -0
- package/dist/providers/deepgram.d.ts +29 -0
- package/dist/providers/deepgram.js +25 -0
- package/dist/providers/deepinfra.d.ts +24 -0
- package/dist/providers/deepseek.d.ts +24 -0
- package/dist/providers/elevenlabs.d.ts +24 -0
- package/dist/providers/elevenlabs.js +23 -0
- package/dist/providers/fal.d.ts +29 -0
- package/dist/providers/fal.js +26 -0
- package/dist/providers/fireworks.d.ts +24 -0
- package/dist/providers/google-vertex-chat.d.ts +12 -0
- package/dist/providers/google-vertex-messages.d.ts +5 -5
- package/dist/providers/google-vertex-responses.d.ts +2 -2
- package/dist/providers/google-vertex.d.ts +6 -6
- package/dist/providers/google.d.ts +21 -6
- package/dist/providers/google.js +13 -9
- package/dist/providers/groq.d.ts +24 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/meta.d.ts +22 -10
- package/dist/providers/meta.js +4 -8
- package/dist/providers/minimax.d.ts +19 -7
- package/dist/providers/moonshot.d.ts +19 -7
- 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-options.d.ts +3 -9
- package/dist/providers/openai-options.js +4 -7
- package/dist/providers/openai.d.ts +33 -12
- package/dist/providers/openai.js +17 -9
- package/dist/providers/opencode-zen.js +1 -1
- package/dist/providers/openrouter.d.ts +54 -7
- package/dist/providers/openrouter.js +10 -5
- package/dist/providers/replicate.d.ts +25 -0
- package/dist/providers/replicate.js +17 -0
- package/dist/providers/runway.d.ts +24 -0
- package/dist/providers/runway.js +17 -0
- package/dist/providers/stability.d.ts +28 -0
- package/dist/providers/stability.js +18 -0
- package/dist/providers/togetherai.d.ts +24 -0
- package/dist/providers/typesafe-ai.js +1 -1
- package/dist/providers/vercel-ai-gateway.js +1 -1
- package/dist/providers/xai.d.ts +17 -0
- package/dist/providers/xai.js +7 -9
- package/dist/providers/zai-coding-plan.d.ts +16 -4
- package/dist/providers/zai.d.ts +13 -1
- package/dist/providers/zai.js +4 -8
- package/dist/route/auth.d.ts +5 -2
- package/dist/route/auth.js +20 -13
- package/dist/route/client.d.ts +9 -7
- package/dist/route/client.js +6 -8
- package/dist/route/endpoint.d.ts +1 -0
- package/dist/route/endpoint.js +2 -2
- package/dist/route/executor-service.d.ts +4 -2
- package/dist/route/executor-service.js +2 -1
- package/dist/route/executor.d.ts +3 -1
- package/dist/route/executor.js +7 -0
- package/dist/route/framing.d.ts +15 -2
- package/dist/route/framing.js +53 -4
- package/dist/route/index.d.ts +1 -1
- package/dist/route/media-protocol.d.ts +145 -18
- package/dist/route/media-protocol.js +96 -28
- package/dist/route/media.d.ts +54 -9
- package/dist/route/media.js +194 -38
- package/dist/route/protocol.d.ts +3 -1
- package/dist/schema/events.d.ts +0 -6
- package/dist/schema/messages.d.ts +0 -3
- package/dist/schema/options.d.ts +10 -6
- package/dist/schema/options.js +10 -5
- package/dist/speech-client.d.ts +66 -0
- package/dist/speech-client.js +21 -0
- package/dist/speech.d.ts +1307 -0
- package/dist/speech.js +124 -0
- package/dist/testing.d.ts +2 -2
- package/dist/transcription-client.d.ts +82 -0
- package/dist/transcription-client.js +13 -0
- package/dist/transcription.d.ts +1492 -0
- package/dist/transcription.js +127 -0
- package/dist/utils/bytes.d.ts +1 -0
- package/dist/utils/bytes.js +10 -0
- package/dist/utils/json.d.ts +4 -0
- package/dist/utils/json.js +4 -0
- package/dist/utils/media-type.d.ts +3 -1
- package/dist/utils/media-type.js +25 -2
- package/dist/video-client.d.ts +59 -0
- package/dist/video-client.js +20 -0
- package/dist/video.d.ts +1351 -0
- package/dist/video.js +118 -0
- package/package.json +3 -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/meta-image.d.ts +0 -2
- package/dist/protocols/utils/meta-image.js +0 -13
- package/dist/protocols/utils/openai-image.d.ts +0 -5
- package/dist/protocols/utils/openai-image.js +0 -18
package/dist/image.js
CHANGED
|
@@ -1,42 +1,17 @@
|
|
|
1
1
|
import { Effect, Schema, Stream } from "effect";
|
|
2
|
+
import { Generation, ProgressEvent, QueuedEvent } from "./generation.js";
|
|
2
3
|
import { Media } from "./media.js";
|
|
3
|
-
import {
|
|
4
|
+
import { MediaModel, composeRoute, tryRequest } from "./media-model.js";
|
|
4
5
|
import { MediaRoute } from "./route/media.js";
|
|
5
|
-
import { AIError, HttpOptions,
|
|
6
|
+
import { AIError, HttpOptions, MediaUsage, ProviderMetadata } from "./schema/index.js";
|
|
6
7
|
import { ImageClient, Service } from "./image-client.js";
|
|
7
|
-
export class ImageModel {
|
|
8
|
-
id;
|
|
9
|
-
provider;
|
|
10
|
-
route;
|
|
11
|
-
http;
|
|
12
|
-
constructor(input) {
|
|
13
|
-
this.id = input.id;
|
|
14
|
-
this.provider = input.provider;
|
|
15
|
-
this.route = input.route;
|
|
16
|
-
this.http = input.http;
|
|
17
|
-
}
|
|
18
|
-
static make(input) {
|
|
19
|
-
return new ImageModel({
|
|
20
|
-
id: ModelID.make(input.id),
|
|
21
|
-
provider: ProviderID.make(input.provider),
|
|
22
|
-
route: input.route,
|
|
23
|
-
http: input.http,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
/** Compose an inline image protocol with its canonical path into a model for one deployment. */
|
|
8
|
+
export class ImageModel extends MediaModel {
|
|
27
9
|
static fromRoute(route, input) {
|
|
28
|
-
return ImageModel
|
|
10
|
+
return new ImageModel({
|
|
29
11
|
id: input.id,
|
|
30
|
-
provider: route.provider,
|
|
12
|
+
provider: route.protocol.provider,
|
|
31
13
|
http: input.http,
|
|
32
|
-
route:
|
|
33
|
-
id: route.id,
|
|
34
|
-
provider: route.provider,
|
|
35
|
-
protocol: route.protocol,
|
|
36
|
-
endpoint: Endpoint.path(route.path, { baseURL: input.baseURL ?? route.baseURL }),
|
|
37
|
-
auth: input.auth,
|
|
38
|
-
headers: input.headers,
|
|
39
|
-
}),
|
|
14
|
+
route: composeRoute(route, input, collectResponse),
|
|
40
15
|
});
|
|
41
16
|
}
|
|
42
17
|
}
|
|
@@ -44,7 +19,7 @@ export const ImageModelSchema = Schema.declare((value) => value instanceof Image
|
|
|
44
19
|
expected: "Image.Model",
|
|
45
20
|
});
|
|
46
21
|
export const ImageSize = Schema.declare((value) => typeof value === "string" && /^\d+x\d+$/.test(value), { title: "ImageSize" });
|
|
47
|
-
export const ImageAspectRatio =
|
|
22
|
+
export const ImageAspectRatio = Media.AspectRatio;
|
|
48
23
|
export class ImageRequest extends Schema.Class("Image.Request")({
|
|
49
24
|
model: ImageModelSchema,
|
|
50
25
|
prompt: Schema.String,
|
|
@@ -74,6 +49,12 @@ export class ImageResponse extends Schema.Class("Image.Response")({
|
|
|
74
49
|
return this.images[0];
|
|
75
50
|
}
|
|
76
51
|
}
|
|
52
|
+
/** The `index`-th lower-fidelity preview of an image still generating; the `image` event supersedes it. */
|
|
53
|
+
export const ImagePartialEvent = Schema.Struct({
|
|
54
|
+
type: Schema.tag("image-partial"),
|
|
55
|
+
index: Schema.Number,
|
|
56
|
+
image: Media.AssetSchema,
|
|
57
|
+
}).annotate({ identifier: "Image.Event.Partial" });
|
|
77
58
|
export const ImageOutputEvent = Schema.Struct({
|
|
78
59
|
type: Schema.tag("image"),
|
|
79
60
|
index: Schema.Number,
|
|
@@ -85,47 +66,57 @@ export const ImageFinishEvent = Schema.Struct({
|
|
|
85
66
|
notices: Schema.optional(Schema.Array(Media.Notice)),
|
|
86
67
|
providerMetadata: Schema.optional(ProviderMetadata),
|
|
87
68
|
}).annotate({ identifier: "Image.Event.Finish" });
|
|
88
|
-
const imageEventTagged = Schema.Union([
|
|
69
|
+
const imageEventTagged = Schema.Union([
|
|
70
|
+
QueuedEvent,
|
|
71
|
+
ProgressEvent,
|
|
72
|
+
ImagePartialEvent,
|
|
73
|
+
ImageOutputEvent,
|
|
74
|
+
ImageFinishEvent,
|
|
75
|
+
]).pipe(Schema.toTaggedUnion("type"));
|
|
89
76
|
export const ImageEvent = Object.assign(imageEventTagged, {
|
|
90
77
|
is: {
|
|
78
|
+
generationQueued: imageEventTagged.guards["generation-queued"],
|
|
79
|
+
generationProgress: imageEventTagged.guards["generation-progress"],
|
|
80
|
+
imagePartial: imageEventTagged.guards["image-partial"],
|
|
91
81
|
image: imageEventTagged.guards.image,
|
|
92
82
|
finish: imageEventTagged.guards.finish,
|
|
93
83
|
},
|
|
94
84
|
});
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
85
|
+
const collectResponse = (events) => {
|
|
86
|
+
const finish = events.find(ImageEvent.is.finish);
|
|
87
|
+
// Every image protocol's `finish` emits the terminal event or fails, so a completed stream always has one.
|
|
88
|
+
if (finish === undefined)
|
|
89
|
+
return Effect.die(new Error("The image stream completed without a finish event"));
|
|
90
|
+
return Effect.succeed(new ImageResponse({
|
|
91
|
+
images: events.filter(ImageEvent.is.image).map((event) => event.image),
|
|
92
|
+
usage: finish.usage,
|
|
93
|
+
notices: finish.notices,
|
|
94
|
+
providerMetadata: finish.providerMetadata,
|
|
95
|
+
}));
|
|
96
|
+
};
|
|
104
97
|
export function request(input) {
|
|
105
98
|
if (input instanceof ImageRequest)
|
|
106
99
|
return input;
|
|
107
100
|
return new ImageRequest({
|
|
108
101
|
...input,
|
|
109
|
-
http:
|
|
102
|
+
http: HttpOptions.make(input.http),
|
|
110
103
|
});
|
|
111
104
|
}
|
|
112
|
-
const requestEffect = (input) =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}),
|
|
119
|
-
}),
|
|
120
|
-
});
|
|
121
|
-
export function generate(input) {
|
|
122
|
-
return requestEffect(input).pipe(Effect.flatMap((request) => ImageClient.generate(request)));
|
|
105
|
+
const requestEffect = (input) => tryRequest(() => request(input));
|
|
106
|
+
export function generate(input, options) {
|
|
107
|
+
return requestEffect(input).pipe(Effect.flatMap((request) => ImageClient.generate(request, options)));
|
|
108
|
+
}
|
|
109
|
+
export function stream(input, options) {
|
|
110
|
+
return Stream.unwrap(requestEffect(input).pipe(Effect.map((request) => ImageClient.stream(request, options))));
|
|
123
111
|
}
|
|
124
|
-
export function
|
|
125
|
-
return
|
|
112
|
+
export function start(input) {
|
|
113
|
+
return requestEffect(input).pipe(Effect.flatMap((request) => ImageClient.start(request)));
|
|
126
114
|
}
|
|
115
|
+
export const resume = (model, token) => ImageClient.resume(model, token);
|
|
127
116
|
export const Image = {
|
|
128
117
|
request,
|
|
129
118
|
generate,
|
|
130
119
|
stream,
|
|
120
|
+
start,
|
|
121
|
+
resume,
|
|
131
122
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,30 @@
|
|
|
1
|
+
export { AIClient } from "./ai-client.js";
|
|
1
2
|
export { LLMClient } from "./route/client.js";
|
|
2
3
|
export { ImageClient } from "./image-client.js";
|
|
3
4
|
export { Auth } from "./route/auth.js";
|
|
4
5
|
export { Provider } from "./provider.js";
|
|
5
6
|
export { ProviderPackage } from "./provider-package.js";
|
|
6
7
|
export { isContextOverflow, isContextOverflowFailure } from "./provider-error.js";
|
|
7
|
-
export type { RouteLanguageModelInput, RouteRoutedLanguageModelInput, Interface as LLMClientShape,
|
|
8
|
+
export type { RouteLanguageModelInput, RouteRoutedLanguageModelInput, Interface as LLMClientShape, LLMClientService, } from "./route/client.js";
|
|
8
9
|
export * from "./schema/index.js";
|
|
9
10
|
export { ImageAspectRatio, ImageEvent, ImageModel, ImageModelSchema, ImageRequest, ImageResponse, ImageSize, } from "./image.js";
|
|
10
11
|
export type { ImageFormat, ImageModelOptions, ImageOptions, ImageRequestFor, ImageRequestInput, ImageRoute, } from "./image.js";
|
|
11
12
|
export { Image } from "./image.js";
|
|
13
|
+
export { VideoClient } from "./video-client.js";
|
|
14
|
+
export { VideoAspectRatio, VideoEvent, VideoFrames, VideoModel, VideoModelSchema, VideoRequest, VideoResponse, } from "./video.js";
|
|
15
|
+
export type { VideoModelOptions, VideoOptions, VideoRequestFor, VideoRequestInput, VideoResolution, VideoRoute, } from "./video.js";
|
|
16
|
+
export { Video } from "./video.js";
|
|
17
|
+
export { SpeechClient } from "./speech-client.js";
|
|
18
|
+
export { SpeechEvent, SpeechModel, SpeechModelSchema, SpeechRequest, SpeechResponse, SpeechTimestamp, SpeechVoice, } from "./speech.js";
|
|
19
|
+
export type { SpeechFormat, SpeechModelOptions, SpeechOptions, SpeechRequestFor, SpeechRequestInput, SpeechRoute, } from "./speech.js";
|
|
20
|
+
export { Speech } from "./speech.js";
|
|
21
|
+
export { TranscriptionClient } from "./transcription-client.js";
|
|
22
|
+
export { TranscriptionEvent, TranscriptionModel, TranscriptionModelSchema, TranscriptionRequest, TranscriptionResponse, TranscriptionSegment, TranscriptionTimestamps, TranscriptionWord, } from "./transcription.js";
|
|
23
|
+
export type { TranscriptionModelOptions, TranscriptionOptions, TranscriptionRequestFor, TranscriptionRequestInput, TranscriptionRoute, } from "./transcription.js";
|
|
24
|
+
export { Transcription } from "./transcription.js";
|
|
12
25
|
export { Media } from "./media.js";
|
|
13
26
|
export { Generation } from "./generation.js";
|
|
14
|
-
export type { Event as GenerationEvent, Poll, Route as GenerationRoute, Snapshot as GenerationSnapshot, Status as GenerationStatus } from "./generation.js";
|
|
27
|
+
export type { AwaitOptions as GenerationAwaitOptions, Event as GenerationEvent, Poll, Route as GenerationRoute, Snapshot as GenerationSnapshot, Status as GenerationStatus, } from "./generation.js";
|
|
15
28
|
export { Tool, ToolFailure, toDefinitions } from "./tool.js";
|
|
16
29
|
export { ToolRuntime } from "./tool-runtime.js";
|
|
17
30
|
export type { DispatchResult as ToolDispatchResult, ToolSettlement } from "./tool-runtime.js";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { AIClient } from "./ai-client.js";
|
|
1
2
|
export { LLMClient } from "./route/client.js";
|
|
2
3
|
export { ImageClient } from "./image-client.js";
|
|
3
4
|
export { Auth } from "./route/auth.js";
|
|
@@ -7,6 +8,15 @@ export { isContextOverflow, isContextOverflowFailure } from "./provider-error.js
|
|
|
7
8
|
export * from "./schema/index.js";
|
|
8
9
|
export { ImageAspectRatio, ImageEvent, ImageModel, ImageModelSchema, ImageRequest, ImageResponse, ImageSize, } from "./image.js";
|
|
9
10
|
export { Image } from "./image.js";
|
|
11
|
+
export { VideoClient } from "./video-client.js";
|
|
12
|
+
export { VideoAspectRatio, VideoEvent, VideoFrames, VideoModel, VideoModelSchema, VideoRequest, VideoResponse, } from "./video.js";
|
|
13
|
+
export { Video } from "./video.js";
|
|
14
|
+
export { SpeechClient } from "./speech-client.js";
|
|
15
|
+
export { SpeechEvent, SpeechModel, SpeechModelSchema, SpeechRequest, SpeechResponse, SpeechTimestamp, SpeechVoice, } from "./speech.js";
|
|
16
|
+
export { Speech } from "./speech.js";
|
|
17
|
+
export { TranscriptionClient } from "./transcription-client.js";
|
|
18
|
+
export { TranscriptionEvent, TranscriptionModel, TranscriptionModelSchema, TranscriptionRequest, TranscriptionResponse, TranscriptionSegment, TranscriptionTimestamps, TranscriptionWord, } from "./transcription.js";
|
|
19
|
+
export { Transcription } from "./transcription.js";
|
|
10
20
|
export { Media } from "./media.js";
|
|
11
21
|
export { Generation } from "./generation.js";
|
|
12
22
|
export { Tool, ToolFailure, toDefinitions } from "./tool.js";
|
package/dist/llm.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Effect, JsonSchema, Schema } from "effect";
|
|
2
|
-
import { Service } from "./route/client.js";
|
|
3
|
-
import { GenerationOptions, HttpOptions, AIError, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, type ContentPart, type LanguageModelProviderOptions, type ToolEntryInput } from "./schema/index.js";
|
|
1
|
+
import { Effect, JsonSchema, Schema, Stream } from "effect";
|
|
2
|
+
import { Service, type StreamOptions } from "./route/client.js";
|
|
3
|
+
import { GenerationOptions, HttpOptions, AIError, LLMEvent, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, type ContentPart, type LanguageModelProviderOptions, type ToolEntryInput } from "./schema/index.js";
|
|
4
4
|
import { type ToolSchema } from "./tool.js";
|
|
5
5
|
/** Input accepted by `LLM.request`, normalized into the canonical `LLMRequest` class. */
|
|
6
6
|
export type RequestInput<SelectedLanguageModel extends LanguageModel = LanguageModel> = Omit<ConstructorParameters<typeof LLMRequest>[0], "model" | "system" | "messages" | "tools" | "toolChoice" | "generation" | "http" | "providerOptions"> & {
|
|
@@ -14,8 +14,10 @@ export type RequestInput<SelectedLanguageModel extends LanguageModel = LanguageM
|
|
|
14
14
|
readonly providerOptions?: NoInfer<LanguageModelProviderOptions<SelectedLanguageModel>>;
|
|
15
15
|
readonly http?: HttpOptions.Input;
|
|
16
16
|
};
|
|
17
|
-
export declare const
|
|
18
|
-
export declare
|
|
17
|
+
export declare function generate<const Model extends LanguageModel>(input: RequestInput<Model>, options?: StreamOptions): Effect.Effect<LLMResponse, AIError, Service>;
|
|
18
|
+
export declare function generate(input: LLMRequest, options?: StreamOptions): Effect.Effect<LLMResponse, AIError, Service>;
|
|
19
|
+
export declare function stream<const Model extends LanguageModel>(input: RequestInput<Model>, options?: StreamOptions): Stream.Stream<LLMEvent, AIError, Service>;
|
|
20
|
+
export declare function stream(input: LLMRequest, options?: StreamOptions): Stream.Stream<LLMEvent, AIError, Service>;
|
|
19
21
|
export declare const request: <const SelectedLanguageModel extends LanguageModel>(input: RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
|
|
20
22
|
type GenerateObjectBase<SelectedLanguageModel extends LanguageModel = LanguageModel> = Omit<RequestInput<SelectedLanguageModel>, "tools" | "toolChoice">;
|
|
21
23
|
export declare class GenerateObjectResponse<T> {
|
package/dist/llm.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { Effect, JsonSchema, Schema } from "effect";
|
|
1
|
+
import { Effect, JsonSchema, Schema, Stream } from "effect";
|
|
2
|
+
import { tryRequest } from "./media-model.js";
|
|
2
3
|
import { LLMClient, Service } from "./route/client.js";
|
|
3
4
|
import { GenerationOptions, HttpOptions, InvalidProviderOutputError, AIError, LLMEvent, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, ToolEntry, } from "./schema/index.js";
|
|
4
5
|
import { make as makeTool, toDefinitions } from "./tool.js";
|
|
5
|
-
export
|
|
6
|
-
|
|
6
|
+
export function generate(input, options) {
|
|
7
|
+
return requestEffect(input).pipe(Effect.flatMap((request) => LLMClient.generate(request, options)));
|
|
8
|
+
}
|
|
9
|
+
export function stream(input, options) {
|
|
10
|
+
return Stream.unwrap(requestEffect(input).pipe(Effect.map((request) => LLMClient.stream(request, options))));
|
|
11
|
+
}
|
|
12
|
+
const requestEffect = (input) => input instanceof LLMRequest ? Effect.succeed(input) : tryRequest(() => request(input));
|
|
7
13
|
export const request = (input) => {
|
|
8
14
|
const { system: requestSystem, prompt, messages, tools, toolChoice: requestToolChoice, generation: requestGeneration, providerOptions: requestProviderOptions, http: requestHttp, ...rest } = input;
|
|
9
15
|
return new LLMRequest({
|
|
@@ -14,7 +20,7 @@ export const request = (input) => {
|
|
|
14
20
|
toolChoice: requestToolChoice ? ToolChoice.make(requestToolChoice) : undefined,
|
|
15
21
|
generation: requestGeneration === undefined ? undefined : GenerationOptions.make(requestGeneration),
|
|
16
22
|
providerOptions: requestProviderOptions,
|
|
17
|
-
http:
|
|
23
|
+
http: HttpOptions.make(requestHttp),
|
|
18
24
|
});
|
|
19
25
|
};
|
|
20
26
|
const GENERATE_OBJECT_TOOL_NAME = "generate_object";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Context, Effect, Layer, Stream } from "effect";
|
|
2
|
+
import { type AwaitOptions, type Generation, type Observation } from "./generation.js";
|
|
3
|
+
import type { MediaRoute } from "./route/media.js";
|
|
4
|
+
import { AIError } from "./schema/index.js";
|
|
5
|
+
/** A media request whose model carries the route that executes it. */
|
|
6
|
+
export interface RoutedRequest<Self extends MediaRoute.MediaRequest, Event, Response> extends MediaRoute.MediaRequest {
|
|
7
|
+
readonly model: MediaRoute.MediaRequest["model"] & {
|
|
8
|
+
readonly route: MediaRoute.AnyRoute<Self, Event, Response>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** `start` and `resume` fail with `UnsupportedOperation` on inline and stream routes. */
|
|
12
|
+
export interface Interface<Req extends RoutedRequest<Req, Event, Response>, Event, Response> {
|
|
13
|
+
readonly generate: (request: Req, options?: AwaitOptions) => Effect.Effect<Response, AIError>;
|
|
14
|
+
readonly stream: (request: Req, options?: AwaitOptions) => Stream.Stream<Event | Observation, AIError>;
|
|
15
|
+
readonly start: (request: Req) => Effect.Effect<Generation<Response>, AIError>;
|
|
16
|
+
readonly resume: (model: Req["model"], token: unknown) => Effect.Effect<Generation<Response>, AIError>;
|
|
17
|
+
}
|
|
18
|
+
/** One modality's layer and service accessors, dispatching each request on its route's `kind`. */
|
|
19
|
+
export declare const make: <Self, Req extends RoutedRequest<Req, Event, Response>, Event, Response>(service: Context.Service<Self, Interface<Req, Event, Response>>, input: {
|
|
20
|
+
readonly modality: string;
|
|
21
|
+
/** A completed response expanded into the streaming event shape. */
|
|
22
|
+
readonly responseEvents: (response: Response) => ReadonlyArray<Event>;
|
|
23
|
+
}) => {
|
|
24
|
+
layer: Layer.Layer<Self, never, import("./route/executor-service.js").RequestExecutorService>;
|
|
25
|
+
generate: (request: Req, options?: AwaitOptions) => Effect.Effect<Response, AIError, Self>;
|
|
26
|
+
stream: (request: Req, options?: AwaitOptions) => Stream.Stream<Observation | Event, AIError, Exclude<Self, import("effect/Scope").Scope>>;
|
|
27
|
+
start: (request: Req) => Effect.Effect<Generation<Response>, AIError, Self>;
|
|
28
|
+
resume: (model: Req["model"], token: unknown) => Effect.Effect<Generation<Response>, AIError, Self>;
|
|
29
|
+
};
|
|
30
|
+
export * as MediaClient from "./media-client.js";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Effect, Layer, Stream } from "effect";
|
|
2
|
+
import { resultEvents } from "./generation.js";
|
|
3
|
+
import { RequestExecutor } from "./route/executor.js";
|
|
4
|
+
import { AIError, UnsupportedOperationError } from "./schema/index.js";
|
|
5
|
+
/** One modality's layer and service accessors, dispatching each request on its route's `kind`. */
|
|
6
|
+
export const make = (service, input) => ({
|
|
7
|
+
layer: Layer.effect(service, Effect.gen(function* () {
|
|
8
|
+
const executor = yield* RequestExecutor.Service;
|
|
9
|
+
const notQueued = (route, operation) => new AIError({
|
|
10
|
+
reason: new UnsupportedOperationError({
|
|
11
|
+
operation: `${input.modality}.${operation}`,
|
|
12
|
+
provider: route.provider,
|
|
13
|
+
route: route.id,
|
|
14
|
+
message: `${route.provider}/${route.id} is not a queued route; use generate or stream`,
|
|
15
|
+
}),
|
|
16
|
+
});
|
|
17
|
+
const start = (request) => {
|
|
18
|
+
const route = request.model.route;
|
|
19
|
+
if (route.kind !== "queued")
|
|
20
|
+
return Effect.fail(notQueued(route, "start"));
|
|
21
|
+
return route.start(request, executor.execute);
|
|
22
|
+
};
|
|
23
|
+
return service.of({
|
|
24
|
+
start,
|
|
25
|
+
resume: (model, token) => {
|
|
26
|
+
if (model.route.kind !== "queued")
|
|
27
|
+
return Effect.fail(notQueued(model.route, "resume"));
|
|
28
|
+
return model.route.resume(model, token, executor.execute);
|
|
29
|
+
},
|
|
30
|
+
generate: (request, options) => {
|
|
31
|
+
const route = request.model.route;
|
|
32
|
+
if (route.kind !== "queued")
|
|
33
|
+
return route.generate(request, executor.execute);
|
|
34
|
+
return start(request).pipe(Effect.flatMap((generation) => generation.await(options)));
|
|
35
|
+
},
|
|
36
|
+
stream: (request, options) => {
|
|
37
|
+
const route = request.model.route;
|
|
38
|
+
if (route.kind === "stream")
|
|
39
|
+
return route.stream(request, executor.execute);
|
|
40
|
+
if (route.kind === "queued")
|
|
41
|
+
return Stream.unwrap(start(request).pipe(Effect.map((generation) => resultEvents(generation, input.responseEvents, options))));
|
|
42
|
+
return Stream.fromIterableEffect(Effect.map(route.generate(request, executor.execute), input.responseEvents));
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
})),
|
|
46
|
+
generate: (request, options) => service.use((client) => client.generate(request, options)),
|
|
47
|
+
stream: (request, options) => Stream.unwrap(service.useSync((client) => client.stream(request, options))),
|
|
48
|
+
start: (request) => service.use((client) => client.start(request)),
|
|
49
|
+
resume: (model, token) => service.use((client) => client.resume(model, token)),
|
|
50
|
+
});
|
|
51
|
+
export * as MediaClient from "./media-client.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Endpoint } from "./route/endpoint.js";
|
|
3
|
+
import { MediaRoute } from "./route/media.js";
|
|
4
|
+
import type { MediaProtocol } from "./route/media-protocol.js";
|
|
5
|
+
import { AIError, HttpOptions, ModelID, ProviderID } from "./schema/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* What every media model carries: ids, the configured route, and deployment `http` overlays. Modality classes
|
|
8
|
+
* (`ImageModel`, `VideoModel`, `SpeechModel`, `TranscriptionModel`) extend it with their route type and a nominal
|
|
9
|
+
* marker so one cannot stand in for the other in requests.
|
|
10
|
+
*/
|
|
11
|
+
export declare class MediaModel<Route, Options> {
|
|
12
|
+
protected readonly _Options: Options;
|
|
13
|
+
readonly id: ModelID;
|
|
14
|
+
readonly provider: ProviderID;
|
|
15
|
+
readonly route: Route;
|
|
16
|
+
readonly http?: HttpOptions;
|
|
17
|
+
constructor(input: MediaModel.Input<Route>);
|
|
18
|
+
}
|
|
19
|
+
export declare namespace MediaModel {
|
|
20
|
+
type Options = Record<string, unknown>;
|
|
21
|
+
interface Input<Route> {
|
|
22
|
+
readonly id: string | ModelID;
|
|
23
|
+
readonly provider: string | ProviderID;
|
|
24
|
+
readonly route: Route;
|
|
25
|
+
readonly http?: HttpOptions;
|
|
26
|
+
}
|
|
27
|
+
/** A protocol plus its canonical start path; `ModelInput.baseURL` overrides `baseURL` per deployment. */
|
|
28
|
+
interface RouteInput<Request extends MediaRoute.MediaRequest, Protocol> {
|
|
29
|
+
readonly protocol: Protocol;
|
|
30
|
+
readonly path: Endpoint.EndpointPart<MediaProtocol.Body, Request>;
|
|
31
|
+
readonly baseURL?: string;
|
|
32
|
+
/** Headers the protocol requires on every call, such as a pinned API version; deployment headers win. */
|
|
33
|
+
readonly headers?: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
type InlineRouteInput<Request extends MediaRoute.MediaRequest, Response> = RouteInput<Request, MediaProtocol.Inline<Request, Response>>;
|
|
36
|
+
type StreamRouteInput<Request extends MediaRoute.MediaRequest, Event, Frame, State> = RouteInput<MediaProtocol.Addressed<Request>, MediaProtocol.Streamed<Request, Event, Frame, State>>;
|
|
37
|
+
type QueuedRouteInput<Request extends MediaRoute.MediaRequest, Response, Token> = RouteInput<Request, MediaProtocol.Queued<Request, Response, Token>>;
|
|
38
|
+
type AnyRouteInput<Request extends MediaRoute.MediaRequest, Event, Response, Frame, State, Token> = InlineRouteInput<Request, Response> | StreamRouteInput<Request, Event, Frame, State> | QueuedRouteInput<Request, Response, Token>;
|
|
39
|
+
}
|
|
40
|
+
/** Compose a protocol route input with one deployment through `MediaRoute.inline`, `queued`, or `stream`. */
|
|
41
|
+
export declare const composeRoute: <Request extends MediaRoute.MediaRequest, Event, Response, Frame, State, Token>(route: MediaModel.AnyRouteInput<Request, Event, Response, Frame, State, Token>, input: MediaRoute.ModelInput, collect: (events: ReadonlyArray<Event>) => Effect.Effect<Response, AIError>) => MediaRoute.AnyRoute<Request, Event, Response>;
|
|
42
|
+
/** Lift a synchronous Schema-class constructor into a typed `InvalidRequest` failure. */
|
|
43
|
+
export declare const tryRequest: <A>(make: () => A) => Effect.Effect<A, AIError>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Endpoint } from "./route/endpoint.js";
|
|
3
|
+
import { MediaRoute } from "./route/media.js";
|
|
4
|
+
import { AIError, HttpOptions, InvalidRequestError, ModelID, ProviderID } from "./schema/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* What every media model carries: ids, the configured route, and deployment `http` overlays. Modality classes
|
|
7
|
+
* (`ImageModel`, `VideoModel`, `SpeechModel`, `TranscriptionModel`) extend it with their route type and a nominal
|
|
8
|
+
* marker so one cannot stand in for the other in requests.
|
|
9
|
+
*/
|
|
10
|
+
export class MediaModel {
|
|
11
|
+
id;
|
|
12
|
+
provider;
|
|
13
|
+
route;
|
|
14
|
+
http;
|
|
15
|
+
constructor(input) {
|
|
16
|
+
this.id = ModelID.make(input.id);
|
|
17
|
+
this.provider = ProviderID.make(input.provider);
|
|
18
|
+
this.route = input.route;
|
|
19
|
+
this.http = input.http;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Compose a protocol route input with one deployment through `MediaRoute.inline`, `queued`, or `stream`. */
|
|
23
|
+
export const composeRoute = (route, input, collect) => {
|
|
24
|
+
if (isStreamInput(route))
|
|
25
|
+
return MediaRoute.stream({ ...composition(route, input), collect });
|
|
26
|
+
if (isQueuedInput(route))
|
|
27
|
+
return MediaRoute.queued(composition(route, input));
|
|
28
|
+
return MediaRoute.inline(composition(route, input));
|
|
29
|
+
};
|
|
30
|
+
const composition = (route, input) => ({
|
|
31
|
+
protocol: route.protocol,
|
|
32
|
+
endpoint: Endpoint.path(route.path, { baseURL: input.baseURL ?? route.baseURL }),
|
|
33
|
+
auth: input.auth,
|
|
34
|
+
headers: route.headers === undefined && input.headers === undefined ? undefined : { ...route.headers, ...input.headers },
|
|
35
|
+
});
|
|
36
|
+
const isStreamInput = (route) => route.protocol.kind === "stream";
|
|
37
|
+
const isQueuedInput = (route) => route.protocol.kind === "queued";
|
|
38
|
+
/** Lift a synchronous Schema-class constructor into a typed `InvalidRequest` failure. */
|
|
39
|
+
export const tryRequest = (make) => Effect.try({
|
|
40
|
+
try: make,
|
|
41
|
+
catch: (error) => new AIError({
|
|
42
|
+
reason: new InvalidRequestError({
|
|
43
|
+
message: error instanceof Error ? error.message : String(error),
|
|
44
|
+
cause: error,
|
|
45
|
+
}),
|
|
46
|
+
}),
|
|
47
|
+
});
|
package/dist/media.d.ts
CHANGED
|
@@ -19,8 +19,6 @@ export declare const Source: Schema.Union<readonly [Schema.Struct<{
|
|
|
19
19
|
readonly mediaType: Schema.optional<Schema.String>;
|
|
20
20
|
/** Epoch milliseconds after which the provider no longer serves the URL. */
|
|
21
21
|
readonly expiresAt: Schema.optional<Schema.Number>;
|
|
22
|
-
/** Headers required to fetch the URL, such as provider auth for Veo downloads. */
|
|
23
|
-
readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
|
|
24
22
|
}>, Schema.Struct<{
|
|
25
23
|
readonly type: Schema.Literal<"ref">;
|
|
26
24
|
readonly provider: Schema.brand<Schema.String, "AI.ProviderID">;
|
|
@@ -28,6 +26,8 @@ export declare const Source: Schema.Union<readonly [Schema.Struct<{
|
|
|
28
26
|
readonly mediaType: Schema.optional<Schema.String>;
|
|
29
27
|
}>]>;
|
|
30
28
|
export type Source = Schema.Schema.Type<typeof Source>;
|
|
29
|
+
export type AspectRatio = `${number}:${number}`;
|
|
30
|
+
export declare const AspectRatio: Schema.declare<`${number}:${number}`, `${number}:${number}`>;
|
|
31
31
|
export declare const Kind: Schema.Literals<readonly ["image", "video", "audio", "document", "other"]>;
|
|
32
32
|
export type Kind = Schema.Schema.Type<typeof Kind>;
|
|
33
33
|
export declare const kindOf: (mediaType: string) => Kind;
|
|
@@ -65,6 +65,8 @@ export declare class Asset {
|
|
|
65
65
|
/** Epoch milliseconds after which a `url` source stops resolving. */
|
|
66
66
|
readonly expiresAt?: number;
|
|
67
67
|
readonly providerMetadata?: ProviderMetadata;
|
|
68
|
+
/** Transient download credentials for `url` sources; see `Asset.Input.headers`. */
|
|
69
|
+
readonly headers?: Record<string, string>;
|
|
68
70
|
constructor(input: Asset.Input);
|
|
69
71
|
/** Inline payload without effects, for protocols that embed base64 or data URLs directly. */
|
|
70
72
|
inline(): Inline | undefined;
|
|
@@ -84,9 +86,6 @@ export declare class Asset {
|
|
|
84
86
|
} | {
|
|
85
87
|
readonly type: "url";
|
|
86
88
|
readonly url: string;
|
|
87
|
-
readonly headers?: {
|
|
88
|
-
readonly [x: string]: string;
|
|
89
|
-
} | undefined;
|
|
90
89
|
readonly mediaType?: string | undefined;
|
|
91
90
|
readonly expiresAt?: number | undefined;
|
|
92
91
|
} | {
|
|
@@ -122,6 +121,12 @@ export declare namespace Asset {
|
|
|
122
121
|
readonly source: Source;
|
|
123
122
|
readonly info?: Info;
|
|
124
123
|
readonly providerMetadata?: ProviderMetadata;
|
|
124
|
+
/**
|
|
125
|
+
* Headers required to download a `url` source, such as the provider API key Veo demands for its file URIs.
|
|
126
|
+
* They are runtime-only: never part of `source`, `toJSON()`, or `AssetSchema`, so a persisted asset cannot leak
|
|
127
|
+
* credentials and cannot be downloaded again after a round-trip. Call `materialize()` before persisting.
|
|
128
|
+
*/
|
|
129
|
+
readonly headers?: Record<string, string>;
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
/** JSON form of an asset: the serializable `Source` plus caller-supplied metadata. `bytes` sources encode as base64. */
|
|
@@ -140,8 +145,6 @@ export declare const AssetEncoded: Schema.Struct<{
|
|
|
140
145
|
readonly mediaType: Schema.optional<Schema.String>;
|
|
141
146
|
/** Epoch milliseconds after which the provider no longer serves the URL. */
|
|
142
147
|
readonly expiresAt: Schema.optional<Schema.Number>;
|
|
143
|
-
/** Headers required to fetch the URL, such as provider auth for Veo downloads. */
|
|
144
|
-
readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
|
|
145
148
|
}>, Schema.Struct<{
|
|
146
149
|
readonly type: Schema.Literal<"ref">;
|
|
147
150
|
readonly provider: Schema.brand<Schema.String, "AI.ProviderID">;
|
|
@@ -175,8 +178,6 @@ export declare const AssetSchema: Schema.decodeTo<Schema.declare<Asset, Asset>,
|
|
|
175
178
|
readonly mediaType: Schema.optional<Schema.String>;
|
|
176
179
|
/** Epoch milliseconds after which the provider no longer serves the URL. */
|
|
177
180
|
readonly expiresAt: Schema.optional<Schema.Number>;
|
|
178
|
-
/** Headers required to fetch the URL, such as provider auth for Veo downloads. */
|
|
179
|
-
readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
|
|
180
181
|
}>, Schema.Struct<{
|
|
181
182
|
readonly type: Schema.Literal<"ref">;
|
|
182
183
|
readonly provider: Schema.brand<Schema.String, "AI.ProviderID">;
|
package/dist/media.js
CHANGED
|
@@ -5,7 +5,7 @@ import { ProviderID } from "./schema/ids.js";
|
|
|
5
5
|
import { AIError, HttpContext, InvalidProviderOutputError, InvalidRequestError } from "./schema/errors.js";
|
|
6
6
|
import { ProviderMetadata } from "./schema/options.js";
|
|
7
7
|
import { Service } from "./route/executor-service.js";
|
|
8
|
-
import { detectMediaType,
|
|
8
|
+
import { detectMediaType, fileMediaType } from "./utils/media-type.js";
|
|
9
9
|
export { detectMediaType } from "./utils/media-type.js";
|
|
10
10
|
const OCTET_STREAM = "application/octet-stream";
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
@@ -27,8 +27,6 @@ const UrlSource = Schema.Struct({
|
|
|
27
27
|
mediaType: Schema.optional(Schema.String),
|
|
28
28
|
/** Epoch milliseconds after which the provider no longer serves the URL. */
|
|
29
29
|
expiresAt: Schema.optional(Schema.Number),
|
|
30
|
-
/** Headers required to fetch the URL, such as provider auth for Veo downloads. */
|
|
31
|
-
headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),
|
|
32
30
|
});
|
|
33
31
|
/** A provider-side handle: OpenAI `file_id`, Gemini file URI, `gs://`, `runway://`, or a prior generation id. */
|
|
34
32
|
const RefSource = Schema.Struct({
|
|
@@ -40,9 +38,7 @@ const RefSource = Schema.Struct({
|
|
|
40
38
|
export const Source = Schema.Union([BytesSource, Base64Source, UrlSource, RefSource])
|
|
41
39
|
.pipe(Schema.toTaggedUnion("type"))
|
|
42
40
|
.annotate({ identifier: "Media.Source" });
|
|
43
|
-
|
|
44
|
-
// Kind, Info, Notice
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
41
|
+
export const AspectRatio = Schema.declare((value) => typeof value === "string" && /^\d+(?:\.\d+)?:\d+(?:\.\d+)?$/.test(value), { title: "Media.AspectRatio" });
|
|
46
42
|
export const Kind = Schema.Literals(["image", "video", "audio", "document", "other"]);
|
|
47
43
|
export const kindOf = (mediaType) => {
|
|
48
44
|
const lower = mediaType.toLowerCase();
|
|
@@ -85,6 +81,8 @@ export class Asset {
|
|
|
85
81
|
/** Epoch milliseconds after which a `url` source stops resolving. */
|
|
86
82
|
expiresAt;
|
|
87
83
|
providerMetadata;
|
|
84
|
+
/** Transient download credentials for `url` sources; see `Asset.Input.headers`. */
|
|
85
|
+
headers;
|
|
88
86
|
// Derived payload forms are cached on the instance because every protocol lowering re-reads the same payload. The
|
|
89
87
|
// cache is check-then-set (concurrent first reads of a `url` source may both download) and is never observable
|
|
90
88
|
// through `source`, so round-tripping through `Media.from(asset.source)` stays lossless.
|
|
@@ -100,6 +98,7 @@ export class Asset {
|
|
|
100
98
|
this.info = input.info;
|
|
101
99
|
this.expiresAt = input.source.type === "url" ? input.source.expiresAt : undefined;
|
|
102
100
|
this.providerMetadata = input.providerMetadata;
|
|
101
|
+
this.headers = input.source.type === "url" ? input.headers : undefined;
|
|
103
102
|
}
|
|
104
103
|
/** Inline payload without effects, for protocols that embed base64 or data URLs directly. */
|
|
105
104
|
inline() {
|
|
@@ -122,7 +121,7 @@ export class Asset {
|
|
|
122
121
|
return Effect.fail(invalid(`Cannot materialize provider ref ${source.provider}:${source.id}`));
|
|
123
122
|
const decoded = source.type === "base64"
|
|
124
123
|
? Effect.fromResult(Encoding.decodeBase64(source.data)).pipe(Effect.mapError((cause) => invalid(`Media asset contains invalid base64 data`, cause)))
|
|
125
|
-
: download(source);
|
|
124
|
+
: download(source, this.headers);
|
|
126
125
|
return decoded.pipe(Effect.tap((data) => Effect.sync(() => (this.#bytes = data))));
|
|
127
126
|
});
|
|
128
127
|
}
|
|
@@ -177,9 +176,9 @@ export const AssetSchema = AssetEncoded.pipe(Schema.decodeTo(AssetInstance, {
|
|
|
177
176
|
decode: SchemaGetter.transform((encoded) => new Asset(encoded)),
|
|
178
177
|
encode: SchemaGetter.transform(encodeAsset),
|
|
179
178
|
}));
|
|
180
|
-
const download = Effect.fn("Media.download")(function* (source) {
|
|
179
|
+
const download = Effect.fn("Media.download")(function* (source, headers) {
|
|
181
180
|
const executor = yield* Service;
|
|
182
|
-
const response = yield* executor.execute(HttpClientRequest.get(source.url).pipe(HttpClientRequest.setHeaders(
|
|
181
|
+
const response = yield* executor.execute(HttpClientRequest.get(source.url).pipe(HttpClientRequest.setHeaders(headers ?? {})));
|
|
183
182
|
const buffer = yield* response.arrayBuffer.pipe(Effect.mapError((cause) => new AIError({
|
|
184
183
|
reason: new InvalidProviderOutputError({
|
|
185
184
|
message: `Failed to read media from ${source.url}`,
|
|
@@ -193,8 +192,8 @@ export const from = (source, options) => new Asset({ ...options, source });
|
|
|
193
192
|
export const bytes = (data, mediaType, options) => from({ type: "bytes", data, mediaType: mediaType ?? detectMediaType(data) ?? OCTET_STREAM }, options);
|
|
194
193
|
export const base64 = (data, mediaType, options) => from({ type: "base64", data, mediaType }, options);
|
|
195
194
|
export const url = (value, options) => {
|
|
196
|
-
const { mediaType, expiresAt,
|
|
197
|
-
return from({ type: "url", url: value, mediaType, expiresAt
|
|
195
|
+
const { mediaType, expiresAt, ...rest } = options ?? {};
|
|
196
|
+
return from({ type: "url", url: value, mediaType, expiresAt }, rest);
|
|
198
197
|
};
|
|
199
198
|
export const ref = (provider, id, mediaType, options) => from({ type: "ref", provider: ProviderID.make(provider), id, mediaType }, options);
|
|
200
199
|
const DATA_URL = /^data:([^;,]+)(?:;[^,]*)*;base64,(.*)$/s;
|
|
@@ -216,7 +215,7 @@ export const file = (path, options) => Effect.gen(function* () {
|
|
|
216
215
|
const data = yield* fs
|
|
217
216
|
.readFile(path)
|
|
218
217
|
.pipe(Effect.mapError((cause) => invalid(`Failed to read media file ${path}`, cause)));
|
|
219
|
-
return bytes(data,
|
|
218
|
+
return bytes(data, fileMediaType(data, path), options);
|
|
220
219
|
});
|
|
221
220
|
/** Materialize an asset and write its bytes through `FileSystem`. */
|
|
222
221
|
export const write = (asset, path) => Effect.gen(function* () {
|