@opencode/ai 0.0.0-dev-20115 → 0.0.0-dev-20117
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 +170 -113
- 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/image-client.d.ts +6 -4
- package/dist/image-client.js +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/media.js +2 -2
- package/dist/promise.d.ts +42 -20
- package/dist/promise.js +37 -11
- package/dist/protocols/openai-speech.d.ts +5 -1
- package/dist/protocols/shared.js +2 -1
- package/dist/route/auth.d.ts +1 -1
- package/dist/route/auth.js +14 -13
- package/dist/route/client.d.ts +7 -5
- package/dist/route/client.js +2 -1
- 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/index.d.ts +1 -1
- package/dist/speech-client.d.ts +6 -4
- package/dist/speech-client.js +2 -1
- package/dist/testing.d.ts +2 -2
- package/dist/transcription-client.d.ts +6 -4
- package/dist/transcription-client.js +2 -1
- package/dist/transcription.d.ts +2 -2
- package/dist/utils/media-type.d.ts +2 -1
- package/dist/utils/media-type.js +3 -1
- package/dist/video-client.d.ts +6 -4
- package/dist/video-client.js +2 -1
- package/dist/video.d.ts +2 -2
- package/package.json +3 -3
package/dist/image-client.js
CHANGED
|
@@ -2,8 +2,9 @@ import { Context, Effect, Layer, Stream } from "effect";
|
|
|
2
2
|
import { RequestExecutor } from "./route/executor.js";
|
|
3
3
|
import { MediaRoute } from "./route/media.js";
|
|
4
4
|
import { responseEvents, } from "./image.js";
|
|
5
|
-
export class
|
|
5
|
+
export class ImageClientService extends Context.Service()("@opencode/ImageClient") {
|
|
6
6
|
}
|
|
7
|
+
export const Service = ImageClientService;
|
|
7
8
|
export const generate = (request, options) => Effect.gen(function* () {
|
|
8
9
|
const client = yield* Service;
|
|
9
10
|
return yield* client.generate(request, options);
|
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/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
|
// ---------------------------------------------------------------------------
|
|
@@ -215,7 +215,7 @@ export const file = (path, options) => Effect.gen(function* () {
|
|
|
215
215
|
const data = yield* fs
|
|
216
216
|
.readFile(path)
|
|
217
217
|
.pipe(Effect.mapError((cause) => invalid(`Failed to read media file ${path}`, cause)));
|
|
218
|
-
return bytes(data,
|
|
218
|
+
return bytes(data, fileMediaType(data, path), options);
|
|
219
219
|
});
|
|
220
220
|
/** Materialize an asset and write its bytes through `FileSystem`. */
|
|
221
221
|
export const write = (asset, path) => Effect.gen(function* () {
|
package/dist/promise.d.ts
CHANGED
|
@@ -1,40 +1,53 @@
|
|
|
1
1
|
import { Effect, Layer } from "effect";
|
|
2
|
-
import
|
|
2
|
+
import { AIClient } from "./ai-client.js";
|
|
3
|
+
import type { AwaitOptions, Event, Snapshot } from "./generation.js";
|
|
3
4
|
import { ImageModel, ImageRequest, type ImageOptions, type ImageRequestInput } from "./image.js";
|
|
4
|
-
import {
|
|
5
|
-
import { LLMClient } from "./route/client.js";
|
|
5
|
+
import { Media } from "./media.js";
|
|
6
6
|
import { RequestExecutor } from "./route/executor.js";
|
|
7
7
|
import { LanguageModel, LLMRequest } from "./schema/index.js";
|
|
8
8
|
import type { RequestInput } from "./llm.js";
|
|
9
9
|
import { SpeechModel, SpeechRequest, type SpeechRequestInput } from "./speech.js";
|
|
10
|
-
import { SpeechClient } from "./speech-client.js";
|
|
11
10
|
import { TranscriptionModel, TranscriptionRequest, type TranscriptionOptions, type TranscriptionRequestInput } from "./transcription.js";
|
|
12
|
-
import { TranscriptionClient } from "./transcription-client.js";
|
|
13
11
|
import { VideoModel, VideoRequest, type VideoOptions, type VideoRequestInput } from "./video.js";
|
|
14
|
-
import { VideoClient } from "./video-client.js";
|
|
15
12
|
/**
|
|
16
13
|
* Promise-first entrypoint for scripts and non-Effect callers. One `ManagedRuntime` hosts the LLM, image, video, speech,
|
|
17
14
|
* and transcription clients over a request executor; every method runs the corresponding Effect API and rethrows
|
|
18
|
-
* `AIError` unchanged.
|
|
15
|
+
* `AIError` unchanged. `file` and `write` load `node:fs/promises` on first use, so importing this module does not.
|
|
19
16
|
*/
|
|
20
17
|
export interface Options {
|
|
21
|
-
/** Executor layer; defaults to `RequestExecutor.fetchLayer`. Inject a recorder or middleware here. */
|
|
18
|
+
/** Executor layer; defaults to `RequestExecutor.fetchLayer`. Inject a recorder or `RequestExecutor.middleware(fn)` here. */
|
|
22
19
|
readonly layer?: Layer.Layer<RequestExecutor.Service>;
|
|
23
20
|
}
|
|
24
21
|
export interface RunOptions {
|
|
25
22
|
readonly signal?: AbortSignal;
|
|
26
23
|
}
|
|
27
|
-
export type Services =
|
|
28
|
-
/**
|
|
24
|
+
export type Services = AIClient.Services;
|
|
25
|
+
/**
|
|
26
|
+
* Promise view of a `Generation`. Its fields are a snapshot taken when the handle was created; `refresh()` resolves to a
|
|
27
|
+
* new handle rather than updating this one.
|
|
28
|
+
*/
|
|
29
29
|
export type GenerationHandle<Response> = Snapshot & {
|
|
30
30
|
/** Serializable JSON; pass it back to `resume` from another process. */
|
|
31
31
|
readonly token: unknown;
|
|
32
32
|
readonly await: (options?: AwaitOptions & RunOptions) => Promise<Response>;
|
|
33
|
+
/** Status observations until the first terminal one, polling like `await`; abort ends iteration without throwing. */
|
|
34
|
+
readonly events: (options?: AwaitOptions & RunOptions) => AsyncIterable<Event>;
|
|
35
|
+
/** The result without polling; fails when the generation has not completed. */
|
|
36
|
+
readonly result: (options?: RunOptions) => Promise<Response>;
|
|
33
37
|
readonly refresh: (options?: RunOptions) => Promise<GenerationHandle<Response>>;
|
|
34
38
|
readonly cancel: (options?: RunOptions) => Promise<void>;
|
|
35
39
|
};
|
|
36
40
|
export declare const make: (options?: Options) => {
|
|
37
41
|
run: <A, E>(effect: Effect.Effect<A, E, Services>, options?: RunOptions) => Promise<A>;
|
|
42
|
+
/** Decoded asset bytes, downloading `url` sources through the executor. */
|
|
43
|
+
bytes: (asset: Media.Asset, options?: RunOptions) => Promise<Uint8Array<ArrayBufferLike>>;
|
|
44
|
+
base64: (asset: Media.Asset, options?: RunOptions) => Promise<string>;
|
|
45
|
+
/** Pull a `url` asset into owned bytes before the provider URL expires. */
|
|
46
|
+
materialize: (asset: Media.Asset, options?: RunOptions) => Promise<Media.Asset>;
|
|
47
|
+
/** Read a file into an asset like `Media.file`: sniffed media type, then the extension's. */
|
|
48
|
+
file: (path: string, options?: Media.AssetOptions & RunOptions) => Promise<Media.Asset>;
|
|
49
|
+
/** Write an asset's bytes like `Media.write`, downloading `url` sources through the executor. */
|
|
50
|
+
write: (asset: Media.Asset, path: string, options?: RunOptions) => Promise<void>;
|
|
38
51
|
llm: {
|
|
39
52
|
request: <const SelectedLanguageModel extends LanguageModel>(input: RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
|
|
40
53
|
generate: <const Model extends LanguageModel>(input: RequestInput<Model> | LLMRequest, options?: RunOptions) => Promise<import("./index.js").LLMResponse>;
|
|
@@ -209,7 +222,7 @@ export declare const make: (options?: Options) => {
|
|
|
209
222
|
readonly namespace?: string | undefined;
|
|
210
223
|
} | {
|
|
211
224
|
readonly type: "media";
|
|
212
|
-
readonly media:
|
|
225
|
+
readonly media: Media.Asset;
|
|
213
226
|
readonly providerMetadata?: {
|
|
214
227
|
readonly [x: string]: {
|
|
215
228
|
readonly [x: string]: unknown;
|
|
@@ -265,11 +278,11 @@ export declare const make: (options?: Options) => {
|
|
|
265
278
|
} | {
|
|
266
279
|
readonly type: "image-partial";
|
|
267
280
|
readonly index: number;
|
|
268
|
-
readonly image:
|
|
281
|
+
readonly image: Media.Asset;
|
|
269
282
|
} | {
|
|
270
283
|
readonly type: "image";
|
|
271
284
|
readonly index: number;
|
|
272
|
-
readonly image:
|
|
285
|
+
readonly image: Media.Asset;
|
|
273
286
|
} | {
|
|
274
287
|
readonly type: "finish";
|
|
275
288
|
readonly providerMetadata?: {
|
|
@@ -327,7 +340,7 @@ export declare const make: (options?: Options) => {
|
|
|
327
340
|
} | {
|
|
328
341
|
readonly type: "video";
|
|
329
342
|
readonly index: number;
|
|
330
|
-
readonly video:
|
|
343
|
+
readonly video: Media.Asset;
|
|
331
344
|
} | {
|
|
332
345
|
readonly type: "finish";
|
|
333
346
|
readonly providerMetadata?: {
|
|
@@ -382,7 +395,7 @@ export declare const make: (options?: Options) => {
|
|
|
382
395
|
}[];
|
|
383
396
|
} | {
|
|
384
397
|
readonly type: "finish";
|
|
385
|
-
readonly audio:
|
|
398
|
+
readonly audio: Media.Asset;
|
|
386
399
|
readonly providerMetadata?: {
|
|
387
400
|
readonly [x: string]: {
|
|
388
401
|
readonly [x: string]: unknown;
|
|
@@ -505,6 +518,15 @@ export type Client = ReturnType<typeof make>;
|
|
|
505
518
|
/** Default client over `RequestExecutor.fetchLayer` for scripts; the runtime builds its layer on first use. */
|
|
506
519
|
export declare const ai: {
|
|
507
520
|
run: <A, E>(effect: Effect.Effect<A, E, Services>, options?: RunOptions) => Promise<A>;
|
|
521
|
+
/** Decoded asset bytes, downloading `url` sources through the executor. */
|
|
522
|
+
bytes: (asset: Media.Asset, options?: RunOptions) => Promise<Uint8Array<ArrayBufferLike>>;
|
|
523
|
+
base64: (asset: Media.Asset, options?: RunOptions) => Promise<string>;
|
|
524
|
+
/** Pull a `url` asset into owned bytes before the provider URL expires. */
|
|
525
|
+
materialize: (asset: Media.Asset, options?: RunOptions) => Promise<Media.Asset>;
|
|
526
|
+
/** Read a file into an asset like `Media.file`: sniffed media type, then the extension's. */
|
|
527
|
+
file: (path: string, options?: Media.AssetOptions & RunOptions) => Promise<Media.Asset>;
|
|
528
|
+
/** Write an asset's bytes like `Media.write`, downloading `url` sources through the executor. */
|
|
529
|
+
write: (asset: Media.Asset, path: string, options?: RunOptions) => Promise<void>;
|
|
508
530
|
llm: {
|
|
509
531
|
request: <const SelectedLanguageModel extends LanguageModel>(input: RequestInput<SelectedLanguageModel>) => LLMRequest<SelectedLanguageModel>;
|
|
510
532
|
generate: <const Model extends LanguageModel>(input: RequestInput<Model> | LLMRequest, options?: RunOptions) => Promise<import("./index.js").LLMResponse>;
|
|
@@ -679,7 +701,7 @@ export declare const ai: {
|
|
|
679
701
|
readonly namespace?: string | undefined;
|
|
680
702
|
} | {
|
|
681
703
|
readonly type: "media";
|
|
682
|
-
readonly media:
|
|
704
|
+
readonly media: Media.Asset;
|
|
683
705
|
readonly providerMetadata?: {
|
|
684
706
|
readonly [x: string]: {
|
|
685
707
|
readonly [x: string]: unknown;
|
|
@@ -735,11 +757,11 @@ export declare const ai: {
|
|
|
735
757
|
} | {
|
|
736
758
|
readonly type: "image-partial";
|
|
737
759
|
readonly index: number;
|
|
738
|
-
readonly image:
|
|
760
|
+
readonly image: Media.Asset;
|
|
739
761
|
} | {
|
|
740
762
|
readonly type: "image";
|
|
741
763
|
readonly index: number;
|
|
742
|
-
readonly image:
|
|
764
|
+
readonly image: Media.Asset;
|
|
743
765
|
} | {
|
|
744
766
|
readonly type: "finish";
|
|
745
767
|
readonly providerMetadata?: {
|
|
@@ -797,7 +819,7 @@ export declare const ai: {
|
|
|
797
819
|
} | {
|
|
798
820
|
readonly type: "video";
|
|
799
821
|
readonly index: number;
|
|
800
|
-
readonly video:
|
|
822
|
+
readonly video: Media.Asset;
|
|
801
823
|
} | {
|
|
802
824
|
readonly type: "finish";
|
|
803
825
|
readonly providerMetadata?: {
|
|
@@ -852,7 +874,7 @@ export declare const ai: {
|
|
|
852
874
|
}[];
|
|
853
875
|
} | {
|
|
854
876
|
readonly type: "finish";
|
|
855
|
-
readonly audio:
|
|
877
|
+
readonly audio: Media.Asset;
|
|
856
878
|
readonly providerMetadata?: {
|
|
857
879
|
readonly [x: string]: {
|
|
858
880
|
readonly [x: string]: unknown;
|
package/dist/promise.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { Effect, Layer, ManagedRuntime, Stream } from "effect";
|
|
2
|
+
import { AIClient } from "./ai-client.js";
|
|
2
3
|
import { Image, ImageModel, ImageRequest } from "./image.js";
|
|
3
|
-
import { ImageClient } from "./image-client.js";
|
|
4
4
|
import { LLM } from "./index.js";
|
|
5
|
-
import {
|
|
5
|
+
import { Media } from "./media.js";
|
|
6
|
+
import { tryRequest } from "./media-model.js";
|
|
6
7
|
import { RequestExecutor } from "./route/executor.js";
|
|
7
|
-
import { LanguageModel, LLMRequest } from "./schema/index.js";
|
|
8
|
+
import { AIError, InvalidRequestError, LanguageModel, LLMRequest } from "./schema/index.js";
|
|
8
9
|
import { Speech, SpeechModel, SpeechRequest } from "./speech.js";
|
|
9
|
-
import { SpeechClient } from "./speech-client.js";
|
|
10
10
|
import { Transcription, TranscriptionModel, TranscriptionRequest, } from "./transcription.js";
|
|
11
|
-
import {
|
|
11
|
+
import { fileMediaType } from "./utils/media-type.js";
|
|
12
12
|
import { Video, VideoModel, VideoRequest } from "./video.js";
|
|
13
|
-
import { VideoClient } from "./video-client.js";
|
|
14
13
|
const abortEffect = (signal) => signal === undefined
|
|
15
14
|
? Effect.never
|
|
16
15
|
: Effect.callback((resume) => {
|
|
@@ -23,29 +22,55 @@ const abortEffect = (signal) => signal === undefined
|
|
|
23
22
|
return Effect.sync(() => signal.removeEventListener("abort", onAbort));
|
|
24
23
|
});
|
|
25
24
|
export const make = (options = {}) => {
|
|
26
|
-
const runtime = ManagedRuntime.make(
|
|
27
|
-
/** Run any package Effect (for example `
|
|
25
|
+
const runtime = ManagedRuntime.make(AIClient.layerWith(options.layer ?? RequestExecutor.fetchLayer));
|
|
26
|
+
/** Run any package Effect (for example `LLMClient.compact(...)`) inside this runtime. */
|
|
28
27
|
const run = (effect, options) => runtime.runPromise(effect, { signal: options?.signal });
|
|
29
28
|
const iterate = (stream, options) => Stream.toAsyncIterable(Stream.unwrap(runtime.contextEffect.pipe(Effect.map((context) => stream.pipe(Stream.interruptWhen(abortEffect(options?.signal)), Stream.provideContext(context))))));
|
|
30
29
|
const handle = (generation) => ({
|
|
31
30
|
...generation.snapshot,
|
|
32
31
|
token: generation.token,
|
|
33
32
|
await: (options) => run(generation.await({ poll: options?.poll }), options),
|
|
33
|
+
events: (options) => iterate(generation.events({ poll: options?.poll }), options),
|
|
34
|
+
result: (options) => run(generation.result(), options),
|
|
34
35
|
refresh: (options) => run(generation.refresh(), options).then(handle),
|
|
35
36
|
cancel: (options) => run(generation.cancel(), options),
|
|
36
37
|
});
|
|
37
38
|
// The typed `generate`/`stream` overloads take a concrete input or a request, not the union; normalize once here.
|
|
38
|
-
const llmRequest = (input) =>
|
|
39
|
+
const llmRequest = (input) => input instanceof LLMRequest ? Effect.succeed(input) : tryRequest(() => LLM.request(input));
|
|
39
40
|
const imageRequest = (input) => input instanceof ImageRequest ? input : Image.request(input);
|
|
40
41
|
const videoRequest = (input) => input instanceof VideoRequest ? input : Video.request(input);
|
|
41
42
|
const speechRequest = (input) => input instanceof SpeechRequest ? input : Speech.request(input);
|
|
42
43
|
const transcriptionRequest = (input) => input instanceof TranscriptionRequest ? input : Transcription.request(input);
|
|
43
44
|
return {
|
|
44
45
|
run,
|
|
46
|
+
/** Decoded asset bytes, downloading `url` sources through the executor. */
|
|
47
|
+
bytes: (asset, options) => run(asset.bytes(), options),
|
|
48
|
+
base64: (asset, options) => run(asset.base64(), options),
|
|
49
|
+
/** Pull a `url` asset into owned bytes before the provider URL expires. */
|
|
50
|
+
materialize: (asset, options) => run(asset.materialize(), options),
|
|
51
|
+
/** Read a file into an asset like `Media.file`: sniffed media type, then the extension's. */
|
|
52
|
+
file: async (path, options) => {
|
|
53
|
+
const { readFile } = await import("node:fs/promises");
|
|
54
|
+
return run(Effect.tryPromise({
|
|
55
|
+
try: (signal) => readFile(path, { signal }),
|
|
56
|
+
catch: (cause) => fileError(`Failed to read media file ${path}`, cause),
|
|
57
|
+
}).pipe(Effect.map((buffer) => {
|
|
58
|
+
const data = new Uint8Array(buffer);
|
|
59
|
+
return Media.bytes(data, fileMediaType(data, path), options);
|
|
60
|
+
})), options);
|
|
61
|
+
},
|
|
62
|
+
/** Write an asset's bytes like `Media.write`, downloading `url` sources through the executor. */
|
|
63
|
+
write: async (asset, path, options) => {
|
|
64
|
+
const { writeFile } = await import("node:fs/promises");
|
|
65
|
+
return run(asset.bytes().pipe(Effect.flatMap((data) => Effect.tryPromise({
|
|
66
|
+
try: (signal) => writeFile(path, data, { signal }),
|
|
67
|
+
catch: (cause) => fileError(`Failed to write media file ${path}`, cause),
|
|
68
|
+
}))), options);
|
|
69
|
+
},
|
|
45
70
|
llm: {
|
|
46
71
|
request: LLM.request,
|
|
47
|
-
generate: (input, options) => run(
|
|
48
|
-
stream: (input, options) => iterate(
|
|
72
|
+
generate: (input, options) => run(Effect.flatMap(llmRequest(input), LLM.generate), options),
|
|
73
|
+
stream: (input, options) => iterate(Stream.unwrap(Effect.map(llmRequest(input), LLM.stream)), options),
|
|
49
74
|
},
|
|
50
75
|
image: {
|
|
51
76
|
request: Image.request,
|
|
@@ -76,6 +101,7 @@ export const make = (options = {}) => {
|
|
|
76
101
|
dispose: () => runtime.dispose(),
|
|
77
102
|
};
|
|
78
103
|
};
|
|
104
|
+
const fileError = (message, cause) => new AIError({ reason: new InvalidRequestError({ message, cause }) });
|
|
79
105
|
/** Default client over `RequestExecutor.fetchLayer` for scripts; the runtime builds its layer on first use. */
|
|
80
106
|
export const ai = make();
|
|
81
107
|
export * as AI from "./promise.js";
|
|
@@ -5,7 +5,11 @@ import { SpeechModel, type SpeechRequestFor } from "../speech.js";
|
|
|
5
5
|
import { SpeechStream } from "./utils/speech-stream.js";
|
|
6
6
|
export declare const DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
7
7
|
export declare const PATH = "/audio/speech";
|
|
8
|
-
|
|
8
|
+
/** `voice`, `instructions`, `speed`, and `format` are common request fields; other native body fields pass through. */
|
|
9
|
+
export type OpenAISpeechOptions = {
|
|
10
|
+
/** Defaults to `"sse"` in `stream` mode on models that support it; the merged value selects the response framing. */
|
|
11
|
+
readonly stream_format?: "sse" | "audio";
|
|
12
|
+
} & Record<string, unknown>;
|
|
9
13
|
export type Request = SpeechRequestFor<OpenAISpeechOptions>;
|
|
10
14
|
interface State extends SpeechStream.Audio {
|
|
11
15
|
readonly done: boolean;
|
package/dist/protocols/shared.js
CHANGED
|
@@ -149,7 +149,8 @@ export const mediaReference = (asset, provider, label) => {
|
|
|
149
149
|
if (provider !== undefined && asset.source.type === "ref" && asset.source.provider === provider)
|
|
150
150
|
return Effect.succeed({ type: "ref", value: asset.source.id });
|
|
151
151
|
const accepted = provider === undefined ? "" : `, and ${provider} references`;
|
|
152
|
-
|
|
152
|
+
const got = asset.source.type === "ref" ? `; got ${asset.source.provider}:${asset.source.id}` : "";
|
|
153
|
+
return Effect.fail(invalidRequest(`${label} accepts inline bytes, data URLs, http(s) URLs${accepted}${got}`));
|
|
153
154
|
};
|
|
154
155
|
/**
|
|
155
156
|
* Lift a tool-result file into a `MediaPart`. Tool files carry either a data URL, an `http(s)` URL, or raw base64 in
|
package/dist/route/auth.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { AIError, type HttpOptions } from "../schema/index.js";
|
|
|
4
4
|
export declare class MissingCredentialError extends Error {
|
|
5
5
|
readonly source: string;
|
|
6
6
|
readonly _tag = "MissingCredentialError";
|
|
7
|
-
constructor(source: string);
|
|
7
|
+
constructor(source: string, message?: string);
|
|
8
8
|
}
|
|
9
9
|
export type CredentialError = MissingCredentialError | Config.ConfigError;
|
|
10
10
|
export type AuthError = CredentialError | AIError;
|
package/dist/route/auth.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Config, Effect, Redacted } from "effect";
|
|
1
|
+
import { Config, Effect, Option, Redacted } from "effect";
|
|
2
2
|
import { Headers } from "effect/unstable/http";
|
|
3
|
-
import { AuthenticationError,
|
|
3
|
+
import { AuthenticationError, AIError } from "../schema/index.js";
|
|
4
4
|
export class MissingCredentialError extends Error {
|
|
5
5
|
source;
|
|
6
6
|
_tag = "MissingCredentialError";
|
|
7
|
-
constructor(source) {
|
|
8
|
-
super(
|
|
7
|
+
constructor(source, message = `Missing auth credential: ${source}`) {
|
|
8
|
+
super(message);
|
|
9
9
|
this.source = source;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -47,7 +47,12 @@ export const value = (secret, source = "value") => credentialFromSecret(secret,
|
|
|
47
47
|
export const optional = (secret, source = "optional value") => secret === undefined
|
|
48
48
|
? credential(Effect.fail(new MissingCredentialError(source)))
|
|
49
49
|
: credentialFromSecret(secret, source);
|
|
50
|
-
export const config = (name) =>
|
|
50
|
+
export const config = (name) => credential(Effect.gen(function* () {
|
|
51
|
+
const secret = yield* Config.option(Config.redacted(name));
|
|
52
|
+
if (Option.isSome(secret) && Redacted.value(secret.value) !== "")
|
|
53
|
+
return secret.value;
|
|
54
|
+
return yield* Effect.fail(new MissingCredentialError(name, `${name} is not set`));
|
|
55
|
+
}));
|
|
51
56
|
export const effect = (load) => credential(load);
|
|
52
57
|
export const none = auth((input) => Effect.succeed(input.headers));
|
|
53
58
|
export const headers = (input) => auth((inputAuth) => Effect.succeed(Headers.setAll(inputAuth.headers, input)));
|
|
@@ -80,14 +85,10 @@ export function scheme(name, source) {
|
|
|
80
85
|
return render(source);
|
|
81
86
|
}
|
|
82
87
|
const toAIError = (error) => {
|
|
83
|
-
if (error instanceof
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
: new InvalidRequestError({ message: `Failed to resolve auth config: ${error.message}`, cause: error }),
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
return error;
|
|
88
|
+
if (error instanceof AIError)
|
|
89
|
+
return error;
|
|
90
|
+
const message = error instanceof MissingCredentialError ? error.message : `Failed to resolve auth config: ${error.message}`;
|
|
91
|
+
return new AIError({ reason: new AuthenticationError({ message, cause: error }) });
|
|
91
92
|
};
|
|
92
93
|
export const toEffect = (input) => (authInput) => input.apply(authInput).pipe(Effect.mapError(toAIError));
|
|
93
94
|
export * as Auth from "./auth.js";
|
package/dist/route/client.d.ts
CHANGED
|
@@ -121,9 +121,11 @@ export declare function canCompact(request: LLMRequest, options?: {
|
|
|
121
121
|
export declare function canCompact(request: LLMRequest, options: {
|
|
122
122
|
readonly mechanism: "trigger";
|
|
123
123
|
}): request is CheckpointRequest;
|
|
124
|
-
declare const
|
|
125
|
-
export declare class
|
|
124
|
+
declare const LLMClientService_base: Context.ServiceClass<LLMClientService, "@opencode/LLMClient", Interface>;
|
|
125
|
+
export declare class LLMClientService extends LLMClientService_base {
|
|
126
126
|
}
|
|
127
|
+
export declare const Service: typeof LLMClientService;
|
|
128
|
+
export type Service = LLMClientService;
|
|
127
129
|
export interface MakeInput<Body, Frame, Event, State> {
|
|
128
130
|
readonly compact?: CompactionOperations;
|
|
129
131
|
/** Route id used in diagnostics and prepared request metadata. */
|
|
@@ -423,7 +425,7 @@ export declare const streamRequest: (request: LLMRequest, options?: StreamOption
|
|
|
423
425
|
readonly [x: string]: unknown;
|
|
424
426
|
};
|
|
425
427
|
} | undefined;
|
|
426
|
-
}, AIError,
|
|
428
|
+
}, AIError, LLMClientService>;
|
|
427
429
|
export declare const layer: Layer.Layer<Service, never, RequestExecutor.Service>;
|
|
428
430
|
export declare const Route: {
|
|
429
431
|
readonly make: typeof make;
|
|
@@ -431,8 +433,8 @@ export declare const Route: {
|
|
|
431
433
|
export declare const LLMClient: {
|
|
432
434
|
readonly canCompact: typeof canCompact;
|
|
433
435
|
readonly compact: typeof compact;
|
|
434
|
-
readonly Service: typeof
|
|
435
|
-
readonly layer: Layer.Layer<
|
|
436
|
+
readonly Service: typeof LLMClientService;
|
|
437
|
+
readonly layer: Layer.Layer<LLMClientService, never, import("./executor-service.js").RequestExecutorService>;
|
|
436
438
|
readonly stream: typeof stream;
|
|
437
439
|
readonly generate: typeof generate;
|
|
438
440
|
};
|
package/dist/route/client.js
CHANGED
|
@@ -66,8 +66,9 @@ const unsupportedCompaction = (request, mechanism) => {
|
|
|
66
66
|
message: `${request.model.provider}/${request.model.route.id} does not support ${mechanism === "trigger" ? "trigger" : "explicit"} compaction`,
|
|
67
67
|
});
|
|
68
68
|
};
|
|
69
|
-
export class
|
|
69
|
+
export class LLMClientService extends Context.Service()("@opencode/LLMClient") {
|
|
70
70
|
}
|
|
71
|
+
export const Service = LLMClientService;
|
|
71
72
|
const resolveRequestOptions = (request) => {
|
|
72
73
|
const messages = normalizeToolHistory(request.messages);
|
|
73
74
|
const normalized = messages === request.messages ? request : LLMRequest.update(request, { messages });
|
|
@@ -6,7 +6,9 @@ export interface Interface {
|
|
|
6
6
|
}
|
|
7
7
|
export type HttpHandler = (request: HttpClientRequest.HttpClientRequest) => Effect.Effect<HttpClientResponse.HttpClientResponse, Error>;
|
|
8
8
|
export type HttpMiddleware = (request: HttpClientRequest.HttpClientRequest, handler: HttpHandler) => Effect.Effect<HttpClientResponse.HttpClientResponse, Error>;
|
|
9
|
-
declare const
|
|
10
|
-
export declare class
|
|
9
|
+
declare const RequestExecutorService_base: Context.ServiceClass<RequestExecutorService, "@opencode/AI/RequestExecutor", Interface>;
|
|
10
|
+
export declare class RequestExecutorService extends RequestExecutorService_base {
|
|
11
11
|
}
|
|
12
|
+
export declare const Service: typeof RequestExecutorService;
|
|
13
|
+
export type Service = RequestExecutorService;
|
|
12
14
|
export {};
|
package/dist/route/executor.d.ts
CHANGED
|
@@ -18,5 +18,7 @@ export declare const httpFailure: (input: {
|
|
|
18
18
|
export declare const responseStream: (response: HttpClientResponse.HttpClientResponse) => Stream.Stream<Uint8Array, AIError>;
|
|
19
19
|
export declare const stream: (executor: Interface, request: HttpClientRequest.HttpClientRequest, middleware?: HttpMiddleware) => Stream.Stream<Uint8Array, AIError>;
|
|
20
20
|
export declare const layer: Layer.Layer<Service, never, HttpClient.HttpClient>;
|
|
21
|
-
export declare const fetchLayer: Layer.Layer<
|
|
21
|
+
export declare const fetchLayer: Layer.Layer<import("./executor-service.js").RequestExecutorService, never, never>;
|
|
22
|
+
/** Run `fn` on every request: it sees the raw response before status classification, inside middleware already on `executor`, and outside per-call middleware. */
|
|
23
|
+
export declare const middleware: (fn: HttpMiddleware, executor?: Layer.Layer<Service>) => Layer.Layer<Service>;
|
|
22
24
|
export * as RequestExecutor from "./executor.js";
|
package/dist/route/executor.js
CHANGED
|
@@ -180,4 +180,11 @@ export const layer = Layer.effect(Service, Effect.gen(function* () {
|
|
|
180
180
|
});
|
|
181
181
|
}));
|
|
182
182
|
export const fetchLayer = layer.pipe(Layer.provide(FetchHttpClient.layer));
|
|
183
|
+
/** Run `fn` on every request: it sees the raw response before status classification, inside middleware already on `executor`, and outside per-call middleware. */
|
|
184
|
+
export const middleware = (fn, executor = fetchLayer) => Layer.effect(Service, Effect.gen(function* () {
|
|
185
|
+
const inner = yield* Service;
|
|
186
|
+
return Service.of({
|
|
187
|
+
execute: (request, next) => inner.execute(request, next === undefined ? fn : (input, handler) => fn(input, (forwarded) => next(forwarded, handler))),
|
|
188
|
+
});
|
|
189
|
+
})).pipe(Layer.provide(executor));
|
|
183
190
|
export * as RequestExecutor from "./executor.js";
|
package/dist/route/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Route, LLMClient } from "./client.js";
|
|
2
|
-
export type { Route as RouteShape, RouteLanguageModelInput, RouteRoutedLanguageModelInput, RouteDefaults, RouteDefaultsInput, AnyRoute, Interface as LLMClientShape,
|
|
2
|
+
export type { Route as RouteShape, RouteLanguageModelInput, RouteRoutedLanguageModelInput, RouteDefaults, RouteDefaultsInput, AnyRoute, Interface as LLMClientShape, LLMClientService, StreamOptions, CompactMethod, CompactionOperations, CompactionRequest, CheckpointRequest, EndpointCompactOptions, TriggerCompactOptions, } from "./client.js";
|
|
3
3
|
export * from "./executor.js";
|
|
4
4
|
export { Auth } from "./auth.js";
|
|
5
5
|
export { AuthOptions } from "./auth-options.js";
|
package/dist/speech-client.d.ts
CHANGED
|
@@ -6,15 +6,17 @@ export interface Interface {
|
|
|
6
6
|
readonly generate: <Options extends SpeechOptions>(request: SpeechRequestFor<Options>) => Effect.Effect<SpeechResponse, AIError>;
|
|
7
7
|
readonly stream: <Options extends SpeechOptions>(request: SpeechRequestFor<Options>) => Stream.Stream<SpeechEvent, AIError>;
|
|
8
8
|
}
|
|
9
|
-
declare const
|
|
10
|
-
export declare class
|
|
9
|
+
declare const SpeechClientService_base: Context.ServiceClass<SpeechClientService, "@opencode/SpeechClient", Interface>;
|
|
10
|
+
export declare class SpeechClientService extends SpeechClientService_base {
|
|
11
11
|
}
|
|
12
|
+
export declare const Service: typeof SpeechClientService;
|
|
13
|
+
export type Service = SpeechClientService;
|
|
12
14
|
export declare const generate: <Options extends SpeechOptions>(request: SpeechRequestFor<Options>) => Effect.Effect<SpeechResponse, AIError, Service>;
|
|
13
15
|
export declare const stream: <Options extends SpeechOptions>(request: SpeechRequestFor<Options>) => Stream.Stream<SpeechEvent, AIError, Service>;
|
|
14
16
|
export declare const layer: Layer.Layer<Service, never, RequestExecutor.Service>;
|
|
15
17
|
export declare const SpeechClient: {
|
|
16
|
-
readonly Service: typeof
|
|
17
|
-
readonly layer: Layer.Layer<
|
|
18
|
+
readonly Service: typeof SpeechClientService;
|
|
19
|
+
readonly layer: Layer.Layer<SpeechClientService, never, import("./route/executor-service.js").RequestExecutorService>;
|
|
18
20
|
readonly generate: <Options extends SpeechOptions>(request: SpeechRequestFor<Options>) => Effect.Effect<SpeechResponse, AIError, Service>;
|
|
19
21
|
readonly stream: <Options extends SpeechOptions>(request: SpeechRequestFor<Options>) => Stream.Stream<SpeechEvent, AIError, Service>;
|
|
20
22
|
};
|
package/dist/speech-client.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Context, Effect, Layer, Stream } from "effect";
|
|
2
2
|
import { RequestExecutor } from "./route/executor.js";
|
|
3
|
-
export class
|
|
3
|
+
export class SpeechClientService extends Context.Service()("@opencode/SpeechClient") {
|
|
4
4
|
}
|
|
5
|
+
export const Service = SpeechClientService;
|
|
5
6
|
export const generate = (request) => Effect.gen(function* () {
|
|
6
7
|
const client = yield* Service;
|
|
7
8
|
return yield* client.generate(request);
|
package/dist/testing.d.ts
CHANGED
|
@@ -1743,11 +1743,11 @@ export declare const hangAfter: (...events: readonly LLMEvent[]) => Stream.Strea
|
|
|
1743
1743
|
} | undefined;
|
|
1744
1744
|
}, never, never>;
|
|
1745
1745
|
/** Provides one shared implementation under the normal client and test-control tags. */
|
|
1746
|
-
export declare const testLayer: (options?: LayerOptions) => Layer.Layer<import("./route/client.js").
|
|
1746
|
+
export declare const testLayer: (options?: LayerOptions) => Layer.Layer<import("./route/client.js").LLMClientService | Test, never, never>;
|
|
1747
1747
|
/** @deprecated Use testLayer; retained for published callers of the legacy control interface. */
|
|
1748
1748
|
export declare const layer: (options?: LayerOptions) => Layer.Layer<Service, never, never>;
|
|
1749
1749
|
/** @deprecated testLayer provides LLMClient.Service directly. */
|
|
1750
|
-
export declare const clientLayer: Layer.Layer<import("./route/client.js").
|
|
1750
|
+
export declare const clientLayer: Layer.Layer<import("./route/client.js").LLMClientService, never, Service>;
|
|
1751
1751
|
export declare const push: (...responses: readonly Response[]) => Effect.Effect<void, never, Service>;
|
|
1752
1752
|
export declare const always: (response: Response) => Effect.Effect<void, never, Service>;
|
|
1753
1753
|
export declare const wait: (count: number) => Effect.Effect<void, never, Service>;
|
|
@@ -9,17 +9,19 @@ export interface Interface {
|
|
|
9
9
|
readonly start: <Options extends TranscriptionOptions>(request: TranscriptionRequestFor<Options>) => Effect.Effect<Generation<TranscriptionResponse>, AIError>;
|
|
10
10
|
readonly resume: <Options extends TranscriptionOptions>(model: TranscriptionModel<Options>, token: unknown) => Effect.Effect<Generation<TranscriptionResponse>, AIError>;
|
|
11
11
|
}
|
|
12
|
-
declare const
|
|
13
|
-
export declare class
|
|
12
|
+
declare const TranscriptionClientService_base: Context.ServiceClass<TranscriptionClientService, "@opencode/TranscriptionClient", Interface>;
|
|
13
|
+
export declare class TranscriptionClientService extends TranscriptionClientService_base {
|
|
14
14
|
}
|
|
15
|
+
export declare const Service: typeof TranscriptionClientService;
|
|
16
|
+
export type Service = TranscriptionClientService;
|
|
15
17
|
export declare const generate: <Options extends TranscriptionOptions>(request: TranscriptionRequestFor<Options>, options?: AwaitOptions) => Effect.Effect<TranscriptionResponse, AIError, Service>;
|
|
16
18
|
export declare const stream: <Options extends TranscriptionOptions>(request: TranscriptionRequestFor<Options>, options?: AwaitOptions) => Stream.Stream<TranscriptionEvent, AIError, Service>;
|
|
17
19
|
export declare const start: <Options extends TranscriptionOptions>(request: TranscriptionRequestFor<Options>) => Effect.Effect<Generation<TranscriptionResponse>, AIError, Service>;
|
|
18
20
|
export declare const resume: <Options extends TranscriptionOptions>(model: TranscriptionModel<Options>, token: unknown) => Effect.Effect<Generation<TranscriptionResponse>, AIError, Service>;
|
|
19
21
|
export declare const layer: Layer.Layer<Service, never, RequestExecutor.Service>;
|
|
20
22
|
export declare const TranscriptionClient: {
|
|
21
|
-
readonly Service: typeof
|
|
22
|
-
readonly layer: Layer.Layer<
|
|
23
|
+
readonly Service: typeof TranscriptionClientService;
|
|
24
|
+
readonly layer: Layer.Layer<TranscriptionClientService, never, import("./route/executor-service.js").RequestExecutorService>;
|
|
23
25
|
readonly generate: <Options extends TranscriptionOptions>(request: TranscriptionRequestFor<Options>, options?: AwaitOptions) => Effect.Effect<TranscriptionResponse, AIError, Service>;
|
|
24
26
|
readonly stream: <Options extends TranscriptionOptions>(request: TranscriptionRequestFor<Options>, options?: AwaitOptions) => Stream.Stream<TranscriptionEvent, AIError, Service>;
|
|
25
27
|
readonly start: <Options extends TranscriptionOptions>(request: TranscriptionRequestFor<Options>) => Effect.Effect<Generation<TranscriptionResponse>, AIError, Service>;
|
|
@@ -2,8 +2,9 @@ import { Context, Effect, Layer, Stream } from "effect";
|
|
|
2
2
|
import { RequestExecutor } from "./route/executor.js";
|
|
3
3
|
import { MediaRoute } from "./route/media.js";
|
|
4
4
|
import { responseEvents, } from "./transcription.js";
|
|
5
|
-
export class
|
|
5
|
+
export class TranscriptionClientService extends Context.Service()("@opencode/TranscriptionClient") {
|
|
6
6
|
}
|
|
7
|
+
export const Service = TranscriptionClientService;
|
|
7
8
|
export const generate = (request, options) => Effect.gen(function* () {
|
|
8
9
|
const client = yield* Service;
|
|
9
10
|
return yield* client.generate(request, options);
|
package/dist/transcription.d.ts
CHANGED
|
@@ -1012,7 +1012,7 @@ export declare const TranscriptionEvent: Schema.Union<readonly [Schema.Struct<{
|
|
|
1012
1012
|
readonly confidence?: number | undefined;
|
|
1013
1013
|
}[] | undefined;
|
|
1014
1014
|
}) => any) | undefined;
|
|
1015
|
-
} & { [K in Exclude<keyof Cases, "finish" | "
|
|
1015
|
+
} & { [K in Exclude<keyof Cases, "finish" | "generation-queued" | "generation-progress" | "text-delta" | "segment">]: never; }, OrElse extends (value: Exclude<{
|
|
1016
1016
|
readonly id: string;
|
|
1017
1017
|
readonly type: "generation-queued";
|
|
1018
1018
|
readonly position?: number | undefined;
|
|
@@ -1245,7 +1245,7 @@ export declare const TranscriptionEvent: Schema.Union<readonly [Schema.Struct<{
|
|
|
1245
1245
|
readonly confidence?: number | undefined;
|
|
1246
1246
|
}[] | undefined;
|
|
1247
1247
|
}) => any) | undefined;
|
|
1248
|
-
} & { [K in Exclude<keyof Cases, "finish" | "
|
|
1248
|
+
} & { [K in Exclude<keyof Cases, "finish" | "generation-queued" | "generation-progress" | "text-delta" | "segment">]: never; }, OrElse extends (value: Exclude<{
|
|
1249
1249
|
readonly id: string;
|
|
1250
1250
|
readonly type: "generation-queued";
|
|
1251
1251
|
readonly position?: number | undefined;
|
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
* `undefined` so callers can fall back to a provider-declared type or `application/octet-stream`.
|
|
4
4
|
*/
|
|
5
5
|
export declare const detectMediaType: (bytes: Uint8Array) => string | undefined;
|
|
6
|
-
|
|
6
|
+
/** Media type of a file's contents: sniffed magic bytes, then the path's extension. */
|
|
7
|
+
export declare const fileMediaType: (bytes: Uint8Array, path: string) => string | undefined;
|
|
7
8
|
export declare const mediaTypeExtension: (mediaType: string) => string | undefined;
|
package/dist/utils/media-type.js
CHANGED
|
@@ -54,7 +54,9 @@ const EXTENSIONS = {
|
|
|
54
54
|
md: "text/markdown",
|
|
55
55
|
csv: "text/csv",
|
|
56
56
|
};
|
|
57
|
-
|
|
57
|
+
const extensionMediaType = (path) => EXTENSIONS[path.slice(path.lastIndexOf(".") + 1).toLowerCase()];
|
|
58
|
+
/** Media type of a file's contents: sniffed magic bytes, then the path's extension. */
|
|
59
|
+
export const fileMediaType = (bytes, path) => detectMediaType(bytes) ?? extensionMediaType(path);
|
|
58
60
|
const EXTENSION_ALIASES = {
|
|
59
61
|
"audio/mp3": "mp3",
|
|
60
62
|
"audio/m4a": "m4a",
|