@opencode/ai 2.0.15 → 2.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +441 -99
- package/dist/ai-client.d.ts +8 -0
- package/dist/ai-client.js +12 -0
- package/dist/experimental/evaluation-client.d.ts +3 -3
- package/dist/experimental/evaluation-client.js +1 -1
- package/dist/experimental/evaluation.js +1 -1
- package/dist/generation.d.ts +39 -29
- package/dist/generation.js +62 -36
- package/dist/image-client.d.ts +59 -17
- package/dist/image-client.js +16 -24
- package/dist/image.d.ts +394 -55
- package/dist/image.js +48 -57
- package/dist/index.d.ts +15 -2
- package/dist/index.js +10 -0
- package/dist/llm.d.ts +7 -5
- package/dist/llm.js +10 -4
- package/dist/media-client.d.ts +30 -0
- package/dist/media-client.js +51 -0
- package/dist/media-model.d.ts +43 -0
- package/dist/media-model.js +47 -0
- package/dist/media.d.ts +10 -9
- package/dist/media.js +11 -12
- package/dist/promise.d.ts +473 -15
- package/dist/promise.js +71 -13
- package/dist/protocols/alibaba-chat.d.ts +12 -0
- package/dist/protocols/alibaba-chat.js +4 -1
- package/dist/protocols/alibaba-messages.d.ts +1 -1
- package/dist/protocols/alibaba-messages.js +6 -4
- package/dist/protocols/alibaba-responses.d.ts +2 -2
- package/dist/protocols/anthropic-messages.d.ts +34 -34
- package/dist/protocols/anthropic-messages.js +14 -9
- package/dist/protocols/assemblyai-transcription.d.ts +41 -0
- package/dist/protocols/assemblyai-transcription.js +136 -0
- package/dist/protocols/bedrock-converse.d.ts +7 -0
- package/dist/protocols/bedrock-converse.js +39 -19
- package/dist/protocols/bfl-images.d.ts +38 -0
- package/dist/protocols/bfl-images.js +153 -0
- package/dist/protocols/cartesia-speech.d.ts +143 -0
- package/dist/protocols/cartesia-speech.js +120 -0
- package/dist/protocols/deepgram-speech.d.ts +135 -0
- package/dist/protocols/deepgram-speech.js +91 -0
- package/dist/protocols/deepgram-transcription.d.ts +26 -0
- package/dist/protocols/deepgram-transcription.js +125 -0
- package/dist/protocols/elevenlabs-speech.d.ts +138 -0
- package/dist/protocols/elevenlabs-speech.js +111 -0
- package/dist/protocols/fal-images.d.ts +25 -0
- package/dist/protocols/fal-images.js +104 -0
- package/dist/protocols/fal-video.d.ts +29 -0
- package/dist/protocols/fal-video.js +73 -0
- package/dist/protocols/gemini.d.ts +22 -22
- package/dist/protocols/gemini.js +19 -36
- package/dist/protocols/google-images.d.ts +3 -3
- package/dist/protocols/google-images.js +12 -34
- package/dist/protocols/google-speech.d.ts +146 -0
- package/dist/protocols/google-speech.js +88 -0
- package/dist/protocols/google-transcription.d.ts +174 -0
- package/dist/protocols/google-transcription.js +126 -0
- package/dist/protocols/google-video.d.ts +26 -0
- package/dist/protocols/google-video.js +142 -0
- package/dist/protocols/meta-images.d.ts +3 -4
- package/dist/protocols/meta-images.js +13 -29
- package/dist/protocols/meta-messages.d.ts +5 -5
- package/dist/protocols/meta-responses.d.ts +4 -4
- package/dist/protocols/meta-responses.js +6 -4
- package/dist/protocols/open-responses.d.ts +10 -9
- package/dist/protocols/open-responses.js +4 -9
- package/dist/protocols/openai-chat.d.ts +84 -0
- package/dist/protocols/openai-chat.js +28 -17
- package/dist/protocols/openai-compatible-chat.d.ts +12 -0
- package/dist/protocols/openai-compatible-responses.d.ts +2 -2
- package/dist/protocols/openai-images.d.ts +130 -7
- package/dist/protocols/openai-images.js +143 -91
- package/dist/protocols/openai-responses.d.ts +20 -20
- package/dist/protocols/openai-responses.js +31 -31
- package/dist/protocols/openai-speech.d.ts +136 -0
- package/dist/protocols/openai-speech.js +97 -0
- package/dist/protocols/openai-transcription.d.ts +211 -0
- package/dist/protocols/openai-transcription.js +202 -0
- package/dist/protocols/replicate-images.d.ts +28 -0
- package/dist/protocols/replicate-images.js +127 -0
- package/dist/protocols/runway-video.d.ts +38 -0
- package/dist/protocols/runway-video.js +140 -0
- package/dist/protocols/shared.d.ts +21 -17
- package/dist/protocols/shared.js +27 -36
- package/dist/protocols/stability-images.d.ts +39 -0
- package/dist/protocols/stability-images.js +136 -0
- package/dist/protocols/utils/fal-queue.d.ts +26 -0
- package/dist/protocols/utils/fal-queue.js +67 -0
- package/dist/protocols/utils/gemini-generate-content.d.ts +65 -0
- package/dist/protocols/utils/gemini-generate-content.js +65 -0
- package/dist/protocols/utils/gemini-json-schema.d.ts +3 -0
- package/dist/protocols/utils/gemini-json-schema.js +76 -0
- package/dist/protocols/utils/media-input.d.ts +23 -1
- package/dist/protocols/utils/media-input.js +40 -0
- package/dist/protocols/utils/responses-checkpoint.js +3 -7
- package/dist/protocols/utils/responses-compaction.d.ts +3 -1
- package/dist/protocols/utils/responses-compaction.js +16 -3
- package/dist/protocols/utils/speech-stream.d.ts +49 -0
- package/dist/protocols/utils/speech-stream.js +64 -0
- package/dist/protocols/utils/tool-schema.d.ts +2 -2
- package/dist/protocols/utils/tool-schema.js +62 -19
- package/dist/protocols/xai-images.d.ts +4 -4
- package/dist/protocols/xai-images.js +14 -40
- package/dist/protocols/xai-responses.d.ts +2 -2
- package/dist/protocols/xai-responses.js +1 -1
- package/dist/protocols/xai-video.d.ts +34 -0
- package/dist/protocols/xai-video.js +141 -0
- package/dist/protocols/zai-chat.d.ts +13 -1
- package/dist/protocols/zai-images.d.ts +2 -2
- package/dist/protocols/zai-images.js +11 -14
- package/dist/protocols/zai-messages.d.ts +1 -1
- package/dist/provider-error.js +10 -1
- package/dist/providers/alibaba.d.ts +15 -3
- package/dist/providers/amazon-bedrock-mantle.d.ts +14 -2
- package/dist/providers/amazon-bedrock.d.ts +2 -0
- package/dist/providers/amazon-bedrock.js +1 -0
- package/dist/providers/anthropic-compatible.d.ts +5 -5
- package/dist/providers/anthropic.d.ts +5 -5
- package/dist/providers/assemblyai.d.ts +25 -0
- package/dist/providers/assemblyai.js +24 -0
- package/dist/providers/azure.d.ts +20 -8
- package/dist/providers/azure.js +2 -2
- package/dist/providers/baseten.d.ts +24 -0
- package/dist/providers/black-forest-labs.d.ts +25 -0
- package/dist/providers/black-forest-labs.js +23 -0
- package/dist/providers/cartesia.d.ts +24 -0
- package/dist/providers/cartesia.js +17 -0
- package/dist/providers/cerebras.d.ts +24 -0
- package/dist/providers/cloudflare-ai-gateway.d.ts +42 -18
- package/dist/providers/cloudflare-workers-ai.d.ts +24 -0
- package/dist/providers/deepgram.d.ts +29 -0
- package/dist/providers/deepgram.js +25 -0
- package/dist/providers/deepinfra.d.ts +24 -0
- package/dist/providers/deepseek.d.ts +24 -0
- package/dist/providers/elevenlabs.d.ts +24 -0
- package/dist/providers/elevenlabs.js +23 -0
- package/dist/providers/fal.d.ts +29 -0
- package/dist/providers/fal.js +26 -0
- package/dist/providers/fireworks.d.ts +24 -0
- package/dist/providers/google-vertex-chat.d.ts +12 -0
- package/dist/providers/google-vertex-messages.d.ts +5 -5
- package/dist/providers/google-vertex-responses.d.ts +2 -2
- package/dist/providers/google-vertex.d.ts +6 -6
- package/dist/providers/google.d.ts +21 -6
- package/dist/providers/google.js +13 -9
- package/dist/providers/groq.d.ts +24 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/meta.d.ts +22 -10
- package/dist/providers/meta.js +4 -8
- package/dist/providers/minimax.d.ts +19 -7
- package/dist/providers/moonshot.d.ts +19 -7
- package/dist/providers/moonshot.js +3 -3
- package/dist/providers/openai-compatible-responses.d.ts +2 -2
- package/dist/providers/openai-compatible.d.ts +12 -0
- package/dist/providers/openai-options.d.ts +3 -9
- package/dist/providers/openai-options.js +4 -7
- package/dist/providers/openai.d.ts +33 -12
- package/dist/providers/openai.js +17 -9
- package/dist/providers/opencode-zen.js +1 -1
- package/dist/providers/openrouter.d.ts +54 -7
- package/dist/providers/openrouter.js +10 -5
- package/dist/providers/replicate.d.ts +25 -0
- package/dist/providers/replicate.js +17 -0
- package/dist/providers/runway.d.ts +24 -0
- package/dist/providers/runway.js +17 -0
- package/dist/providers/stability.d.ts +28 -0
- package/dist/providers/stability.js +18 -0
- package/dist/providers/togetherai.d.ts +24 -0
- package/dist/providers/typesafe-ai.js +1 -1
- package/dist/providers/vercel-ai-gateway.js +1 -1
- package/dist/providers/xai.d.ts +17 -0
- package/dist/providers/xai.js +7 -9
- package/dist/providers/zai-coding-plan.d.ts +16 -4
- package/dist/providers/zai.d.ts +13 -1
- package/dist/providers/zai.js +4 -8
- package/dist/route/auth.d.ts +5 -2
- package/dist/route/auth.js +20 -13
- package/dist/route/client.d.ts +9 -7
- package/dist/route/client.js +6 -8
- package/dist/route/endpoint.d.ts +1 -0
- package/dist/route/endpoint.js +2 -2
- package/dist/route/executor-service.d.ts +4 -2
- package/dist/route/executor-service.js +2 -1
- package/dist/route/executor.d.ts +3 -1
- package/dist/route/executor.js +7 -0
- package/dist/route/framing.d.ts +15 -2
- package/dist/route/framing.js +53 -4
- package/dist/route/index.d.ts +1 -1
- package/dist/route/media-protocol.d.ts +145 -18
- package/dist/route/media-protocol.js +96 -28
- package/dist/route/media.d.ts +54 -9
- package/dist/route/media.js +194 -38
- package/dist/route/protocol.d.ts +3 -1
- package/dist/schema/events.d.ts +0 -6
- package/dist/schema/messages.d.ts +0 -3
- package/dist/schema/options.d.ts +10 -6
- package/dist/schema/options.js +10 -5
- package/dist/speech-client.d.ts +66 -0
- package/dist/speech-client.js +21 -0
- package/dist/speech.d.ts +1307 -0
- package/dist/speech.js +124 -0
- package/dist/testing.d.ts +2 -2
- package/dist/transcription-client.d.ts +82 -0
- package/dist/transcription-client.js +13 -0
- package/dist/transcription.d.ts +1492 -0
- package/dist/transcription.js +127 -0
- package/dist/utils/bytes.d.ts +1 -0
- package/dist/utils/bytes.js +10 -0
- package/dist/utils/json.d.ts +4 -0
- package/dist/utils/json.js +4 -0
- package/dist/utils/media-type.d.ts +3 -1
- package/dist/utils/media-type.js +25 -2
- package/dist/video-client.d.ts +59 -0
- package/dist/video-client.js +20 -0
- package/dist/video.d.ts +1351 -0
- package/dist/video.js +118 -0
- package/package.json +3 -3
- package/dist/protocols/utils/gemini-tool-schema.d.ts +0 -2
- package/dist/protocols/utils/gemini-tool-schema.js +0 -103
- package/dist/protocols/utils/meta-image.d.ts +0 -2
- package/dist/protocols/utils/meta-image.js +0 -13
- package/dist/protocols/utils/openai-image.d.ts +0 -5
- package/dist/protocols/utils/openai-image.js +0 -18
package/dist/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;
|
|
@@ -13,7 +13,7 @@ export interface AuthInput {
|
|
|
13
13
|
readonly request: {
|
|
14
14
|
readonly http?: HttpOptions;
|
|
15
15
|
};
|
|
16
|
-
readonly method: "POST" | "GET";
|
|
16
|
+
readonly method: "POST" | "GET" | "PUT" | "DELETE";
|
|
17
17
|
readonly url: string;
|
|
18
18
|
readonly body: string;
|
|
19
19
|
readonly headers: Headers.Headers;
|
|
@@ -47,5 +47,8 @@ export declare function header(name: string): (source: Secret | Credential) => D
|
|
|
47
47
|
export declare function header(name: string, source: Secret | Credential): Definition;
|
|
48
48
|
export declare function bearerHeader(name: string): (source: Secret | Credential) => Definition;
|
|
49
49
|
export declare function bearerHeader(name: string, source: Secret | Credential): Definition;
|
|
50
|
+
/** `Authorization: <scheme> <secret>` for providers whose scheme is not `Bearer`, such as fal's `Key`. */
|
|
51
|
+
export declare function scheme(name: string): (source: Secret | Credential) => Definition;
|
|
52
|
+
export declare function scheme(name: string, source: Secret | Credential): Definition;
|
|
50
53
|
export declare const toEffect: (input: Definition) => (authInput: AuthInput) => Effect.Effect<Headers.Headers, AIError>;
|
|
51
54
|
export * as Auth from "./auth.js";
|
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)));
|
|
@@ -73,15 +78,17 @@ export function bearerHeader(name, source) {
|
|
|
73
78
|
return render;
|
|
74
79
|
return render(source);
|
|
75
80
|
}
|
|
81
|
+
export function scheme(name, source) {
|
|
82
|
+
const render = (input) => fromCredential(credentialInput(input), (secret) => ({ authorization: `${name} ${secret}` }));
|
|
83
|
+
if (source === undefined)
|
|
84
|
+
return render;
|
|
85
|
+
return render(source);
|
|
86
|
+
}
|
|
76
87
|
const toAIError = (error) => {
|
|
77
|
-
if (error instanceof
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
: new InvalidRequestError({ message: `Failed to resolve auth config: ${error.message}`, cause: error }),
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
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 }) });
|
|
85
92
|
};
|
|
86
93
|
export const toEffect = (input) => (authInput) => input.apply(authInput).pipe(Effect.mapError(toAIError));
|
|
87
94
|
export * as Auth from "./auth.js";
|
package/dist/route/client.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Framing } from "./framing.js";
|
|
|
6
6
|
import { HttpTransport } from "./transport/index.js";
|
|
7
7
|
import type { HttpMiddleware, Transport, TransportRuntime, WebSocketChannelExecutor } from "./transport/index.js";
|
|
8
8
|
import type { Protocol } from "./protocol.js";
|
|
9
|
-
import type { ProtocolID, ProviderOptions } from "../schema/index.js";
|
|
9
|
+
import type { LanguageModelSanitizerCompatibility, ProtocolID, ProviderOptions } from "../schema/index.js";
|
|
10
10
|
import { AIError, CompactionResponse, CompactionCheckpointResponse, GenerationOptions, HttpOptions, LLMRequest, LLMResponse, LanguageModel, LLMEvent, ProviderID } from "../schema/index.js";
|
|
11
11
|
export interface RouteBody<Body> {
|
|
12
12
|
/** Schema for the validated provider-native body sent as the JSON request. */
|
|
@@ -31,6 +31,7 @@ export interface Route<Body, Prepared = unknown, Compact extends CompactionOpera
|
|
|
31
31
|
readonly defaults: RouteDefaults;
|
|
32
32
|
readonly body: RouteBody<Body>;
|
|
33
33
|
readonly supportsEffortUpdates?: (request: LLMRequest) => boolean;
|
|
34
|
+
readonly sanitizer?: LanguageModelSanitizerCompatibility;
|
|
34
35
|
readonly with: {
|
|
35
36
|
<Next extends CompactionOperations | undefined>(patch: RoutePatch<Body, Prepared> & {
|
|
36
37
|
readonly compact: Next;
|
|
@@ -71,7 +72,6 @@ export interface RoutePatch<Body, Prepared> extends RouteDefaultsInput {
|
|
|
71
72
|
}
|
|
72
73
|
type RouteMappedLanguageModelInput = RouteLanguageModelInput | RouteRoutedLanguageModelInput;
|
|
73
74
|
export declare const generationOptions: (input: GenerationOptions.Input | undefined) => GenerationOptions | undefined;
|
|
74
|
-
export declare const httpOptions: (input: HttpOptionsInput | undefined) => HttpOptions | undefined;
|
|
75
75
|
export interface Interface {
|
|
76
76
|
readonly compact: CompactMethod;
|
|
77
77
|
readonly stream: StreamMethod;
|
|
@@ -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
|
@@ -9,6 +9,7 @@ import { applyEffortUpdates } from "../effort-updates.js";
|
|
|
9
9
|
import { normalizeToolHistory } from "../tool-history.js";
|
|
10
10
|
import { sanitizeSurrogates } from "../utils/sanitize.js";
|
|
11
11
|
import * as ProviderShared from "../protocols/shared.js";
|
|
12
|
+
import { ToolSchemaProjection } from "../protocols/utils/tool-schema.js";
|
|
12
13
|
import { AIError, CompactionResponse, CompactionCheckpointResponse, AIErrorReason, GenerationOptions, HttpOptions, LLMRequest, LLMResponse, LanguageModel, LLMEvent, InvalidProviderOutputError, ProviderConfigurationError, ProviderID, mergeGenerationOptions, mergeHttpOptions, mergeProviderOptions, } from "../schema/index.js";
|
|
13
14
|
const makeRouteLanguageModel = (route, mapped) => {
|
|
14
15
|
const provider = route.provider ?? ("provider" in mapped ? mapped.provider : undefined);
|
|
@@ -33,7 +34,7 @@ const mergeRouteDefaults = (base, patch) => {
|
|
|
33
34
|
headers,
|
|
34
35
|
generation: mergeGenerationOptions(generationOptions(base?.generation), generationOptions(patch.generation)),
|
|
35
36
|
providerOptions: mergeProviderOptions(base?.providerOptions, patch.providerOptions),
|
|
36
|
-
http: mergeHttpOptions(base?.http,
|
|
37
|
+
http: mergeHttpOptions(base?.http, HttpOptions.make(patch.http), headers === undefined ? undefined : new HttpOptions({ headers })),
|
|
37
38
|
};
|
|
38
39
|
};
|
|
39
40
|
const endpointBaseURL = (endpoint) => typeof endpoint.baseURL === "string" ? endpoint.baseURL : undefined;
|
|
@@ -44,11 +45,6 @@ const mergeHeaders = (...items) => {
|
|
|
44
45
|
return Object.fromEntries(entries);
|
|
45
46
|
};
|
|
46
47
|
export const generationOptions = (input) => input === undefined ? undefined : GenerationOptions.make(input);
|
|
47
|
-
export const httpOptions = (input) => {
|
|
48
|
-
if (input === undefined)
|
|
49
|
-
return input;
|
|
50
|
-
return HttpOptions.make(input);
|
|
51
|
-
};
|
|
52
48
|
export function canCompact(request, options) {
|
|
53
49
|
if (options?.mechanism === "trigger")
|
|
54
50
|
return request.model.route.compact?.trigger !== undefined;
|
|
@@ -66,8 +62,9 @@ const unsupportedCompaction = (request, mechanism) => {
|
|
|
66
62
|
message: `${request.model.provider}/${request.model.route.id} does not support ${mechanism === "trigger" ? "trigger" : "explicit"} compaction`,
|
|
67
63
|
});
|
|
68
64
|
};
|
|
69
|
-
export class
|
|
65
|
+
export class LLMClientService extends Context.Service()("@opencode/LLMClient") {
|
|
70
66
|
}
|
|
67
|
+
export const Service = LLMClientService;
|
|
71
68
|
const resolveRequestOptions = (request) => {
|
|
72
69
|
const messages = normalizeToolHistory(request.messages);
|
|
73
70
|
const normalized = messages === request.messages ? request : LLMRequest.update(request, { messages });
|
|
@@ -122,6 +119,7 @@ function makeFromTransport(input) {
|
|
|
122
119
|
defaults: routeInput.defaults ?? {},
|
|
123
120
|
body: protocol.body,
|
|
124
121
|
supportsEffortUpdates: protocol.supportsEffortUpdates,
|
|
122
|
+
sanitizer: protocol.sanitizer,
|
|
125
123
|
with: (patch) => {
|
|
126
124
|
const { compact, id, provider, providerMetadataKey, auth, transport, endpoint, ...defaults } = patch;
|
|
127
125
|
return build({
|
|
@@ -214,7 +212,7 @@ const prepareRequest = (request) => {
|
|
|
214
212
|
const sanitized = LLMRequest.update(original, sanitizeSurrogates({ ...LLMRequest.input(original), model: undefined }));
|
|
215
213
|
// Deduplicate per sibling level; a tool and a namespace may share a name.
|
|
216
214
|
const dedupe = (tools) => [...new Map(tools.map((tool) => [`${tool.type}:${tool.name}`, tool])).values()].map((tool) => tool.type === "tool" ? tool : { ...tool, tools: dedupe(tool.tools) });
|
|
217
|
-
const resolved = applyCachePolicy(applyEffortUpdates(LLMRequest.update(sanitized, { tools: dedupe(sanitized.tools) })));
|
|
215
|
+
const resolved = applyCachePolicy(applyEffortUpdates(LLMRequest.update(sanitized, { tools: ToolSchemaProjection.tools(dedupe(sanitized.tools), sanitized.model) })));
|
|
218
216
|
const headers = resolved.model.route.headers?.({ request: resolved });
|
|
219
217
|
return headers === undefined
|
|
220
218
|
? resolved
|
package/dist/route/endpoint.d.ts
CHANGED
|
@@ -24,5 +24,6 @@ export type EndpointPatch<Body, Request = LLMRequest> = Partial<Definition<Body,
|
|
|
24
24
|
/** Construct an `Endpoint` from a path string or path function. */
|
|
25
25
|
export declare const path: <Body, Request = LLMRequest>(value: EndpointPart<Body, Request>, options?: Omit<Definition<Body, Request>, "path">) => Definition<Body, Request>;
|
|
26
26
|
export declare const merge: <Body, Request = LLMRequest>(base: Definition<Body, Request>, patch: EndpointPatch<Body, Request>) => Definition<Body, Request>;
|
|
27
|
+
export declare const trimBaseUrl: (value: string) => string;
|
|
27
28
|
export declare const render: <Body, Request = LLMRequest>(endpoint: Definition<Body, Request>, input: EndpointInput<Body, Request>) => URL;
|
|
28
29
|
export * as Endpoint from "./endpoint.js";
|
package/dist/route/endpoint.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as ProviderShared from "../protocols/shared.js";
|
|
2
1
|
/** Construct an `Endpoint` from a path string or path function. */
|
|
3
2
|
export const path = (value, options = {}) => ({
|
|
4
3
|
...options,
|
|
@@ -11,9 +10,10 @@ export const merge = (base, patch) => ({
|
|
|
11
10
|
path: patch.path ?? base.path,
|
|
12
11
|
query: patch.query === undefined ? base.query : { ...base.query, ...patch.query },
|
|
13
12
|
});
|
|
13
|
+
export const trimBaseUrl = (value) => value.replace(/\/+$/, "");
|
|
14
14
|
const renderPart = (part, input) => typeof part === "function" ? part(input) : part;
|
|
15
15
|
export const render = (endpoint, input) => {
|
|
16
|
-
const url = new URL(`${
|
|
16
|
+
const url = new URL(`${trimBaseUrl(endpoint.baseURL ?? "")}${renderPart(endpoint.path, input)}`);
|
|
17
17
|
for (const [key, value] of Object.entries(endpoint.query ?? {}))
|
|
18
18
|
url.searchParams.set(key, value);
|
|
19
19
|
return url;
|
|
@@ -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/framing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { Stream } from "effect";
|
|
2
|
+
import { AIError } from "../schema/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Decode a streaming HTTP response body into provider-protocol frames.
|
|
5
5
|
*
|
|
@@ -10,6 +10,8 @@ import type { AIError } from "../schema/index.js";
|
|
|
10
10
|
* `[DONE]`; protocols that use it as a terminal select `sseWithDone`.
|
|
11
11
|
* - AWS event stream — length-prefixed binary frames with CRC checksums.
|
|
12
12
|
* Each emitted frame is one parsed binary event record.
|
|
13
|
+
* - Media streams — newline-delimited JSON (`lines`) or the whole body as one
|
|
14
|
+
* frame (`document`); chunked binary bodies need no framing.
|
|
13
15
|
*
|
|
14
16
|
* The frame type is opaque to this layer; the protocol's event schema decodes
|
|
15
17
|
* each frame before its state machine handles it.
|
|
@@ -20,10 +22,21 @@ export interface Definition<Frame> {
|
|
|
20
22
|
/** Original wire representation when framing transforms the provider payload. */
|
|
21
23
|
readonly body?: (frame: Frame) => string | undefined;
|
|
22
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* `framing` step for Server-Sent Events. Decodes UTF-8, runs the SSE channel
|
|
27
|
+
* decoder, optionally filters named events, and drops empty events and known
|
|
28
|
+
* keepalives that proxies send as data. `[DONE]` is dropped by default or
|
|
29
|
+
* retained for protocols that use it as their stream boundary. Retry control events are ignored without
|
|
30
|
+
* interrupting the stream. Decoder failures become provider output errors so
|
|
31
|
+
* the public error channel stays `AIError`.
|
|
32
|
+
*/
|
|
33
|
+
export declare const sseFraming: (bytes: Stream.Stream<Uint8Array, AIError>, events?: ReadonlySet<string>, includeDone?: boolean) => Stream.Stream<string, AIError>;
|
|
23
34
|
/** Server-Sent Events framing. Used by every JSON-streaming HTTP provider. */
|
|
24
35
|
export declare const sse: Definition<string>;
|
|
25
36
|
/** Server-Sent Events framing that retains the conventional `[DONE]` sentinel. */
|
|
26
37
|
export declare const sseWithDone: Definition<string>;
|
|
27
38
|
/** SSE framing restricted to protocol-recognized event names. */
|
|
28
39
|
export declare const sseEvents: (events: ReadonlySet<string>) => Definition<string>;
|
|
40
|
+
export declare const lines: Definition<string>;
|
|
41
|
+
export declare const document: Definition<string>;
|
|
29
42
|
export * as Framing from "./framing.js";
|
package/dist/route/framing.js
CHANGED
|
@@ -1,14 +1,63 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import { makeParser } from "effect/unstable/encoding/Sse";
|
|
3
|
+
import { AIError, InvalidProviderOutputError } from "../schema/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* `framing` step for Server-Sent Events. Decodes UTF-8, runs the SSE channel
|
|
6
|
+
* decoder, optionally filters named events, and drops empty events and known
|
|
7
|
+
* keepalives that proxies send as data. `[DONE]` is dropped by default or
|
|
8
|
+
* retained for protocols that use it as their stream boundary. Retry control events are ignored without
|
|
9
|
+
* interrupting the stream. Decoder failures become provider output errors so
|
|
10
|
+
* the public error channel stays `AIError`.
|
|
11
|
+
*/
|
|
12
|
+
export const sseFraming = (bytes, events, includeDone = false) => bytes.pipe(Stream.decodeText(), Stream.mapAccumEffect(() => {
|
|
13
|
+
const output = [];
|
|
14
|
+
return {
|
|
15
|
+
output,
|
|
16
|
+
parser: makeParser((event) => {
|
|
17
|
+
if (event._tag === "Event")
|
|
18
|
+
output.push(event);
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
}, (state, chunk) => Effect.gen(function* () {
|
|
22
|
+
const error = state.parser.feed(chunk);
|
|
23
|
+
if (error)
|
|
24
|
+
return yield* new AIError({
|
|
25
|
+
reason: new InvalidProviderOutputError({
|
|
26
|
+
route: "sse",
|
|
27
|
+
message: error.message,
|
|
28
|
+
body: chunk,
|
|
29
|
+
cause: error,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
return [state, state.output.splice(0)];
|
|
33
|
+
})), Stream.filter((event) => (events === undefined || events.has(event.event)) &&
|
|
34
|
+
event.data.length > 0 &&
|
|
35
|
+
// Some OpenAI-compatible proxies serialize an empty flush as a bare
|
|
36
|
+
// `data: null`, between events or after `[DONE]`. No protocol has a
|
|
37
|
+
// null event, so it carries nothing and must not abort the stream.
|
|
38
|
+
event.data !== "null" &&
|
|
39
|
+
// Vertex AI partner models (e.g. `xai/grok-4.6`) send their SSE
|
|
40
|
+
// keepalive comment as `data: : keepalive` while reasoning.
|
|
41
|
+
event.data !== ": keepalive" &&
|
|
42
|
+
(event.data !== "[DONE]" || includeDone || (events !== undefined && event.event !== "message"))), Stream.map((event) => event.data));
|
|
2
43
|
/** Server-Sent Events framing. Used by every JSON-streaming HTTP provider. */
|
|
3
|
-
export const sse = { id: "sse", frame:
|
|
44
|
+
export const sse = { id: "sse", frame: sseFraming };
|
|
4
45
|
/** Server-Sent Events framing that retains the conventional `[DONE]` sentinel. */
|
|
5
46
|
export const sseWithDone = {
|
|
6
47
|
id: "sse",
|
|
7
|
-
frame: (bytes) =>
|
|
48
|
+
frame: (bytes) => sseFraming(bytes, undefined, true),
|
|
8
49
|
};
|
|
9
50
|
/** SSE framing restricted to protocol-recognized event names. */
|
|
10
51
|
export const sseEvents = (events) => ({
|
|
11
52
|
id: "sse",
|
|
12
|
-
frame: (bytes) =>
|
|
53
|
+
frame: (bytes) => sseFraming(bytes, events),
|
|
13
54
|
});
|
|
55
|
+
export const lines = {
|
|
56
|
+
id: "lines",
|
|
57
|
+
frame: (bytes) => bytes.pipe(Stream.decodeText(), Stream.splitLines, Stream.filter((line) => line.trim().length > 0)),
|
|
58
|
+
};
|
|
59
|
+
export const document = {
|
|
60
|
+
id: "document",
|
|
61
|
+
frame: (bytes) => Stream.fromEffect(Stream.mkString(bytes.pipe(Stream.decodeText()))),
|
|
62
|
+
};
|
|
14
63
|
export * as Framing from "./framing.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";
|
|
@@ -1,15 +1,31 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect";
|
|
1
|
+
import { Duration, Effect, Schema, type Stream } from "effect";
|
|
2
2
|
import { HttpClientResponse } from "effect/unstable/http";
|
|
3
|
-
import {
|
|
3
|
+
import type { Snapshot, Status } from "../generation.js";
|
|
4
|
+
import { Media } from "../media.js";
|
|
5
|
+
import type { AuthInput } from "./auth.js";
|
|
6
|
+
import { AIError, HttpContext, ProviderID } from "../schema/index.js";
|
|
7
|
+
/** Array values become repeated parameters (`keyterm=a&keyterm=b`). */
|
|
8
|
+
export type Query = Readonly<Record<string, string | ReadonlyArray<string>>>;
|
|
9
|
+
/** `query` is appended to the endpoint URL before the route and caller `http.query` overlays. */
|
|
4
10
|
export type Body = {
|
|
5
11
|
readonly type: "json";
|
|
6
12
|
readonly value: Record<string, unknown>;
|
|
13
|
+
readonly query?: Query;
|
|
7
14
|
} | {
|
|
8
15
|
readonly type: "multipart";
|
|
9
16
|
readonly value: FormData;
|
|
17
|
+
} | {
|
|
18
|
+
readonly type: "binary";
|
|
19
|
+
readonly value: Uint8Array;
|
|
20
|
+
readonly contentType: string;
|
|
21
|
+
readonly query?: Query;
|
|
10
22
|
};
|
|
11
|
-
export declare const json: (value: Record<string, unknown
|
|
23
|
+
export declare const json: (value: Record<string, unknown>, query?: Query) => Body;
|
|
12
24
|
export declare const multipart: (value: FormData) => Body;
|
|
25
|
+
export declare const binary: (value: Uint8Array, contentType: string, query?: Query) => Body;
|
|
26
|
+
export type Send = (path: string, body: Body) => Effect.Effect<HttpClientResponse.HttpClientResponse, AIError>;
|
|
27
|
+
/** Runs after unsupported-field rejection and before `body.from`, for providers that need an upload first. */
|
|
28
|
+
export type Prepare<Request> = (request: Request, send: Send) => Effect.Effect<Request, AIError>;
|
|
13
29
|
export interface DecodeContext<Request> {
|
|
14
30
|
readonly request: Request;
|
|
15
31
|
readonly body: Body;
|
|
@@ -18,7 +34,7 @@ export interface DecodeContext<Request> {
|
|
|
18
34
|
export interface Inline<Request, Response> {
|
|
19
35
|
readonly kind: "inline";
|
|
20
36
|
readonly id: string;
|
|
21
|
-
readonly
|
|
37
|
+
readonly provider: ProviderID;
|
|
22
38
|
/** Common request fields this protocol cannot lower; the route rejects them before `body.from` runs. */
|
|
23
39
|
readonly unsupported?: ReadonlyArray<keyof Request & string>;
|
|
24
40
|
readonly body: {
|
|
@@ -28,18 +44,129 @@ export interface Inline<Request, Response> {
|
|
|
28
44
|
readonly decode: (response: HttpClientResponse.HttpClientResponse, context: DecodeContext<Request>) => Effect.Effect<Response, AIError>;
|
|
29
45
|
};
|
|
30
46
|
}
|
|
31
|
-
export declare const inline: <Request, Response>(input: Omit<Inline<Request, Response>, "kind">) => Inline<Request, Response>;
|
|
32
|
-
/**
|
|
33
|
-
export
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
export declare const inline: <Request, Response>(route: Identity, input: Omit<Inline<Request, Response>, "kind" | "id" | "provider">) => Inline<Request, Response>;
|
|
48
|
+
/** What `start` learned from the submission response: the route-owned handle plus the first observation. */
|
|
49
|
+
export interface Started<Token> {
|
|
50
|
+
readonly token: Token;
|
|
51
|
+
readonly snapshot: Snapshot;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A follow-up call's inputs: the decoded token and the auth headers the route sent, so a protocol can attach them
|
|
55
|
+
* to output URLs that require the same credentials to download (Veo). `materialize` downloads an output through the
|
|
56
|
+
* route's executor, for URLs that expire too soon to hand back (BFL).
|
|
57
|
+
*/
|
|
58
|
+
export interface PollContext<Token> {
|
|
59
|
+
readonly token: Token;
|
|
60
|
+
readonly auth: Record<string, string>;
|
|
61
|
+
readonly materialize: (asset: Media.Asset) => Effect.Effect<Media.Asset, AIError>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Submit, then poll. `start` posts the body to the route endpoint; `status`, `result`, and `cancel` are follow-up
|
|
65
|
+
* calls addressed by the token. Paths are relative to the route base URL unless the provider hands back absolute
|
|
66
|
+
* URLs (fal `status_url`), in which case they are used verbatim. `result` is always its own GET: providers that
|
|
67
|
+
* return the output inside the status body (Veo, xAI, Runway) point `result.path` at the status path and decode the
|
|
68
|
+
* same document, so `Generation.await` and `Video.resume(...).await()` behave identically everywhere.
|
|
69
|
+
*/
|
|
70
|
+
export interface Queued<Request, Response, Token> {
|
|
71
|
+
readonly kind: "queued";
|
|
72
|
+
readonly id: string;
|
|
73
|
+
readonly provider: ProviderID;
|
|
74
|
+
/** Common request fields this protocol cannot lower; the route rejects them before `start.body.from` runs. */
|
|
75
|
+
readonly unsupported?: ReadonlyArray<keyof Request & string>;
|
|
76
|
+
/** Serializable handle. `Generation.token` carries the encoded form so it can be persisted and resumed elsewhere. */
|
|
77
|
+
readonly token: Schema.Codec<Token, unknown>;
|
|
78
|
+
readonly start: {
|
|
79
|
+
readonly prepare?: Prepare<Request>;
|
|
80
|
+
readonly body: {
|
|
81
|
+
readonly from: (request: Request) => Effect.Effect<Body, AIError>;
|
|
82
|
+
};
|
|
83
|
+
readonly decode: (response: HttpClientResponse.HttpClientResponse, context: DecodeContext<Request>) => Effect.Effect<Started<Token>, AIError>;
|
|
84
|
+
};
|
|
85
|
+
readonly status: {
|
|
86
|
+
readonly path: (token: Token) => string;
|
|
87
|
+
readonly decode: (response: HttpClientResponse.HttpClientResponse, context: PollContext<Token>) => Effect.Effect<Snapshot, AIError>;
|
|
88
|
+
};
|
|
89
|
+
readonly result: {
|
|
90
|
+
readonly path: (token: Token) => string;
|
|
91
|
+
readonly decode: (response: HttpClientResponse.HttpClientResponse, context: PollContext<Token>) => Effect.Effect<Response, AIError>;
|
|
92
|
+
};
|
|
93
|
+
readonly cancel?: {
|
|
94
|
+
readonly method: AuthInput["method"];
|
|
95
|
+
readonly path: (token: Token) => string;
|
|
96
|
+
/**
|
|
97
|
+
* Fetch a fresh status first and skip the call for terminal generations, for providers whose cancel endpoint
|
|
98
|
+
* destroys finished work (Runway's `DELETE /v1/tasks/{id}` deletes completed tasks and their outputs).
|
|
99
|
+
*/
|
|
100
|
+
readonly activeOnly?: boolean;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export declare const queued: <Request, Response, Token>(route: Identity, input: Omit<Queued<Request, Response, Token>, "kind" | "id" | "provider">) => Queued<Request, Response, Token>;
|
|
104
|
+
export type Mode = "generate" | "stream";
|
|
105
|
+
export type Addressed<Request> = Request & {
|
|
106
|
+
readonly mode: Mode;
|
|
107
|
+
};
|
|
108
|
+
export interface ResponseContext<Request> extends DecodeContext<Addressed<Request>> {
|
|
109
|
+
readonly http: HttpContext;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* One request whose body is parsed incrementally, like LLM protocols: `frames` → `step`* → `finish`. `generate` and
|
|
113
|
+
* `stream` share this state machine; `request.mode` lets a protocol pick a different body, path, or framing.
|
|
114
|
+
*/
|
|
115
|
+
export interface Streamed<Request, Event, Frame, State> {
|
|
116
|
+
readonly kind: "stream";
|
|
117
|
+
readonly id: string;
|
|
118
|
+
readonly provider: ProviderID;
|
|
119
|
+
/** Common request fields this protocol cannot lower; the route rejects them before `body.from` runs. */
|
|
120
|
+
readonly unsupported?: ReadonlyArray<keyof Request & string>;
|
|
121
|
+
readonly body: {
|
|
122
|
+
readonly from: (request: Addressed<Request>) => Effect.Effect<Body, AIError>;
|
|
123
|
+
};
|
|
124
|
+
readonly frames: (bytes: Stream.Stream<Uint8Array, AIError>, context: DecodeContext<Addressed<Request>>) => Stream.Stream<Frame, AIError>;
|
|
125
|
+
readonly initial: () => State;
|
|
126
|
+
readonly step: (state: State, frame: Frame) => Effect.Effect<readonly [State, ReadonlyArray<Event>], AIError>;
|
|
127
|
+
/** Emit exactly one terminal event, or fail when the provider stopped before completing. */
|
|
128
|
+
readonly finish: (state: State, context: ResponseContext<Request>) => Effect.Effect<ReadonlyArray<Event>, AIError>;
|
|
129
|
+
}
|
|
130
|
+
export declare const stream: <Request, Event, Frame, State>(route: Identity, input: Omit<Streamed<Request, Event, Frame, State>, "kind" | "id" | "provider">) => Streamed<Request, Event, Frame, State>;
|
|
131
|
+
/** One protocol's route id, display name, and provider, with the decoders and errors that carry them. */
|
|
132
|
+
export declare const identity: (input: {
|
|
133
|
+
readonly id: string;
|
|
134
|
+
readonly name: string;
|
|
135
|
+
readonly provider: string;
|
|
136
|
+
}) => {
|
|
137
|
+
id: string;
|
|
138
|
+
name: string;
|
|
139
|
+
provider: string & import("effect/Brand").Brand<"AI.ProviderID">;
|
|
140
|
+
text: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect<{
|
|
141
|
+
body: string;
|
|
142
|
+
http: HttpContext;
|
|
143
|
+
invalid: (message: string, cause?: unknown) => AIError;
|
|
144
|
+
ended: (status: Exclude<Status, "queued" | "running" | "completed">, message: string) => AIError;
|
|
145
|
+
pending: (id: string) => AIError;
|
|
146
|
+
contentPolicy: (message: string) => AIError;
|
|
147
|
+
}, AIError, never>;
|
|
148
|
+
decodeJson: <A>(schema: Schema.Codec<A, unknown>) => (response: HttpClientResponse.HttpClientResponse) => Effect.Effect<{
|
|
149
|
+
value: A;
|
|
150
|
+
body: string;
|
|
151
|
+
http: HttpContext;
|
|
152
|
+
invalid: (message: string, cause?: unknown) => AIError;
|
|
153
|
+
ended: (status: Exclude<Status, "queued" | "running" | "completed">, message: string) => AIError;
|
|
154
|
+
pending: (id: string) => AIError;
|
|
155
|
+
contentPolicy: (message: string) => AIError;
|
|
156
|
+
}, AIError, never>;
|
|
157
|
+
/** Decode a submission response into the token and first snapshot. */
|
|
158
|
+
decodeStarted: <A, Token>(schema: Schema.Codec<A, unknown>, started: (value: A) => Started<Token>) => (response: HttpClientResponse.HttpClientResponse) => Effect.Effect<Started<Token>, AIError, never>;
|
|
159
|
+
/** Schema-decode one JSON stream frame. Decode failures keep the frame as `reason.body`. */
|
|
160
|
+
decodeFrame: <A>(schema: Schema.Codec<A, unknown>) => (frame: string) => Effect.Effect<A, AIError, never>;
|
|
161
|
+
/** A stream-time failure; the frame stays on `reason.body`. */
|
|
162
|
+
frameError: (message: string, body?: string, cause?: unknown) => AIError;
|
|
163
|
+
incomplete: () => AIError;
|
|
164
|
+
unsupported: (operation: string, message: string) => AIError;
|
|
165
|
+
};
|
|
166
|
+
export type Identity = ReturnType<typeof identity>;
|
|
167
|
+
export type Output = Effect.Success<ReturnType<Identity["text"]>>;
|
|
168
|
+
/** Map a provider status string through the protocol's table; unknown values are an invalid provider document. */
|
|
169
|
+
export declare const status: <Table extends Record<string, Status>>(table: Table, raw: string, output: Output) => Effect.Effect<Status, AIError>;
|
|
170
|
+
/** A `url` asset whose provider-declared retention window starts now. */
|
|
171
|
+
export declare const expiringUrl: (url: string, retention: Duration.Duration, options?: Parameters<typeof Media.url>[1]) => Effect.Effect<Media.Asset, never, never>;
|
|
45
172
|
export * as MediaProtocol from "./media-protocol.js";
|