@opencode/ai 2.0.16 → 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 +187 -129
- 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 +6 -10
- package/dist/generation.js +17 -20
- package/dist/image-client.d.ts +59 -24
- package/dist/image-client.js +16 -40
- package/dist/image.d.ts +15 -27
- package/dist/image.js +4 -15
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -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 +9 -10
- package/dist/media-model.js +10 -12
- package/dist/media.js +2 -2
- package/dist/promise.d.ts +68 -30
- package/dist/promise.js +52 -31
- 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/anthropic-messages.d.ts +34 -34
- package/dist/protocols/anthropic-messages.js +14 -8
- package/dist/protocols/assemblyai-transcription.d.ts +2 -1
- package/dist/protocols/assemblyai-transcription.js +14 -16
- package/dist/protocols/bedrock-converse.d.ts +7 -0
- package/dist/protocols/bedrock-converse.js +37 -11
- package/dist/protocols/bfl-images.d.ts +7 -1
- package/dist/protocols/bfl-images.js +36 -36
- package/dist/protocols/cartesia-speech.d.ts +18 -2
- package/dist/protocols/cartesia-speech.js +10 -16
- package/dist/protocols/deepgram-speech.d.ts +19 -3
- package/dist/protocols/deepgram-speech.js +11 -12
- package/dist/protocols/deepgram-transcription.d.ts +2 -1
- package/dist/protocols/deepgram-transcription.js +9 -13
- package/dist/protocols/elevenlabs-speech.d.ts +19 -3
- package/dist/protocols/elevenlabs-speech.js +9 -13
- package/dist/protocols/fal-images.d.ts +2 -1
- package/dist/protocols/fal-images.js +30 -40
- package/dist/protocols/fal-video.d.ts +2 -2
- package/dist/protocols/fal-video.js +9 -24
- package/dist/protocols/gemini.d.ts +13 -13
- package/dist/protocols/gemini.js +16 -7
- package/dist/protocols/google-images.d.ts +3 -3
- package/dist/protocols/google-images.js +11 -21
- package/dist/protocols/google-speech.d.ts +16 -0
- package/dist/protocols/google-speech.js +20 -16
- package/dist/protocols/google-transcription.d.ts +2 -1
- package/dist/protocols/google-transcription.js +8 -20
- package/dist/protocols/google-video.d.ts +2 -2
- package/dist/protocols/google-video.js +14 -30
- package/dist/protocols/meta-images.d.ts +3 -4
- package/dist/protocols/meta-images.js +12 -21
- package/dist/protocols/meta-messages.d.ts +5 -5
- package/dist/protocols/meta-responses.js +6 -4
- package/dist/protocols/open-responses.d.ts +4 -3
- package/dist/protocols/open-responses.js +4 -8
- package/dist/protocols/openai-chat.js +3 -4
- package/dist/protocols/openai-images.d.ts +7 -5
- package/dist/protocols/openai-images.js +65 -66
- package/dist/protocols/openai-responses.d.ts +10 -10
- package/dist/protocols/openai-responses.js +31 -30
- package/dist/protocols/openai-speech.d.ts +21 -1
- package/dist/protocols/openai-speech.js +11 -12
- package/dist/protocols/openai-transcription.d.ts +4 -0
- package/dist/protocols/openai-transcription.js +44 -32
- package/dist/protocols/replicate-images.js +11 -17
- package/dist/protocols/runway-video.d.ts +3 -3
- package/dist/protocols/runway-video.js +11 -17
- package/dist/protocols/shared.d.ts +11 -17
- package/dist/protocols/shared.js +11 -40
- package/dist/protocols/stability-images.d.ts +2 -1
- package/dist/protocols/stability-images.js +24 -36
- package/dist/protocols/utils/fal-queue.d.ts +1 -3
- package/dist/protocols/utils/fal-queue.js +4 -6
- package/dist/protocols/utils/media-input.d.ts +15 -1
- package/dist/protocols/utils/media-input.js +22 -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 +3 -3
- package/dist/protocols/utils/speech-stream.js +1 -4
- package/dist/protocols/utils/tool-schema.d.ts +2 -2
- package/dist/protocols/utils/tool-schema.js +29 -9
- package/dist/protocols/xai-images.d.ts +4 -4
- package/dist/protocols/xai-images.js +14 -29
- package/dist/protocols/xai-responses.js +1 -1
- package/dist/protocols/xai-video.js +12 -18
- 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 +7 -1
- package/dist/providers/alibaba.d.ts +1 -1
- 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 +1 -1
- package/dist/providers/assemblyai.js +5 -10
- package/dist/providers/azure.d.ts +4 -4
- package/dist/providers/azure.js +2 -2
- package/dist/providers/black-forest-labs.d.ts +1 -1
- package/dist/providers/black-forest-labs.js +5 -10
- package/dist/providers/cartesia.d.ts +1 -1
- package/dist/providers/cartesia.js +5 -10
- package/dist/providers/cloudflare-ai-gateway.d.ts +14 -14
- package/dist/providers/deepgram.d.ts +1 -1
- package/dist/providers/deepgram.js +6 -12
- package/dist/providers/elevenlabs.d.ts +1 -1
- package/dist/providers/elevenlabs.js +5 -10
- package/dist/providers/fal.d.ts +1 -1
- package/dist/providers/fal.js +5 -12
- package/dist/providers/google-vertex-messages.d.ts +5 -5
- package/dist/providers/google-vertex.d.ts +3 -3
- package/dist/providers/google.d.ts +3 -3
- package/dist/providers/google.js +7 -12
- package/dist/providers/meta.d.ts +8 -8
- package/dist/providers/meta.js +4 -8
- package/dist/providers/minimax.d.ts +5 -5
- package/dist/providers/moonshot.d.ts +5 -5
- package/dist/providers/openai-options.d.ts +3 -9
- package/dist/providers/openai-options.js +4 -7
- package/dist/providers/openai.d.ts +9 -10
- package/dist/providers/openai.js +11 -12
- package/dist/providers/opencode-zen.js +1 -1
- package/dist/providers/openrouter.d.ts +6 -7
- package/dist/providers/openrouter.js +10 -5
- package/dist/providers/replicate.d.ts +1 -1
- package/dist/providers/replicate.js +5 -10
- package/dist/providers/runway.d.ts +1 -1
- package/dist/providers/runway.js +5 -10
- package/dist/providers/stability.d.ts +1 -1
- package/dist/providers/stability.js +6 -11
- package/dist/providers/typesafe-ai.js +1 -1
- package/dist/providers/vercel-ai-gateway.js +1 -1
- package/dist/providers/xai.js +5 -10
- package/dist/providers/zai-coding-plan.d.ts +1 -1
- package/dist/providers/zai.js +4 -8
- package/dist/route/auth.d.ts +1 -1
- package/dist/route/auth.js +14 -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 +10 -1
- package/dist/route/framing.js +45 -5
- package/dist/route/index.d.ts +1 -1
- package/dist/route/media-protocol.d.ts +49 -35
- package/dist/route/media-protocol.js +77 -65
- package/dist/route/media.d.ts +10 -16
- package/dist/route/media.js +46 -62
- package/dist/route/protocol.d.ts +3 -1
- package/dist/schema/options.d.ts +6 -3
- package/dist/schema/options.js +7 -3
- package/dist/speech-client.d.ts +62 -17
- package/dist/speech-client.js +17 -21
- package/dist/speech.d.ts +178 -21
- package/dist/speech.js +13 -8
- package/dist/testing.d.ts +2 -2
- package/dist/transcription-client.d.ts +78 -24
- package/dist/transcription-client.js +9 -40
- package/dist/transcription.d.ts +15 -27
- package/dist/transcription.js +4 -10
- package/dist/utils/json.d.ts +4 -0
- package/dist/utils/json.js +4 -0
- package/dist/utils/media-type.d.ts +2 -1
- package/dist/utils/media-type.js +3 -1
- package/dist/video-client.d.ts +55 -24
- package/dist/video-client.js +16 -36
- package/dist/video.d.ts +18 -26
- package/dist/video.js +15 -16
- package/package.json +3 -3
- 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
|
@@ -11,11 +11,11 @@ export declare class Service extends Service_base {
|
|
|
11
11
|
}
|
|
12
12
|
export declare const evaluate: <Options extends EvaluationOptions, const Questions extends EvaluationQuestions>(request: EvaluationRequestFor<Options, Questions>) => Effect.Effect<EvaluationResponseFor<Questions>, AIError, Service>;
|
|
13
13
|
export declare const layer: Layer.Layer<Service, never, RequestExecutor.Service>;
|
|
14
|
-
export declare const fetchLayer: Layer.Layer<Service, never, never>;
|
|
14
|
+
export declare const fetchLayer: Layer.Layer<import("../route/executor-service.js").RequestExecutorService | Service, never, never>;
|
|
15
15
|
export declare const EvaluationClient: {
|
|
16
16
|
readonly Service: typeof Service;
|
|
17
|
-
readonly layer: Layer.Layer<Service, never,
|
|
18
|
-
readonly fetchLayer: Layer.Layer<Service, never, never>;
|
|
17
|
+
readonly layer: Layer.Layer<Service, never, import("../route/executor-service.js").RequestExecutorService>;
|
|
18
|
+
readonly fetchLayer: Layer.Layer<import("../route/executor-service.js").RequestExecutorService | Service, never, never>;
|
|
19
19
|
readonly evaluate: <Options extends EvaluationOptions, const Questions extends EvaluationQuestions>(request: EvaluationRequestFor<Options, Questions>) => Effect.Effect<EvaluationResponseFor<Questions>, AIError, Service>;
|
|
20
20
|
};
|
|
21
21
|
export {};
|
|
@@ -55,7 +55,7 @@ export const layer = Layer.effect(Service, Effect.gen(function* () {
|
|
|
55
55
|
})),
|
|
56
56
|
});
|
|
57
57
|
}));
|
|
58
|
-
export const fetchLayer = layer.pipe(Layer.
|
|
58
|
+
export const fetchLayer = layer.pipe(Layer.provideMerge(RequestExecutor.fetchLayer));
|
|
59
59
|
export const EvaluationClient = {
|
|
60
60
|
Service,
|
|
61
61
|
layer,
|
|
@@ -94,7 +94,7 @@ export function request(input) {
|
|
|
94
94
|
return new EvaluationRequest({
|
|
95
95
|
...input,
|
|
96
96
|
model: input.model,
|
|
97
|
-
http:
|
|
97
|
+
http: HttpOptions.make(input.http),
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
export function run(input) {
|
package/dist/generation.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Duration, Effect,
|
|
1
|
+
import { Duration, Effect, Schema, Stream } from "effect";
|
|
2
2
|
import { AIError } from "./schema/errors.js";
|
|
3
3
|
export declare const Status: Schema.Literals<readonly ["queued", "running", "completed", "failed", "cancelled", "expired"]>;
|
|
4
4
|
export type Status = Schema.Schema.Type<typeof Status>;
|
|
@@ -9,7 +9,6 @@ export interface Snapshot {
|
|
|
9
9
|
/** Normalized 0..1 when the provider reports progress. */
|
|
10
10
|
readonly progress?: number;
|
|
11
11
|
readonly position?: number;
|
|
12
|
-
readonly expiresAt?: number;
|
|
13
12
|
}
|
|
14
13
|
/**
|
|
15
14
|
* Route-owned generation operations for one generation. The media route decodes its serializable token once (from the
|
|
@@ -19,14 +18,10 @@ export interface Route<Response> {
|
|
|
19
18
|
readonly status: Effect.Effect<Snapshot, AIError>;
|
|
20
19
|
readonly result: Effect.Effect<Response, AIError>;
|
|
21
20
|
readonly cancel?: Effect.Effect<void, AIError>;
|
|
22
|
-
/** Provider polling hint (e.g. `openai-poll-after-ms`) that overrides the default interval for the next poll. */
|
|
23
|
-
readonly pollHint?: (snapshot: Snapshot) => Duration.Duration | undefined;
|
|
24
21
|
}
|
|
25
22
|
export interface Poll {
|
|
26
23
|
readonly interval?: Duration.Input;
|
|
27
24
|
readonly timeout?: Duration.Input;
|
|
28
|
-
/** Full override of the polling schedule; `interval` and `pollHint` are ignored when supplied. */
|
|
29
|
-
readonly schedule?: Schedule.Schedule<unknown, Snapshot>;
|
|
30
25
|
}
|
|
31
26
|
export interface AwaitOptions {
|
|
32
27
|
readonly poll?: Poll;
|
|
@@ -49,6 +44,7 @@ export type Event = Observation | {
|
|
|
49
44
|
readonly id: string;
|
|
50
45
|
readonly status: Status;
|
|
51
46
|
};
|
|
47
|
+
export declare const isTerminal: (status: Status) => boolean;
|
|
52
48
|
export declare class Generation<Response> {
|
|
53
49
|
readonly route: Route<Response>;
|
|
54
50
|
/** Route-owned serializable JSON; pass it to the modality's `resume` from another process. */
|
|
@@ -57,7 +53,6 @@ export declare class Generation<Response> {
|
|
|
57
53
|
readonly status: Status;
|
|
58
54
|
readonly progress?: number;
|
|
59
55
|
readonly position?: number;
|
|
60
|
-
readonly expiresAt?: number;
|
|
61
56
|
constructor(route: Route<Response>,
|
|
62
57
|
/** Route-owned serializable JSON; pass it to the modality's `resume` from another process. */
|
|
63
58
|
token: unknown, snapshot: Snapshot);
|
|
@@ -70,9 +65,10 @@ export declare class Generation<Response> {
|
|
|
70
65
|
await(options?: AwaitOptions): Effect.Effect<Response, AIError>;
|
|
71
66
|
cancel(): Effect.Effect<void, AIError>;
|
|
72
67
|
/**
|
|
73
|
-
* Status observations as a stream, ending after the first terminal observation. Each poll
|
|
74
|
-
* remaining until `poll.timeout`, so a hung status request
|
|
75
|
-
*
|
|
68
|
+
* Status observations as a stream, ending after the first terminal observation. Each poll and each sleep between polls
|
|
69
|
+
* is bounded by the time remaining until `poll.timeout`, so a hung status request or a long interval fails the stream at
|
|
70
|
+
* the deadline instead of stalling it. (`Stream.interruptWhen` would express this directly but deadlocks under
|
|
71
|
+
* `TestClock` when the source completes while the timer sleeps.)
|
|
76
72
|
*/
|
|
77
73
|
events(options?: AwaitOptions): Stream.Stream<Event, AIError>;
|
|
78
74
|
private event;
|
package/dist/generation.js
CHANGED
|
@@ -14,6 +14,7 @@ export const ProgressEvent = Schema.Struct({
|
|
|
14
14
|
progress: Schema.optional(Schema.Number),
|
|
15
15
|
}).annotate({ identifier: "Generation.Event.Progress" });
|
|
16
16
|
const TERMINAL = new Set(["completed", "failed", "cancelled", "expired"]);
|
|
17
|
+
export const isTerminal = (status) => TERMINAL.has(status);
|
|
17
18
|
export class Generation {
|
|
18
19
|
route;
|
|
19
20
|
token;
|
|
@@ -21,7 +22,6 @@ export class Generation {
|
|
|
21
22
|
status;
|
|
22
23
|
progress;
|
|
23
24
|
position;
|
|
24
|
-
expiresAt;
|
|
25
25
|
constructor(route,
|
|
26
26
|
/** Route-owned serializable JSON; pass it to the modality's `resume` from another process. */
|
|
27
27
|
token, snapshot) {
|
|
@@ -31,7 +31,6 @@ export class Generation {
|
|
|
31
31
|
this.status = snapshot.status;
|
|
32
32
|
this.progress = snapshot.progress;
|
|
33
33
|
this.position = snapshot.position;
|
|
34
|
-
this.expiresAt = snapshot.expiresAt;
|
|
35
34
|
}
|
|
36
35
|
get snapshot() {
|
|
37
36
|
return {
|
|
@@ -39,11 +38,10 @@ export class Generation {
|
|
|
39
38
|
status: this.status,
|
|
40
39
|
progress: this.progress,
|
|
41
40
|
position: this.position,
|
|
42
|
-
expiresAt: this.expiresAt,
|
|
43
41
|
};
|
|
44
42
|
}
|
|
45
43
|
get terminal() {
|
|
46
|
-
return
|
|
44
|
+
return isTerminal(this.status);
|
|
47
45
|
}
|
|
48
46
|
refresh() {
|
|
49
47
|
return this.route.status.pipe(Effect.map((snapshot) => new Generation(this.route, this.token, snapshot)));
|
|
@@ -64,9 +62,10 @@ export class Generation {
|
|
|
64
62
|
return this.route.cancel ?? Effect.void;
|
|
65
63
|
}
|
|
66
64
|
/**
|
|
67
|
-
* Status observations as a stream, ending after the first terminal observation. Each poll
|
|
68
|
-
* remaining until `poll.timeout`, so a hung status request
|
|
69
|
-
*
|
|
65
|
+
* Status observations as a stream, ending after the first terminal observation. Each poll and each sleep between polls
|
|
66
|
+
* is bounded by the time remaining until `poll.timeout`, so a hung status request or a long interval fails the stream at
|
|
67
|
+
* the deadline instead of stalling it. (`Stream.interruptWhen` would express this directly but deadlocks under
|
|
68
|
+
* `TestClock` when the source completes while the timer sleeps.)
|
|
70
69
|
*/
|
|
71
70
|
events(options) {
|
|
72
71
|
if (this.terminal)
|
|
@@ -74,11 +73,16 @@ export class Generation {
|
|
|
74
73
|
const timeout = Duration.fromInputUnsafe(options?.poll?.timeout ?? DEFAULT_POLL_TIMEOUT);
|
|
75
74
|
return Stream.unwrap(Clock.currentTimeMillis.pipe(Effect.map((start) => {
|
|
76
75
|
const deadline = start + Duration.toMillis(timeout);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
// Fail before polling once the deadline has passed: a fast status request could otherwise win the zero-budget
|
|
77
|
+
// race and schedule another zero-delay poll.
|
|
78
|
+
const refresh = Clock.currentTimeMillis.pipe(Effect.flatMap((now) => now >= deadline
|
|
79
|
+
? this.timeoutError(timeout)
|
|
80
|
+
: this.refresh().pipe(Effect.timeoutOrElse({
|
|
81
|
+
duration: Duration.millis(deadline - now),
|
|
82
|
+
orElse: () => this.timeoutError(timeout),
|
|
83
|
+
}))));
|
|
84
|
+
const schedule = this.schedule(options?.poll).pipe(Schedule.modifyDelay((meta) => Effect.succeed(Duration.min(meta.duration, Duration.millis(Math.max(0, deadline - meta.now))))));
|
|
85
|
+
return Stream.fromEffectSchedule(refresh, schedule).pipe(Stream.takeUntil((generation) => generation.terminal), Stream.map((generation) => generation.event()));
|
|
82
86
|
})));
|
|
83
87
|
}
|
|
84
88
|
event() {
|
|
@@ -100,14 +104,7 @@ export class Generation {
|
|
|
100
104
|
return this.refresh().pipe(Effect.repeat({ schedule: this.schedule(poll), until: (generation) => generation.terminal }));
|
|
101
105
|
}
|
|
102
106
|
schedule(poll) {
|
|
103
|
-
|
|
104
|
-
return poll.schedule.pipe(Schedule.setInputType());
|
|
105
|
-
const interval = poll?.interval ?? DEFAULT_POLL_INTERVAL;
|
|
106
|
-
const pollHint = this.route.pollHint;
|
|
107
|
-
const spaced = Schedule.spaced(interval).pipe(Schedule.setInputType());
|
|
108
|
-
if (!pollHint)
|
|
109
|
-
return spaced;
|
|
110
|
-
return spaced.pipe(Schedule.modifyDelay((metadata) => Effect.succeed(pollHint(metadata.input.snapshot) ?? interval)));
|
|
107
|
+
return Schedule.spaced(poll?.interval ?? DEFAULT_POLL_INTERVAL);
|
|
111
108
|
}
|
|
112
109
|
}
|
|
113
110
|
export const resultEvents = (generation, expand, options) => generation.events(options).pipe(Stream.filter((event) => event.type !== "generation-finished"), Stream.concat(Stream.fromIterableEffect(Effect.map(generation.result(), expand))));
|
package/dist/image-client.d.ts
CHANGED
|
@@ -1,28 +1,63 @@
|
|
|
1
|
-
import { Context
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
readonly generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>, options?: AwaitOptions) => Effect.Effect<ImageResponse, AIError>;
|
|
8
|
-
readonly stream: <Options extends ImageOptions>(request: ImageRequestFor<Options>, options?: AwaitOptions) => Stream.Stream<ImageEvent, AIError>;
|
|
9
|
-
readonly start: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<Generation<ImageResponse>, AIError>;
|
|
10
|
-
readonly resume: <Options extends ImageOptions>(model: ImageModel<Options>, token: unknown) => Effect.Effect<Generation<ImageResponse>, AIError>;
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import { MediaClient } from "./media-client.js";
|
|
3
|
+
import { type ImageEvent, type ImageRequestFor, type ImageResponse } from "./image.js";
|
|
4
|
+
export type Interface = MediaClient.Interface<ImageRequestFor, ImageEvent, ImageResponse>;
|
|
5
|
+
declare const ImageClientService_base: Context.ServiceClass<ImageClientService, "@opencode/ImageClient", Interface>;
|
|
6
|
+
export declare class ImageClientService extends ImageClientService_base {
|
|
11
7
|
}
|
|
12
|
-
declare const
|
|
13
|
-
export
|
|
14
|
-
}
|
|
15
|
-
export declare const generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>, options?: AwaitOptions) => Effect.Effect<ImageResponse, AIError, Service>;
|
|
16
|
-
export declare const stream: <Options extends ImageOptions>(request: ImageRequestFor<Options>, options?: AwaitOptions) => Stream.Stream<ImageEvent, AIError, Service>;
|
|
17
|
-
export declare const start: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<Generation<ImageResponse>, AIError, Service>;
|
|
18
|
-
export declare const resume: <Options extends ImageOptions>(model: ImageModel<Options>, token: unknown) => Effect.Effect<Generation<ImageResponse>, AIError, Service>;
|
|
19
|
-
export declare const layer: Layer.Layer<Service, never, RequestExecutor.Service>;
|
|
8
|
+
export declare const Service: typeof ImageClientService;
|
|
9
|
+
export type Service = ImageClientService;
|
|
20
10
|
export declare const ImageClient: {
|
|
21
|
-
readonly
|
|
22
|
-
readonly
|
|
23
|
-
readonly
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
readonly layer: import("effect/Layer").Layer<ImageClientService, never, import("./route/executor-service.js").RequestExecutorService>;
|
|
12
|
+
readonly generate: (request: ImageRequestFor, options?: import("./generation.js").AwaitOptions) => import("effect/Effect").Effect<ImageResponse, import("./index.js").AIError, ImageClientService>;
|
|
13
|
+
readonly stream: (request: ImageRequestFor, options?: import("./generation.js").AwaitOptions) => import("effect/Stream").Stream<import("./generation.js").Observation | {
|
|
14
|
+
readonly type: "image-partial";
|
|
15
|
+
readonly index: number;
|
|
16
|
+
readonly image: import("./media.js").Asset;
|
|
17
|
+
} | {
|
|
18
|
+
readonly type: "image";
|
|
19
|
+
readonly index: number;
|
|
20
|
+
readonly image: import("./media.js").Asset;
|
|
21
|
+
} | {
|
|
22
|
+
readonly type: "finish";
|
|
23
|
+
readonly providerMetadata?: {
|
|
24
|
+
readonly [x: string]: {
|
|
25
|
+
readonly [x: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
} | undefined;
|
|
28
|
+
readonly usage?: {
|
|
29
|
+
readonly type: "tokens";
|
|
30
|
+
readonly input?: number | undefined;
|
|
31
|
+
readonly output?: number | undefined;
|
|
32
|
+
readonly total?: number | undefined;
|
|
33
|
+
readonly details?: {
|
|
34
|
+
readonly [x: string]: unknown;
|
|
35
|
+
} | undefined;
|
|
36
|
+
} | {
|
|
37
|
+
readonly type: "seconds";
|
|
38
|
+
readonly seconds: number;
|
|
39
|
+
} | {
|
|
40
|
+
readonly type: "characters";
|
|
41
|
+
readonly characters: number;
|
|
42
|
+
} | {
|
|
43
|
+
readonly type: "credits";
|
|
44
|
+
readonly credits: number;
|
|
45
|
+
} | {
|
|
46
|
+
readonly type: "compute";
|
|
47
|
+
readonly seconds: number;
|
|
48
|
+
} | undefined;
|
|
49
|
+
readonly notices?: readonly {
|
|
50
|
+
readonly type: "other" | "moderated" | "filtered";
|
|
51
|
+
readonly message: string;
|
|
52
|
+
readonly providerMetadata?: {
|
|
53
|
+
readonly [x: string]: {
|
|
54
|
+
readonly [x: string]: unknown;
|
|
55
|
+
};
|
|
56
|
+
} | undefined;
|
|
57
|
+
}[] | undefined;
|
|
58
|
+
}, import("./index.js").AIError, ImageClientService>;
|
|
59
|
+
readonly start: (request: ImageRequestFor) => import("effect/Effect").Effect<import("./generation.js").Generation<ImageResponse>, import("./index.js").AIError, ImageClientService>;
|
|
60
|
+
readonly resume: (model: import("./image.js").ImageModel<import("./media-model.js").MediaModel.Options>, token: unknown) => import("effect/Effect").Effect<import("./generation.js").Generation<ImageResponse>, import("./index.js").AIError, ImageClientService>;
|
|
61
|
+
readonly Service: typeof ImageClientService;
|
|
27
62
|
};
|
|
28
63
|
export {};
|
package/dist/image-client.js
CHANGED
|
@@ -1,44 +1,20 @@
|
|
|
1
|
-
import { Context
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export class Service extends Context.Service()("@opencode/ImageClient") {
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import { MediaClient } from "./media-client.js";
|
|
3
|
+
import { ImageOutputEvent, ImageFinishEvent, } from "./image.js";
|
|
4
|
+
export class ImageClientService extends Context.Service()("@opencode/ImageClient") {
|
|
6
5
|
}
|
|
7
|
-
export const
|
|
8
|
-
const client = yield* Service;
|
|
9
|
-
return yield* client.generate(request, options);
|
|
10
|
-
});
|
|
11
|
-
export const stream = (request, options) => Stream.unwrap(Effect.gen(function* () {
|
|
12
|
-
const client = yield* Service;
|
|
13
|
-
return client.stream(request, options);
|
|
14
|
-
}));
|
|
15
|
-
export const start = (request) => Effect.gen(function* () {
|
|
16
|
-
const client = yield* Service;
|
|
17
|
-
return yield* client.start(request);
|
|
18
|
-
});
|
|
19
|
-
export const resume = (model, token) => Effect.gen(function* () {
|
|
20
|
-
const client = yield* Service;
|
|
21
|
-
return yield* client.resume(model, token);
|
|
22
|
-
});
|
|
23
|
-
export const layer = Layer.effect(Service, Effect.gen(function* () {
|
|
24
|
-
const executor = yield* RequestExecutor.Service;
|
|
25
|
-
const dispatch = MediaRoute.dispatch({
|
|
26
|
-
modality: "image",
|
|
27
|
-
execute: executor.execute,
|
|
28
|
-
responseEvents,
|
|
29
|
-
});
|
|
30
|
-
return Service.of({
|
|
31
|
-
start: (request) => dispatch.start(request.model.route, request),
|
|
32
|
-
resume: (model, token) => dispatch.resume(model.route, model, token),
|
|
33
|
-
generate: (request, options) => dispatch.generate(request.model.route, request, options),
|
|
34
|
-
stream: (request, options) => dispatch.stream(request.model.route, request, options),
|
|
35
|
-
});
|
|
36
|
-
}));
|
|
6
|
+
export const Service = ImageClientService;
|
|
37
7
|
export const ImageClient = {
|
|
38
8
|
Service,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
9
|
+
...MediaClient.make(Service, {
|
|
10
|
+
modality: "image",
|
|
11
|
+
responseEvents: (response) => [
|
|
12
|
+
...response.images.map((image, index) => ImageOutputEvent.make({ index, image })),
|
|
13
|
+
ImageFinishEvent.make({
|
|
14
|
+
usage: response.usage,
|
|
15
|
+
notices: response.notices,
|
|
16
|
+
providerMetadata: response.providerMetadata,
|
|
17
|
+
}),
|
|
18
|
+
],
|
|
19
|
+
}),
|
|
44
20
|
};
|
package/dist/image.d.ts
CHANGED
|
@@ -3,33 +3,25 @@ import { Generation, type AwaitOptions } from "./generation.js";
|
|
|
3
3
|
import { Media } from "./media.js";
|
|
4
4
|
import { MediaModel } from "./media-model.js";
|
|
5
5
|
import { MediaRoute } from "./route/media.js";
|
|
6
|
-
import type
|
|
7
|
-
import { AIError, HttpOptions } from "./schema/index.js";
|
|
6
|
+
import { AIError, HttpOptions, type OpenString } from "./schema/index.js";
|
|
8
7
|
import { Service } from "./image-client.js";
|
|
9
|
-
export type ImageOptions =
|
|
10
|
-
export type ImageRoute
|
|
11
|
-
export declare class ImageModel<Options extends ImageOptions = ImageOptions> extends MediaModel<ImageRoute
|
|
8
|
+
export type ImageOptions = MediaModel.Options;
|
|
9
|
+
export type ImageRoute = MediaRoute.AnyRoute<ImageRequestFor, ImageEvent, ImageResponse>;
|
|
10
|
+
export declare class ImageModel<Options extends ImageOptions = ImageOptions> extends MediaModel<ImageRoute, Options> {
|
|
12
11
|
protected readonly _ImageModel: void;
|
|
13
|
-
static make<Options extends ImageOptions = ImageOptions>(input: MediaModel.Input<ImageRoute<Options>>): ImageModel<Options>;
|
|
14
12
|
/** The number of type arguments selects the kind: `<Options>`, `<Options, Frame, State>`, or `<Options, Token>`. */
|
|
15
|
-
static fromRoute<Options extends ImageOptions>(route:
|
|
16
|
-
static fromRoute<Options extends ImageOptions, Frame, State>(route:
|
|
17
|
-
static fromRoute<Options extends ImageOptions, Token>(route:
|
|
13
|
+
static fromRoute<Options extends ImageOptions>(route: MediaModel.InlineRouteInput<ImageRequestFor<Options>, ImageResponse>, input: MediaRoute.ModelInput): ImageModel<Options>;
|
|
14
|
+
static fromRoute<Options extends ImageOptions, Frame, State>(route: MediaModel.StreamRouteInput<ImageRequestFor<Options>, ImageEvent, Frame, State>, input: MediaRoute.ModelInput): ImageModel<Options>;
|
|
15
|
+
static fromRoute<Options extends ImageOptions, Token>(route: MediaModel.QueuedRouteInput<ImageRequestFor<Options>, ImageResponse, Token>, input: MediaRoute.ModelInput): ImageModel<Options>;
|
|
18
16
|
}
|
|
19
|
-
export declare
|
|
20
|
-
type InlineRouteInput<Options extends ImageOptions = ImageOptions> = MediaModel.RouteInput<ImageRequestFor<Options>, MediaProtocol.Inline<ImageRequestFor<Options>, ImageResponse>>;
|
|
21
|
-
type StreamRouteInput<Options extends ImageOptions = ImageOptions, Frame = unknown, State = unknown> = MediaModel.RouteInput<MediaProtocol.Addressed<ImageRequestFor<Options>>, MediaProtocol.Streamed<ImageRequestFor<Options>, ImageEvent, Frame, State>>;
|
|
22
|
-
type QueuedRouteInput<Options extends ImageOptions = ImageOptions, Token = unknown> = MediaModel.RouteInput<ImageRequestFor<Options>, MediaProtocol.Queued<ImageRequestFor<Options>, ImageResponse, Token>>;
|
|
23
|
-
type RouteInput<Options extends ImageOptions = ImageOptions, Frame = unknown, State = unknown, Token = unknown> = MediaModel.AnyRouteInput<ImageRequestFor<Options>, ImageEvent, ImageResponse, Frame, State, Token>;
|
|
24
|
-
}
|
|
25
|
-
export declare const ImageModelSchema: Schema.declare<ImageModel<ImageOptions>, ImageModel<ImageOptions>>;
|
|
17
|
+
export declare const ImageModelSchema: Schema.declare<ImageModel<MediaModel.Options>, ImageModel<MediaModel.Options>>;
|
|
26
18
|
export type ImageSize = `${number}x${number}`;
|
|
27
19
|
export declare const ImageSize: Schema.declare<`${number}x${number}`, `${number}x${number}`>;
|
|
28
20
|
export type ImageAspectRatio = Media.AspectRatio;
|
|
29
21
|
export declare const ImageAspectRatio: Schema.declare<`${number}:${number}`, `${number}:${number}`>;
|
|
30
|
-
export type ImageFormat = "png" | "jpeg" | "webp"
|
|
22
|
+
export type ImageFormat = OpenString<"png" | "jpeg" | "webp">;
|
|
31
23
|
declare const ImageRequest_base: Schema.Class<ImageRequest, Schema.Struct<{
|
|
32
|
-
readonly model: Schema.declare<ImageModel<
|
|
24
|
+
readonly model: Schema.declare<ImageModel<MediaModel.Options>, ImageModel<MediaModel.Options>>;
|
|
33
25
|
readonly prompt: Schema.String;
|
|
34
26
|
/** Edit sources or style/subject references, in order. */
|
|
35
27
|
readonly images: Schema.optional<Schema.$Array<Schema.decodeTo<Schema.declare<Media.Asset, Media.Asset>, Schema.Struct<{
|
|
@@ -1418,22 +1410,18 @@ export declare const ImageEvent: Schema.Union<readonly [Schema.Struct<{
|
|
|
1418
1410
|
};
|
|
1419
1411
|
};
|
|
1420
1412
|
export type ImageEvent = Schema.Schema.Type<typeof imageEventTagged>;
|
|
1421
|
-
export declare const responseEvents: (response: ImageResponse) => ReadonlyArray<ImageEvent>;
|
|
1422
1413
|
export declare function request<const Model extends ImageModel>(input: ImageRequestInput<Model>): ImageRequestFor<ImageModelOptions<Model>>;
|
|
1423
1414
|
export declare function request(input: ImageRequest): ImageRequest;
|
|
1424
|
-
export declare function generate<const Model extends ImageModel>(input: ImageRequestInput<Model>, options?: AwaitOptions): Effect.Effect<ImageResponse, AIError, Service>;
|
|
1425
|
-
export declare function
|
|
1426
|
-
export declare function stream<const Model extends ImageModel>(input: ImageRequestInput<Model>, options?: AwaitOptions): Stream.Stream<ImageEvent, AIError, Service>;
|
|
1427
|
-
export declare function stream(input: ImageRequest, options?: AwaitOptions): Stream.Stream<ImageEvent, AIError, Service>;
|
|
1415
|
+
export declare function generate<const Model extends ImageModel>(input: ImageRequest | ImageRequestInput<Model>, options?: AwaitOptions): Effect.Effect<ImageResponse, AIError, Service>;
|
|
1416
|
+
export declare function stream<const Model extends ImageModel>(input: ImageRequest | ImageRequestInput<Model>, options?: AwaitOptions): Stream.Stream<ImageEvent, AIError, Service>;
|
|
1428
1417
|
/** Inline and streaming routes fail with `UnsupportedOperation`. */
|
|
1429
|
-
export declare function start<const Model extends ImageModel>(input: ImageRequestInput<Model>): Effect.Effect<Generation<ImageResponse>, AIError, Service>;
|
|
1430
|
-
export declare
|
|
1431
|
-
export declare const resume: <Options extends ImageOptions>(model: ImageModel<Options>, token: unknown) => Effect.Effect<Generation<ImageResponse>, AIError, Service>;
|
|
1418
|
+
export declare function start<const Model extends ImageModel>(input: ImageRequest | ImageRequestInput<Model>): Effect.Effect<Generation<ImageResponse>, AIError, Service>;
|
|
1419
|
+
export declare const resume: (model: ImageModel, token: unknown) => Effect.Effect<Generation<ImageResponse>, AIError, Service>;
|
|
1432
1420
|
export declare const Image: {
|
|
1433
1421
|
readonly request: typeof request;
|
|
1434
1422
|
readonly generate: typeof generate;
|
|
1435
1423
|
readonly stream: typeof stream;
|
|
1436
1424
|
readonly start: typeof start;
|
|
1437
|
-
readonly resume:
|
|
1425
|
+
readonly resume: (model: ImageModel, token: unknown) => Effect.Effect<Generation<ImageResponse>, AIError, Service>;
|
|
1438
1426
|
};
|
|
1439
1427
|
export {};
|
package/dist/image.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { Effect, Schema, Stream } from "effect";
|
|
2
2
|
import { Generation, ProgressEvent, QueuedEvent } from "./generation.js";
|
|
3
3
|
import { Media } from "./media.js";
|
|
4
|
-
import { MediaModel,
|
|
4
|
+
import { MediaModel, composeRoute, tryRequest } from "./media-model.js";
|
|
5
5
|
import { MediaRoute } from "./route/media.js";
|
|
6
6
|
import { AIError, HttpOptions, MediaUsage, ProviderMetadata } from "./schema/index.js";
|
|
7
7
|
import { ImageClient, Service } from "./image-client.js";
|
|
8
8
|
export class ImageModel extends MediaModel {
|
|
9
|
-
static make(input) {
|
|
10
|
-
return new ImageModel(input);
|
|
11
|
-
}
|
|
12
9
|
static fromRoute(route, input) {
|
|
13
10
|
return new ImageModel({
|
|
14
11
|
id: input.id,
|
|
15
|
-
provider: route.provider,
|
|
12
|
+
provider: route.protocol.provider,
|
|
16
13
|
http: input.http,
|
|
17
|
-
route:
|
|
14
|
+
route: composeRoute(route, input, collectResponse),
|
|
18
15
|
});
|
|
19
16
|
}
|
|
20
17
|
}
|
|
@@ -85,14 +82,6 @@ export const ImageEvent = Object.assign(imageEventTagged, {
|
|
|
85
82
|
finish: imageEventTagged.guards.finish,
|
|
86
83
|
},
|
|
87
84
|
});
|
|
88
|
-
export const responseEvents = (response) => [
|
|
89
|
-
...response.images.map((image, index) => ImageOutputEvent.make({ index, image })),
|
|
90
|
-
ImageFinishEvent.make({
|
|
91
|
-
usage: response.usage,
|
|
92
|
-
notices: response.notices,
|
|
93
|
-
providerMetadata: response.providerMetadata,
|
|
94
|
-
}),
|
|
95
|
-
];
|
|
96
85
|
const collectResponse = (events) => {
|
|
97
86
|
const finish = events.find(ImageEvent.is.finish);
|
|
98
87
|
// Every image protocol's `finish` emits the terminal event or fails, so a completed stream always has one.
|
|
@@ -110,7 +99,7 @@ export function request(input) {
|
|
|
110
99
|
return input;
|
|
111
100
|
return new ImageRequest({
|
|
112
101
|
...input,
|
|
113
|
-
http:
|
|
102
|
+
http: HttpOptions.make(input.http),
|
|
114
103
|
});
|
|
115
104
|
}
|
|
116
105
|
const requestEffect = (input) => tryRequest(() => request(input));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
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";
|
package/dist/index.js
CHANGED
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";
|