@opencode/ai 2.0.15 → 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 +286 -2
- package/dist/generation.d.ts +36 -22
- package/dist/generation.js +53 -24
- package/dist/image-client.d.ts +14 -7
- package/dist/image-client.js +24 -8
- package/dist/image.d.ts +398 -47
- package/dist/image.js +47 -45
- package/dist/index.d.ts +13 -1
- package/dist/index.js +9 -0
- package/dist/media-model.d.ts +44 -0
- package/dist/media-model.js +49 -0
- package/dist/media.d.ts +10 -9
- package/dist/media.js +9 -10
- package/dist/promise.d.ts +428 -8
- package/dist/promise.js +40 -3
- package/dist/protocols/alibaba-chat.d.ts +12 -0
- package/dist/protocols/alibaba-responses.d.ts +2 -2
- package/dist/protocols/anthropic-messages.js +1 -2
- package/dist/protocols/assemblyai-transcription.d.ts +40 -0
- package/dist/protocols/assemblyai-transcription.js +138 -0
- package/dist/protocols/bedrock-converse.js +5 -11
- 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 +9 -9
- package/dist/protocols/gemini.js +8 -34
- package/dist/protocols/google-images.js +2 -14
- 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.js +2 -9
- package/dist/protocols/meta-responses.d.ts +4 -4
- package/dist/protocols/meta-responses.js +1 -1
- package/dist/protocols/open-responses.d.ts +6 -6
- package/dist/protocols/open-responses.js +1 -2
- package/dist/protocols/openai-chat.d.ts +84 -0
- package/dist/protocols/openai-chat.js +26 -14
- 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 +124 -3
- package/dist/protocols/openai-images.js +107 -54
- 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 +13 -3
- package/dist/protocols/shared.js +23 -3
- package/dist/protocols/stability-images.d.ts +38 -0
- package/dist/protocols/stability-images.js +148 -0
- 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 +8 -0
- package/dist/protocols/utils/media-input.js +18 -0
- 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/xai-images.js +1 -12
- 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/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/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/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/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 +3 -3
- package/dist/providers/google.d.ts +18 -3
- package/dist/providers/google.js +11 -2
- 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 +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 +48 -0
- 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/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/framing.d.ts +5 -1
- package/dist/route/framing.js +9 -0
- package/dist/route/media-protocol.d.ts +116 -3
- package/dist/route/media-protocol.js +60 -4
- package/dist/route/media.d.ts +58 -7
- package/dist/route/media.js +201 -29
- package/dist/schema/events.d.ts +0 -6
- package/dist/schema/messages.d.ts +0 -3
- package/dist/schema/options.d.ts +4 -3
- package/dist/schema/options.js +3 -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/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 +1 -0
- package/dist/utils/media-type.js +22 -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 +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/image.js
CHANGED
|
@@ -1,42 +1,20 @@
|
|
|
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, composeAnyRoute, 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
|
-
}
|
|
8
|
+
export class ImageModel extends MediaModel {
|
|
18
9
|
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
|
-
});
|
|
10
|
+
return new ImageModel(input);
|
|
25
11
|
}
|
|
26
|
-
/** Compose an inline image protocol with its canonical path into a model for one deployment. */
|
|
27
12
|
static fromRoute(route, input) {
|
|
28
|
-
return ImageModel
|
|
13
|
+
return new ImageModel({
|
|
29
14
|
id: input.id,
|
|
30
15
|
provider: route.provider,
|
|
31
16
|
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
|
-
}),
|
|
17
|
+
route: composeAnyRoute(route, input, collectResponse),
|
|
40
18
|
});
|
|
41
19
|
}
|
|
42
20
|
}
|
|
@@ -44,7 +22,7 @@ export const ImageModelSchema = Schema.declare((value) => value instanceof Image
|
|
|
44
22
|
expected: "Image.Model",
|
|
45
23
|
});
|
|
46
24
|
export const ImageSize = Schema.declare((value) => typeof value === "string" && /^\d+x\d+$/.test(value), { title: "ImageSize" });
|
|
47
|
-
export const ImageAspectRatio =
|
|
25
|
+
export const ImageAspectRatio = Media.AspectRatio;
|
|
48
26
|
export class ImageRequest extends Schema.Class("Image.Request")({
|
|
49
27
|
model: ImageModelSchema,
|
|
50
28
|
prompt: Schema.String,
|
|
@@ -74,6 +52,12 @@ export class ImageResponse extends Schema.Class("Image.Response")({
|
|
|
74
52
|
return this.images[0];
|
|
75
53
|
}
|
|
76
54
|
}
|
|
55
|
+
/** The `index`-th lower-fidelity preview of an image still generating; the `image` event supersedes it. */
|
|
56
|
+
export const ImagePartialEvent = Schema.Struct({
|
|
57
|
+
type: Schema.tag("image-partial"),
|
|
58
|
+
index: Schema.Number,
|
|
59
|
+
image: Media.AssetSchema,
|
|
60
|
+
}).annotate({ identifier: "Image.Event.Partial" });
|
|
77
61
|
export const ImageOutputEvent = Schema.Struct({
|
|
78
62
|
type: Schema.tag("image"),
|
|
79
63
|
index: Schema.Number,
|
|
@@ -85,14 +69,22 @@ export const ImageFinishEvent = Schema.Struct({
|
|
|
85
69
|
notices: Schema.optional(Schema.Array(Media.Notice)),
|
|
86
70
|
providerMetadata: Schema.optional(ProviderMetadata),
|
|
87
71
|
}).annotate({ identifier: "Image.Event.Finish" });
|
|
88
|
-
const imageEventTagged = Schema.Union([
|
|
72
|
+
const imageEventTagged = Schema.Union([
|
|
73
|
+
QueuedEvent,
|
|
74
|
+
ProgressEvent,
|
|
75
|
+
ImagePartialEvent,
|
|
76
|
+
ImageOutputEvent,
|
|
77
|
+
ImageFinishEvent,
|
|
78
|
+
]).pipe(Schema.toTaggedUnion("type"));
|
|
89
79
|
export const ImageEvent = Object.assign(imageEventTagged, {
|
|
90
80
|
is: {
|
|
81
|
+
generationQueued: imageEventTagged.guards["generation-queued"],
|
|
82
|
+
generationProgress: imageEventTagged.guards["generation-progress"],
|
|
83
|
+
imagePartial: imageEventTagged.guards["image-partial"],
|
|
91
84
|
image: imageEventTagged.guards.image,
|
|
92
85
|
finish: imageEventTagged.guards.finish,
|
|
93
86
|
},
|
|
94
87
|
});
|
|
95
|
-
/** Inline routes produce every image at once; expand the response into the streaming event shape. */
|
|
96
88
|
export const responseEvents = (response) => [
|
|
97
89
|
...response.images.map((image, index) => ImageOutputEvent.make({ index, image })),
|
|
98
90
|
ImageFinishEvent.make({
|
|
@@ -101,6 +93,18 @@ export const responseEvents = (response) => [
|
|
|
101
93
|
providerMetadata: response.providerMetadata,
|
|
102
94
|
}),
|
|
103
95
|
];
|
|
96
|
+
const collectResponse = (events) => {
|
|
97
|
+
const finish = events.find(ImageEvent.is.finish);
|
|
98
|
+
// Every image protocol's `finish` emits the terminal event or fails, so a completed stream always has one.
|
|
99
|
+
if (finish === undefined)
|
|
100
|
+
return Effect.die(new Error("The image stream completed without a finish event"));
|
|
101
|
+
return Effect.succeed(new ImageResponse({
|
|
102
|
+
images: events.filter(ImageEvent.is.image).map((event) => event.image),
|
|
103
|
+
usage: finish.usage,
|
|
104
|
+
notices: finish.notices,
|
|
105
|
+
providerMetadata: finish.providerMetadata,
|
|
106
|
+
}));
|
|
107
|
+
};
|
|
104
108
|
export function request(input) {
|
|
105
109
|
if (input instanceof ImageRequest)
|
|
106
110
|
return input;
|
|
@@ -109,23 +113,21 @@ export function request(input) {
|
|
|
109
113
|
http: input.http === undefined ? undefined : HttpOptions.make(input.http),
|
|
110
114
|
});
|
|
111
115
|
}
|
|
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)));
|
|
116
|
+
const requestEffect = (input) => tryRequest(() => request(input));
|
|
117
|
+
export function generate(input, options) {
|
|
118
|
+
return requestEffect(input).pipe(Effect.flatMap((request) => ImageClient.generate(request, options)));
|
|
119
|
+
}
|
|
120
|
+
export function stream(input, options) {
|
|
121
|
+
return Stream.unwrap(requestEffect(input).pipe(Effect.map((request) => ImageClient.stream(request, options))));
|
|
123
122
|
}
|
|
124
|
-
export function
|
|
125
|
-
return
|
|
123
|
+
export function start(input) {
|
|
124
|
+
return requestEffect(input).pipe(Effect.flatMap((request) => ImageClient.start(request)));
|
|
126
125
|
}
|
|
126
|
+
export const resume = (model, token) => ImageClient.resume(model, token);
|
|
127
127
|
export const Image = {
|
|
128
128
|
request,
|
|
129
129
|
generate,
|
|
130
130
|
stream,
|
|
131
|
+
start,
|
|
132
|
+
resume,
|
|
131
133
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -9,9 +9,21 @@ export * from "./schema/index.js";
|
|
|
9
9
|
export { ImageAspectRatio, ImageEvent, ImageModel, ImageModelSchema, ImageRequest, ImageResponse, ImageSize, } from "./image.js";
|
|
10
10
|
export type { ImageFormat, ImageModelOptions, ImageOptions, ImageRequestFor, ImageRequestInput, ImageRoute, } from "./image.js";
|
|
11
11
|
export { Image } from "./image.js";
|
|
12
|
+
export { VideoClient } from "./video-client.js";
|
|
13
|
+
export { VideoAspectRatio, VideoEvent, VideoFrames, VideoModel, VideoModelSchema, VideoRequest, VideoResponse, } from "./video.js";
|
|
14
|
+
export type { VideoModelOptions, VideoOptions, VideoRequestFor, VideoRequestInput, VideoResolution, VideoRoute, } from "./video.js";
|
|
15
|
+
export { Video } from "./video.js";
|
|
16
|
+
export { SpeechClient } from "./speech-client.js";
|
|
17
|
+
export { SpeechEvent, SpeechModel, SpeechModelSchema, SpeechRequest, SpeechResponse, SpeechTimestamp, SpeechVoice, } from "./speech.js";
|
|
18
|
+
export type { SpeechFormat, SpeechModelOptions, SpeechOptions, SpeechRequestFor, SpeechRequestInput, SpeechRoute, } from "./speech.js";
|
|
19
|
+
export { Speech } from "./speech.js";
|
|
20
|
+
export { TranscriptionClient } from "./transcription-client.js";
|
|
21
|
+
export { TranscriptionEvent, TranscriptionModel, TranscriptionModelSchema, TranscriptionRequest, TranscriptionResponse, TranscriptionSegment, TranscriptionTimestamps, TranscriptionWord, } from "./transcription.js";
|
|
22
|
+
export type { TranscriptionModelOptions, TranscriptionOptions, TranscriptionRequestFor, TranscriptionRequestInput, TranscriptionRoute, } from "./transcription.js";
|
|
23
|
+
export { Transcription } from "./transcription.js";
|
|
12
24
|
export { Media } from "./media.js";
|
|
13
25
|
export { Generation } from "./generation.js";
|
|
14
|
-
export type { Event as GenerationEvent, Poll, Route as GenerationRoute, Snapshot as GenerationSnapshot, Status as GenerationStatus } from "./generation.js";
|
|
26
|
+
export type { AwaitOptions as GenerationAwaitOptions, Event as GenerationEvent, Poll, Route as GenerationRoute, Snapshot as GenerationSnapshot, Status as GenerationStatus, } from "./generation.js";
|
|
15
27
|
export { Tool, ToolFailure, toDefinitions } from "./tool.js";
|
|
16
28
|
export { ToolRuntime } from "./tool-runtime.js";
|
|
17
29
|
export type { DispatchResult as ToolDispatchResult, ToolSettlement } from "./tool-runtime.js";
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,15 @@ export { isContextOverflow, isContextOverflowFailure } from "./provider-error.js
|
|
|
7
7
|
export * from "./schema/index.js";
|
|
8
8
|
export { ImageAspectRatio, ImageEvent, ImageModel, ImageModelSchema, ImageRequest, ImageResponse, ImageSize, } from "./image.js";
|
|
9
9
|
export { Image } from "./image.js";
|
|
10
|
+
export { VideoClient } from "./video-client.js";
|
|
11
|
+
export { VideoAspectRatio, VideoEvent, VideoFrames, VideoModel, VideoModelSchema, VideoRequest, VideoResponse, } from "./video.js";
|
|
12
|
+
export { Video } from "./video.js";
|
|
13
|
+
export { SpeechClient } from "./speech-client.js";
|
|
14
|
+
export { SpeechEvent, SpeechModel, SpeechModelSchema, SpeechRequest, SpeechResponse, SpeechTimestamp, SpeechVoice, } from "./speech.js";
|
|
15
|
+
export { Speech } from "./speech.js";
|
|
16
|
+
export { TranscriptionClient } from "./transcription-client.js";
|
|
17
|
+
export { TranscriptionEvent, TranscriptionModel, TranscriptionModelSchema, TranscriptionRequest, TranscriptionResponse, TranscriptionSegment, TranscriptionTimestamps, TranscriptionWord, } from "./transcription.js";
|
|
18
|
+
export { Transcription } from "./transcription.js";
|
|
10
19
|
export { Media } from "./media.js";
|
|
11
20
|
export { Generation } from "./generation.js";
|
|
12
21
|
export { Tool, ToolFailure, toDefinitions } from "./tool.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
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`) extend it with their route type and a nominal marker so one cannot stand
|
|
9
|
+
* in for the other in requests.
|
|
10
|
+
*/
|
|
11
|
+
export declare class MediaModel<Route, Options> {
|
|
12
|
+
protected readonly _Options: (options: 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
|
+
interface Input<Route> {
|
|
21
|
+
readonly id: string | ModelID;
|
|
22
|
+
readonly provider: string | ProviderID;
|
|
23
|
+
readonly route: Route;
|
|
24
|
+
readonly http?: HttpOptions;
|
|
25
|
+
}
|
|
26
|
+
/** A protocol plus its canonical start path; `ModelInput.baseURL` overrides `baseURL` per deployment. */
|
|
27
|
+
interface RouteInput<Request extends MediaRoute.MediaRequest, Protocol> {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly provider: string | ProviderID;
|
|
30
|
+
readonly protocol: Protocol;
|
|
31
|
+
readonly path: Endpoint.EndpointPart<MediaProtocol.Body, Request>;
|
|
32
|
+
readonly baseURL?: string;
|
|
33
|
+
/** Headers the protocol requires on every call, such as a pinned API version; deployment headers win. */
|
|
34
|
+
readonly headers?: Record<string, string>;
|
|
35
|
+
}
|
|
36
|
+
type AnyRouteInput<Request extends MediaRoute.MediaRequest, Event, Response, Frame, State, Token> = RouteInput<Request, MediaProtocol.Inline<Request, Response>> | RouteInput<MediaProtocol.Addressed<Request>, MediaProtocol.Streamed<Request, Event, Frame, State>> | RouteInput<Request, MediaProtocol.Queued<Request, Response, Token>>;
|
|
37
|
+
}
|
|
38
|
+
/** Compose a protocol route input with one deployment through `MediaRoute.inline`, `queued`, or `stream`. */
|
|
39
|
+
export declare const composeRoute: <Request extends MediaRoute.MediaRequest, Protocol, Route>(compose: (input: MediaRoute.Composition<Request> & {
|
|
40
|
+
readonly protocol: Protocol;
|
|
41
|
+
}) => Route, route: MediaModel.RouteInput<Request, Protocol>, input: MediaRoute.ModelInput) => Route;
|
|
42
|
+
export declare const composeAnyRoute: <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>;
|
|
43
|
+
/** Lift a synchronous Schema-class constructor into a typed `InvalidRequest` failure. */
|
|
44
|
+
export declare const tryRequest: <A>(make: () => A) => Effect.Effect<A, AIError>;
|
|
@@ -0,0 +1,49 @@
|
|
|
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`) extend it with their route type and a nominal marker so one cannot stand
|
|
8
|
+
* 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 = (compose, route, input) => compose({
|
|
24
|
+
id: route.id,
|
|
25
|
+
provider: route.provider,
|
|
26
|
+
protocol: route.protocol,
|
|
27
|
+
endpoint: Endpoint.path(route.path, { baseURL: input.baseURL ?? route.baseURL }),
|
|
28
|
+
auth: input.auth,
|
|
29
|
+
headers: route.headers === undefined && input.headers === undefined ? undefined : { ...route.headers, ...input.headers },
|
|
30
|
+
});
|
|
31
|
+
export const composeAnyRoute = (route, input, collect) => {
|
|
32
|
+
if (isStreamInput(route))
|
|
33
|
+
return composeRoute((composition) => MediaRoute.stream({ ...composition, collect }), route, input);
|
|
34
|
+
if (isQueuedInput(route))
|
|
35
|
+
return composeRoute(MediaRoute.queued, route, input);
|
|
36
|
+
return composeRoute(MediaRoute.inline, route, input);
|
|
37
|
+
};
|
|
38
|
+
const isStreamInput = (route) => route.protocol.kind === "stream";
|
|
39
|
+
const isQueuedInput = (route) => route.protocol.kind === "queued";
|
|
40
|
+
/** Lift a synchronous Schema-class constructor into a typed `InvalidRequest` failure. */
|
|
41
|
+
export const tryRequest = (make) => Effect.try({
|
|
42
|
+
try: make,
|
|
43
|
+
catch: (error) => new AIError({
|
|
44
|
+
reason: new InvalidRequestError({
|
|
45
|
+
message: error instanceof Error ? error.message : String(error),
|
|
46
|
+
cause: error,
|
|
47
|
+
}),
|
|
48
|
+
}),
|
|
49
|
+
});
|
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
|
@@ -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;
|