@opencode-ai/ai 0.0.0-next-16670 → 0.0.0-next-16676
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 +1 -1
- package/dist/image-client.d.ts +4 -4
- package/dist/image.d.ts +4 -4
- package/dist/image.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/llm.d.ts +11 -11
- package/dist/llm.js +3 -3
- package/dist/protocols/anthropic-messages.js +8 -4
- package/dist/protocols/bedrock-converse.js +3 -5
- package/dist/protocols/google-images.js +2 -2
- package/dist/protocols/open-responses.d.ts +8 -8
- package/dist/protocols/open-responses.js +4 -9
- package/dist/protocols/openai-chat.d.ts +4 -4
- package/dist/protocols/openai-chat.js +3 -3
- package/dist/protocols/openai-compatible-chat.d.ts +2 -2
- package/dist/protocols/openai-compatible-responses.d.ts +2 -2
- package/dist/protocols/openai-images.js +2 -2
- package/dist/protocols/shared.d.ts +16 -16
- package/dist/protocols/shared.js +6 -6
- package/dist/protocols/utils/bedrock-media.d.ts +1 -1
- package/dist/protocols/utils/image-input.d.ts +5 -5
- package/dist/protocols/utils/image-input.js +2 -2
- package/dist/protocols/utils/tool-schema.d.ts +2 -2
- package/dist/protocols/utils/tool-stream.d.ts +7 -7
- package/dist/protocols/utils/tool-stream.js +2 -2
- package/dist/protocols/xai-images.js +2 -2
- package/dist/protocols/zai-images.js +2 -2
- package/dist/provider-error.d.ts +2 -2
- package/dist/provider-error.js +2 -2
- package/dist/provider-package.d.ts +2 -2
- package/dist/provider.d.ts +8 -8
- package/dist/providers/amazon-bedrock.d.ts +7 -7
- package/dist/providers/anthropic-compatible.d.ts +6 -6
- package/dist/providers/anthropic.d.ts +7 -7
- package/dist/providers/azure.d.ts +13 -13
- package/dist/providers/cloudflare.d.ts +8 -8
- package/dist/providers/github-copilot.d.ts +15 -15
- package/dist/providers/google-vertex-chat.d.ts +6 -6
- package/dist/providers/google-vertex-messages.d.ts +6 -6
- package/dist/providers/google-vertex-responses.d.ts +6 -6
- package/dist/providers/google-vertex.d.ts +6 -6
- package/dist/providers/google.d.ts +7 -7
- package/dist/providers/openai-compatible-responses.d.ts +6 -6
- package/dist/providers/openai-compatible.d.ts +20 -20
- package/dist/providers/openai.d.ts +19 -19
- package/dist/providers/openrouter.d.ts +11 -11
- package/dist/providers/xai.d.ts +19 -19
- package/dist/providers/zai.d.ts +4 -4
- package/dist/route/auth-options.d.ts +3 -3
- package/dist/route/auth.d.ts +4 -4
- package/dist/route/auth.js +4 -4
- package/dist/route/client.d.ts +18 -18
- package/dist/route/client.js +6 -6
- package/dist/route/executor.d.ts +3 -3
- package/dist/route/executor.js +4 -4
- package/dist/route/framing.d.ts +2 -2
- package/dist/route/index.d.ts +1 -1
- package/dist/route/protocol.d.ts +3 -3
- package/dist/route/transport/http.d.ts +1 -1
- package/dist/route/transport/index.d.ts +3 -3
- package/dist/route/transport/websocket.d.ts +10 -10
- package/dist/route/transport/websocket.js +3 -3
- package/dist/schema/errors.d.ts +6 -6
- package/dist/schema/errors.js +18 -18
- package/dist/schema/events.js +1 -1
- package/dist/schema/ids.d.ts +3 -3
- package/dist/schema/ids.js +4 -3
- package/dist/schema/messages.d.ts +2 -2
- package/dist/schema/messages.js +2 -2
- package/dist/schema/options.d.ts +38 -38
- package/dist/schema/options.js +31 -29
- package/dist/testing.d.ts +4 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -195,7 +195,7 @@ The hosted result is represented as a provider-executed tool call and tool resul
|
|
|
195
195
|
- **`LLM.request({...})`** — build a provider-neutral `LLMRequest`. Accepts ergonomic inputs (`system: string`, `prompt: string`) that normalize into the canonical Schema classes.
|
|
196
196
|
- **`LLM.generate` / `LLM.stream`** — re-exported from `LLMClient` for one-import use.
|
|
197
197
|
- **`Message.user(...)` / `Message.assistant(...)` / `Message.tool(...)`** — message constructors from the canonical schema model.
|
|
198
|
-
- **`
|
|
198
|
+
- **`LanguageModel.make(...)` / `ToolCallPart.make(...)` / `ToolResultPart.make(...)` / `ToolDefinition.make(...)`** — model and tool-related constructors from the canonical schema model.
|
|
199
199
|
- **`LLMEvent.is.*`** — typed guards (`is.textDelta`, `is.toolCall`, `is.finish`, …) for filtering streams.
|
|
200
200
|
- **`Image.generate({...})`** — generate images through a provider-neutral image request and response model.
|
|
201
201
|
- **`ImageClient`** — Effect service and layer for image execution, parallel to `LLMClient`.
|
package/dist/image-client.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from "effect";
|
|
2
2
|
import { RequestExecutor } from "./route/executor";
|
|
3
3
|
import type { ImageOptions, ImageRequestFor, ImageResponse } from "./image";
|
|
4
|
-
import type {
|
|
4
|
+
import type { AIError } from "./schema";
|
|
5
5
|
export type Execute = RequestExecutor.Interface["execute"];
|
|
6
6
|
export interface Interface {
|
|
7
|
-
readonly generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<ImageResponse,
|
|
7
|
+
readonly generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<ImageResponse, AIError>;
|
|
8
8
|
}
|
|
9
9
|
declare const Service_base: Context.ServiceClass<Service, "@opencode/ImageClient", Interface>;
|
|
10
10
|
export declare class Service extends Service_base {
|
|
11
11
|
}
|
|
12
|
-
export declare const generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<ImageResponse,
|
|
12
|
+
export declare const generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<ImageResponse, AIError>;
|
|
13
13
|
export declare const layer: Layer.Layer<Service, never, RequestExecutor.Service>;
|
|
14
14
|
export declare const ImageClient: {
|
|
15
15
|
readonly Service: typeof Service;
|
|
16
16
|
readonly layer: Layer.Layer<Service, never, RequestExecutor.Service>;
|
|
17
|
-
readonly generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<ImageResponse,
|
|
17
|
+
readonly generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<ImageResponse, AIError>;
|
|
18
18
|
};
|
|
19
19
|
export {};
|
package/dist/image.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
|
-
import { HttpOptions,
|
|
2
|
+
import { HttpOptions, AIError, ModelID, ProviderID, Usage } from "./schema";
|
|
3
3
|
import { Service, type Execute as ImageExecute } from "./image-client";
|
|
4
4
|
export interface ImageRoute<Options extends ImageOptions = ImageOptions> {
|
|
5
5
|
readonly id: string;
|
|
6
|
-
readonly generate: (request: ImageRequestFor<Options>, execute: ImageExecute) => Effect.Effect<ImageResponse,
|
|
6
|
+
readonly generate: (request: ImageRequestFor<Options>, execute: ImageExecute) => Effect.Effect<ImageResponse, AIError>;
|
|
7
7
|
}
|
|
8
8
|
export type ImageOptions = Record<string, unknown>;
|
|
9
9
|
export declare class ImageModel<Options extends ImageOptions = ImageOptions> {
|
|
@@ -101,8 +101,8 @@ export declare class ImageResponse extends ImageResponse_base {
|
|
|
101
101
|
}
|
|
102
102
|
export declare function request<const Model extends object>(input: ImageRequestInput<Model>): ImageRequestFor<ImageModelOptions<Model>>;
|
|
103
103
|
export declare function request(input: ImageRequest): ImageRequest;
|
|
104
|
-
export declare function generate<const Model extends object>(input: ImageRequestInput<Model>): Effect.Effect<ImageResponse,
|
|
105
|
-
export declare function generate(input: ImageRequest): Effect.Effect<ImageResponse,
|
|
104
|
+
export declare function generate<const Model extends object>(input: ImageRequestInput<Model>): Effect.Effect<ImageResponse, AIError, Service>;
|
|
105
|
+
export declare function generate(input: ImageRequest): Effect.Effect<ImageResponse, AIError, Service>;
|
|
106
106
|
export declare const Image: {
|
|
107
107
|
readonly request: typeof request;
|
|
108
108
|
readonly generate: typeof generate;
|
package/dist/image.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
|
-
import { HttpOptions, InvalidRequestReason,
|
|
2
|
+
import { HttpOptions, InvalidRequestReason, AIError, ModelID, ProviderID, ProviderMetadata, Usage } from "./schema";
|
|
3
3
|
import { ImageClient, Service } from "./image-client";
|
|
4
4
|
export class ImageModel {
|
|
5
5
|
id;
|
|
@@ -89,7 +89,7 @@ export function request(input) {
|
|
|
89
89
|
export function generate(input) {
|
|
90
90
|
return Effect.try({
|
|
91
91
|
try: () => (input instanceof ImageRequest ? input : request(input)),
|
|
92
|
-
catch: (error) => new
|
|
92
|
+
catch: (error) => new AIError({
|
|
93
93
|
module: "Image",
|
|
94
94
|
method: "generate",
|
|
95
95
|
reason: new InvalidRequestReason({ message: error instanceof Error ? error.message : String(error) }),
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { Auth } from "./route/auth";
|
|
|
4
4
|
export { Provider } from "./provider";
|
|
5
5
|
export { ProviderPackage } from "./provider-package";
|
|
6
6
|
export { isContextOverflow, isContextOverflowFailure } from "./provider-error";
|
|
7
|
-
export type {
|
|
7
|
+
export type { RouteLanguageModelInput, RouteRoutedLanguageModelInput, Interface as LLMClientShape, Service as LLMClientService, } from "./route/client";
|
|
8
8
|
export * from "./schema";
|
|
9
9
|
export { GeneratedImage, ImageInput, ImageInputSchema, ImageModel, ImageRequest, ImageResponse } from "./image";
|
|
10
10
|
export type { ImageModelOptions, ImageOptions, ImageRequestFor, ImageRequestInput, ImageRoute } from "./image";
|
|
@@ -14,5 +14,5 @@ export { ToolRuntime } from "./tool-runtime";
|
|
|
14
14
|
export type { DispatchResult as ToolDispatchResult, ToolSettlement } from "./tool-runtime";
|
|
15
15
|
export type { AnyExecutableTool, AnyTool, ExecutableTool, ExecutableTools, Definition as ToolShape, ToolExecute, ToolExecuteContext, ToolModelOutputInput, Tools, ToolSchema, ToolToModelOutput, } from "./tool";
|
|
16
16
|
export * as LLM from "./llm";
|
|
17
|
-
export type { Definition as ProviderDefinition,
|
|
17
|
+
export type { Definition as ProviderDefinition, LanguageModelFactory as ProviderLanguageModelFactory, LanguageModelOptions as ProviderLanguageModelOptions, } from "./provider";
|
|
18
18
|
export type { Definition as ProviderPackageDefinition, Settings as ProviderPackageSettings } from "./provider-package";
|
package/dist/llm.d.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { Effect, JsonSchema, Schema } from "effect";
|
|
2
|
-
import { GenerationOptions, HttpOptions,
|
|
2
|
+
import { GenerationOptions, HttpOptions, AIError, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, ToolDefinition, type ContentPart, type LanguageModelProviderOptions } from "./schema";
|
|
3
3
|
import { type ToolSchema } from "./tool";
|
|
4
4
|
/** Input accepted by `LLM.request`, normalized into the canonical `LLMRequest` class. */
|
|
5
|
-
export type RequestInput<
|
|
6
|
-
readonly model:
|
|
5
|
+
export type RequestInput<SelectedLanguageModel extends LanguageModel = LanguageModel> = Omit<ConstructorParameters<typeof LLMRequest>[0], "model" | "system" | "messages" | "tools" | "toolChoice" | "generation" | "http" | "providerOptions"> & {
|
|
6
|
+
readonly model: SelectedLanguageModel;
|
|
7
7
|
readonly system?: string | SystemPart | ReadonlyArray<SystemPart>;
|
|
8
8
|
readonly prompt?: string | ContentPart | ReadonlyArray<ContentPart>;
|
|
9
9
|
readonly messages?: ReadonlyArray<Message | Message.Input>;
|
|
10
10
|
readonly tools?: ReadonlyArray<ToolDefinition.Input>;
|
|
11
11
|
readonly toolChoice?: ToolChoice.Input;
|
|
12
12
|
readonly generation?: GenerationOptions.Input;
|
|
13
|
-
readonly providerOptions?: NoInfer<
|
|
13
|
+
readonly providerOptions?: NoInfer<LanguageModelProviderOptions<SelectedLanguageModel>>;
|
|
14
14
|
readonly http?: HttpOptions.Input;
|
|
15
15
|
};
|
|
16
16
|
export declare const generate: typeof import("./route/client").generate;
|
|
17
17
|
export declare const stream: typeof import("./route/client").stream;
|
|
18
|
-
export declare const request: <const
|
|
19
|
-
type GenerateObjectBase<
|
|
18
|
+
export declare const request: <const SelectedLanguageModel extends LanguageModel>(input: RequestInput<SelectedLanguageModel>) => LLMRequest;
|
|
19
|
+
type GenerateObjectBase<SelectedLanguageModel extends LanguageModel = LanguageModel> = Omit<RequestInput<SelectedLanguageModel>, "tools" | "toolChoice">;
|
|
20
20
|
export declare class GenerateObjectResponse<T> {
|
|
21
21
|
readonly object: T;
|
|
22
22
|
readonly response: LLMResponse;
|
|
@@ -205,10 +205,10 @@ export declare class GenerateObjectResponse<T> {
|
|
|
205
205
|
})[];
|
|
206
206
|
get usage(): import("./schema").Usage | undefined;
|
|
207
207
|
}
|
|
208
|
-
export interface GenerateObjectOptions<S extends ToolSchema<any>,
|
|
208
|
+
export interface GenerateObjectOptions<S extends ToolSchema<any>, SelectedLanguageModel extends LanguageModel = LanguageModel> extends GenerateObjectBase<SelectedLanguageModel> {
|
|
209
209
|
readonly schema: S;
|
|
210
210
|
}
|
|
211
|
-
export interface GenerateObjectDynamicOptions<
|
|
211
|
+
export interface GenerateObjectDynamicOptions<SelectedLanguageModel extends LanguageModel = LanguageModel> extends GenerateObjectBase<SelectedLanguageModel> {
|
|
212
212
|
/** Raw JSON Schema object describing the expected output shape. */
|
|
213
213
|
readonly jsonSchema: JsonSchema.JsonSchema;
|
|
214
214
|
}
|
|
@@ -220,10 +220,10 @@ export interface GenerateObjectDynamicOptions<SelectedModel extends Model = Mode
|
|
|
220
220
|
* Two input modes:
|
|
221
221
|
*
|
|
222
222
|
* 1. `schema: EffectSchema<T>` — `.object` is decoded and typed as `T`.
|
|
223
|
-
* Decode failures surface as `
|
|
223
|
+
* Decode failures surface as `AIError`.
|
|
224
224
|
* 2. `jsonSchema: JsonSchema.JsonSchema` — `.object` is `unknown`. Use when
|
|
225
225
|
* the schema is only available at runtime (MCP, plugin manifests). Caller validates.
|
|
226
226
|
*/
|
|
227
|
-
export declare function generateObject<const
|
|
228
|
-
export declare function generateObject<const
|
|
227
|
+
export declare function generateObject<const SelectedLanguageModel extends LanguageModel, S extends ToolSchema<any>>(options: GenerateObjectOptions<S, SelectedLanguageModel>): Effect.Effect<GenerateObjectResponse<Schema.Schema.Type<S>>, AIError>;
|
|
228
|
+
export declare function generateObject<const SelectedLanguageModel extends LanguageModel>(options: GenerateObjectDynamicOptions<SelectedLanguageModel>): Effect.Effect<GenerateObjectResponse<unknown>, AIError>;
|
|
229
229
|
export {};
|
package/dist/llm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, JsonSchema, Schema } from "effect";
|
|
2
2
|
import { LLMClient } from "./route/client";
|
|
3
|
-
import { GenerationOptions, HttpOptions, InvalidProviderOutputReason,
|
|
3
|
+
import { GenerationOptions, HttpOptions, InvalidProviderOutputReason, AIError, LLMEvent, LLMRequest, LLMResponse, Message, LanguageModel, SystemPart, ToolChoice, ToolDefinition, } from "./schema";
|
|
4
4
|
import { make as makeTool, toDefinitions } from "./tool";
|
|
5
5
|
export const generate = LLMClient.generate;
|
|
6
6
|
export const stream = LLMClient.stream;
|
|
@@ -42,14 +42,14 @@ const runGenerateObject = Effect.fn("LLM.generateObject")(function* (options, to
|
|
|
42
42
|
const response = yield* LLMClient.generate(generateRequest);
|
|
43
43
|
const call = response.toolCalls.find((event) => LLMEvent.is.toolCall(event) && event.name === GENERATE_OBJECT_TOOL_NAME);
|
|
44
44
|
if (!call || !LLMEvent.is.toolCall(call))
|
|
45
|
-
return yield* new
|
|
45
|
+
return yield* new AIError({
|
|
46
46
|
module: "LLM",
|
|
47
47
|
method: "generateObject",
|
|
48
48
|
reason: new InvalidProviderOutputReason({
|
|
49
49
|
message: `generateObject: model did not call the forced \`${GENERATE_OBJECT_TOOL_NAME}\` tool`,
|
|
50
50
|
}),
|
|
51
51
|
});
|
|
52
|
-
const object = yield* tool._decode(call.input).pipe(Effect.mapError((error) => new
|
|
52
|
+
const object = yield* tool._decode(call.input).pipe(Effect.mapError((error) => new AIError({
|
|
53
53
|
module: "LLM",
|
|
54
54
|
method: "generateObject",
|
|
55
55
|
reason: new InvalidProviderOutputReason({
|
|
@@ -5,7 +5,7 @@ import { Auth } from "../route/auth";
|
|
|
5
5
|
import { Endpoint } from "../route/endpoint";
|
|
6
6
|
import { Framing } from "../route/framing";
|
|
7
7
|
import { Protocol } from "../route/protocol";
|
|
8
|
-
import {
|
|
8
|
+
import { AIError, LLMEvent, mergeJsonRecords, Usage, } from "../schema";
|
|
9
9
|
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared";
|
|
10
10
|
import { classifyProviderFailure } from "../provider-error";
|
|
11
11
|
import * as Cache from "./utils/cache";
|
|
@@ -167,8 +167,12 @@ const AnthropicUsage = Schema.StructWithRest(Schema.Struct({
|
|
|
167
167
|
output_tokens: Schema.optional(Schema.Number),
|
|
168
168
|
cache_creation_input_tokens: optionalNull(Schema.Number),
|
|
169
169
|
cache_read_input_tokens: optionalNull(Schema.Number),
|
|
170
|
-
server_tool_use: optionalNull(Schema.StructWithRest(Schema.Struct({ web_search_requests: Schema.optional(Schema.Number) }), [
|
|
171
|
-
|
|
170
|
+
server_tool_use: optionalNull(Schema.StructWithRest(Schema.Struct({ web_search_requests: Schema.optional(Schema.Number) }), [
|
|
171
|
+
Schema.Record(Schema.String, Schema.Unknown),
|
|
172
|
+
])),
|
|
173
|
+
output_tokens_details: optionalNull(Schema.StructWithRest(Schema.Struct({ thinking_tokens: Schema.optional(Schema.Number) }), [
|
|
174
|
+
Schema.Record(Schema.String, Schema.Unknown),
|
|
175
|
+
])),
|
|
172
176
|
}), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
173
177
|
const AnthropicStreamBlock = Schema.Struct({
|
|
174
178
|
type: Schema.String,
|
|
@@ -793,7 +797,7 @@ const providerErrorMessage = (event) => {
|
|
|
793
797
|
return `${type}: ${message}`;
|
|
794
798
|
return message || type || "Anthropic Messages stream error";
|
|
795
799
|
};
|
|
796
|
-
const onError = (event) => new
|
|
800
|
+
const onError = (event) => new AIError({
|
|
797
801
|
module: ADAPTER,
|
|
798
802
|
method: "stream",
|
|
799
803
|
reason: classifyProviderFailure({ message: providerErrorMessage(event), code: event.error?.type }),
|
|
@@ -2,7 +2,7 @@ import { Effect, Schema } from "effect";
|
|
|
2
2
|
import { Route } from "../route/client";
|
|
3
3
|
import { Endpoint } from "../route/endpoint";
|
|
4
4
|
import { Protocol } from "../route/protocol";
|
|
5
|
-
import {
|
|
5
|
+
import { AIError, LLMEvent, Usage, } from "../schema";
|
|
6
6
|
import { BedrockEventStream } from "./bedrock-event-stream";
|
|
7
7
|
import { classifyProviderFailure } from "../provider-error";
|
|
8
8
|
import { JsonObject, optionalArray, ProviderShared } from "./shared";
|
|
@@ -193,9 +193,7 @@ const reasoningSignature = (part) => {
|
|
|
193
193
|
};
|
|
194
194
|
const reasoningRedactedData = (part) => {
|
|
195
195
|
const bedrock = part.providerMetadata?.bedrock;
|
|
196
|
-
return ProviderShared.isRecord(bedrock) && typeof bedrock.redactedData === "string"
|
|
197
|
-
? bedrock.redactedData
|
|
198
|
-
: undefined;
|
|
196
|
+
return ProviderShared.isRecord(bedrock) && typeof bedrock.redactedData === "string" ? bedrock.redactedData : undefined;
|
|
199
197
|
};
|
|
200
198
|
const lowerToolCall = (part) => ({
|
|
201
199
|
toolUse: {
|
|
@@ -509,7 +507,7 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
509
507
|
["validationException", event.validationException],
|
|
510
508
|
].find((entry) => entry[1] !== undefined);
|
|
511
509
|
if (exception) {
|
|
512
|
-
return yield* new
|
|
510
|
+
return yield* new AIError({
|
|
513
511
|
module: ADAPTER,
|
|
514
512
|
method: "stream",
|
|
515
513
|
reason: classifyProviderFailure({
|
|
@@ -2,7 +2,7 @@ import { Effect, Encoding, Schema } from "effect";
|
|
|
2
2
|
import { Headers, HttpClientRequest } from "effect/unstable/http";
|
|
3
3
|
import { GeneratedImage, ImageModel, ImageResponse, } from "../image";
|
|
4
4
|
import { Auth } from "../route/auth";
|
|
5
|
-
import { InvalidProviderOutputReason,
|
|
5
|
+
import { InvalidProviderOutputReason, AIError, Usage, mergeHttpOptions, mergeJsonRecords, } from "../schema";
|
|
6
6
|
import { ProviderShared } from "./shared";
|
|
7
7
|
import { ImageInputs } from "./utils/image-input";
|
|
8
8
|
const ADAPTER = "google-images";
|
|
@@ -58,7 +58,7 @@ const nativeOptions = (options) => {
|
|
|
58
58
|
thinkingConfig: Object.values(thinkingConfig).some((value) => value !== undefined) ? thinkingConfig : undefined,
|
|
59
59
|
}, native) ?? { responseModalities: ["IMAGE"] });
|
|
60
60
|
};
|
|
61
|
-
const invalidOutput = (message, providerMetadata) => new
|
|
61
|
+
const invalidOutput = (message, providerMetadata) => new AIError({
|
|
62
62
|
module: ADAPTER,
|
|
63
63
|
method: "generate",
|
|
64
64
|
reason: new InvalidProviderOutputReason({ message, route: ADAPTER, providerMetadata }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
2
|
import { HttpTransport } from "../route/transport";
|
|
3
3
|
import { Protocol } from "../route/protocol";
|
|
4
|
-
import {
|
|
4
|
+
import { AIError, LLMEvent, Usage, type LLMRequest, type MediaPart, type ProviderMetadata, type ToolDefinition } from "../schema";
|
|
5
5
|
import { ProviderShared } from "./shared";
|
|
6
6
|
import { Lifecycle } from "./utils/lifecycle";
|
|
7
7
|
import { ToolStream } from "./utils/tool-stream";
|
|
@@ -361,11 +361,11 @@ export declare const lowerTool: (protocolName: string, tool: ToolDefinition, inp
|
|
|
361
361
|
readonly [x: string]: unknown;
|
|
362
362
|
};
|
|
363
363
|
strict: boolean;
|
|
364
|
-
},
|
|
364
|
+
}, AIError, never>;
|
|
365
365
|
export declare const lowerToolChoice: (protocolName: string, toolChoice: NonNullable<LLMRequest["toolChoice"]>) => Effect.Effect<"required" | "none" | "auto" | {
|
|
366
366
|
type: "function";
|
|
367
367
|
name: string;
|
|
368
|
-
},
|
|
368
|
+
}, AIError, never>;
|
|
369
369
|
export declare const fromRequestWithExtension: (request: LLMRequest, extension: Extension) => Effect.Effect<{
|
|
370
370
|
service_tier?: "auto" | "default" | "flex" | "priority" | undefined;
|
|
371
371
|
text?: {
|
|
@@ -379,7 +379,7 @@ export declare const fromRequestWithExtension: (request: LLMRequest, extension:
|
|
|
379
379
|
prompt_cache_key?: string | undefined;
|
|
380
380
|
store?: boolean | undefined;
|
|
381
381
|
instructions?: string | undefined;
|
|
382
|
-
model: string & import("effect/Brand").Brand<"
|
|
382
|
+
model: string & import("effect/Brand").Brand<"AI.ModelID">;
|
|
383
383
|
input: LoweredInputItem[];
|
|
384
384
|
tools: {
|
|
385
385
|
type: "function";
|
|
@@ -398,7 +398,7 @@ export declare const fromRequestWithExtension: (request: LLMRequest, extension:
|
|
|
398
398
|
max_output_tokens: number | undefined;
|
|
399
399
|
temperature: number | undefined;
|
|
400
400
|
top_p: number | undefined;
|
|
401
|
-
},
|
|
401
|
+
}, AIError, never>;
|
|
402
402
|
export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
|
|
403
403
|
readonly input: readonly ({
|
|
404
404
|
readonly type: "reasoning";
|
|
@@ -486,13 +486,13 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
|
|
|
486
486
|
readonly service_tier?: "auto" | "default" | "flex" | "priority" | undefined;
|
|
487
487
|
readonly prompt_cache_key?: string | undefined;
|
|
488
488
|
readonly max_output_tokens?: number | undefined;
|
|
489
|
-
},
|
|
489
|
+
}, AIError, never>;
|
|
490
490
|
export declare const providerMetadata: (state: ParserState, metadata: Record<string, unknown>) => ProviderMetadata;
|
|
491
491
|
export type StepResult = readonly [ParserState, ReadonlyArray<LLMEvent>];
|
|
492
492
|
export declare const terminal: (event: Event) => boolean;
|
|
493
493
|
export declare const onReasoningDelta: (state: ParserState, event: Event, itemID: string) => StepResult;
|
|
494
494
|
export declare const onReasoningDone: (state: ParserState, _event: Event) => StepResult;
|
|
495
|
-
export declare const step: (state: ParserState, event: Event) =>
|
|
495
|
+
export declare const step: (state: ParserState, event: Event) => AIError | Effect.Effect<StepResult, never, never> | Effect.Effect<[ParserState, readonly ({
|
|
496
496
|
readonly type: "step-start";
|
|
497
497
|
readonly index: number;
|
|
498
498
|
} | {
|
|
@@ -673,7 +673,7 @@ export declare const step: (state: ParserState, event: Event) => LLMError | Effe
|
|
|
673
673
|
};
|
|
674
674
|
} | undefined;
|
|
675
675
|
readonly classification?: "context-overflow" | "payload-too-large" | undefined;
|
|
676
|
-
})[]],
|
|
676
|
+
})[]], AIError, never>;
|
|
677
677
|
/**
|
|
678
678
|
* The provider-neutral Open Responses protocol. Provider-specific Responses
|
|
679
679
|
* implementations compose this baseline with their own tools and event variants.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
2
|
import { HttpTransport } from "../route/transport";
|
|
3
3
|
import { Protocol } from "../route/protocol";
|
|
4
|
-
import {
|
|
4
|
+
import { AIError, LLMEvent, Usage, } from "../schema";
|
|
5
5
|
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared";
|
|
6
6
|
import { classifyProviderFailure } from "../provider-error";
|
|
7
7
|
import { OpenResponsesOptions } from "./utils/open-responses-options";
|
|
@@ -290,9 +290,7 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
|
|
|
290
290
|
return;
|
|
291
291
|
const groups = content.reduce((groups, part) => {
|
|
292
292
|
const metadata = part.providerMetadata?.[providerMetadataKey];
|
|
293
|
-
const phase = ProviderShared.isRecord(metadata)
|
|
294
|
-
? messagePhase(metadata.phase, extension)
|
|
295
|
-
: undefined;
|
|
293
|
+
const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase, extension) : undefined;
|
|
296
294
|
const group = groups.at(-1);
|
|
297
295
|
if (group && group.phase === phase)
|
|
298
296
|
group.parts.push(part);
|
|
@@ -481,10 +479,7 @@ const onOutputTextDelta = (state, event, id) => {
|
|
|
481
479
|
const phase = state.messagePhases[id];
|
|
482
480
|
const metadata = phase === undefined ? undefined : providerMetadata(state, { phase });
|
|
483
481
|
const lifecycle = Lifecycle.textStart(state.lifecycle, events, id, metadata);
|
|
484
|
-
return [
|
|
485
|
-
{ ...state, lifecycle: Lifecycle.textDelta(lifecycle, events, id, event.delta) },
|
|
486
|
-
events,
|
|
487
|
-
];
|
|
482
|
+
return [{ ...state, lifecycle: Lifecycle.textDelta(lifecycle, events, id, event.delta) }, events];
|
|
488
483
|
};
|
|
489
484
|
const onOutputTextDone = (state, event, id) => {
|
|
490
485
|
if (state.messageItems.has(id)) {
|
|
@@ -754,7 +749,7 @@ const providerErrorMessage = (event, fallback) => {
|
|
|
754
749
|
const providerError = (state, event, fallback) => {
|
|
755
750
|
const code = event.code || event.error?.code || event.response?.error?.code || undefined;
|
|
756
751
|
const message = providerErrorMessage(event, fallback);
|
|
757
|
-
return new
|
|
752
|
+
return new AIError({
|
|
758
753
|
module: state.id,
|
|
759
754
|
method: "stream",
|
|
760
755
|
reason: classifyProviderFailure({ message, code }),
|
|
@@ -2,7 +2,7 @@ import { Effect, Schema } from "effect";
|
|
|
2
2
|
import { Route } from "../route/client";
|
|
3
3
|
import { HttpTransport } from "../route/transport";
|
|
4
4
|
import { Protocol } from "../route/protocol";
|
|
5
|
-
import {
|
|
5
|
+
import { AIError, LLMEvent, Usage, type FinishReasonDetails, type CacheHint, type LLMRequest } from "../schema";
|
|
6
6
|
import { Lifecycle } from "./utils/lifecycle";
|
|
7
7
|
import { ToolStream } from "./utils/tool-stream";
|
|
8
8
|
export declare const DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
@@ -266,7 +266,7 @@ export declare const fromRequest: (request: LLMRequest, options?: LoweringOption
|
|
|
266
266
|
seed: number | undefined;
|
|
267
267
|
stop: readonly string[] | undefined;
|
|
268
268
|
max_completion_tokens: number | undefined;
|
|
269
|
-
model: string & import("effect/Brand").Brand<"
|
|
269
|
+
model: string & import("effect/Brand").Brand<"AI.ModelID">;
|
|
270
270
|
messages: ({
|
|
271
271
|
readonly role: "system";
|
|
272
272
|
readonly content: string | readonly ({
|
|
@@ -360,7 +360,7 @@ export declare const fromRequest: (request: LLMRequest, options?: LoweringOption
|
|
|
360
360
|
seed: number | undefined;
|
|
361
361
|
stop: readonly string[] | undefined;
|
|
362
362
|
max_tokens: number | undefined;
|
|
363
|
-
model: string & import("effect/Brand").Brand<"
|
|
363
|
+
model: string & import("effect/Brand").Brand<"AI.ModelID">;
|
|
364
364
|
messages: ({
|
|
365
365
|
readonly role: "system";
|
|
366
366
|
readonly content: string | readonly ({
|
|
@@ -444,7 +444,7 @@ export declare const fromRequest: (request: LLMRequest, options?: LoweringOption
|
|
|
444
444
|
stream_options: {
|
|
445
445
|
include_usage: boolean;
|
|
446
446
|
};
|
|
447
|
-
},
|
|
447
|
+
}, AIError, never>;
|
|
448
448
|
/**
|
|
449
449
|
* The OpenAI Chat protocol — request body construction, body schema, and the
|
|
450
450
|
* streaming-event state machine. Reused by every route that speaks OpenAI Chat
|
|
@@ -5,7 +5,7 @@ import { Auth } from "../route/auth";
|
|
|
5
5
|
import { Endpoint } from "../route/endpoint";
|
|
6
6
|
import { HttpTransport } from "../route/transport";
|
|
7
7
|
import { Protocol } from "../route/protocol";
|
|
8
|
-
import {
|
|
8
|
+
import { AIError, LLMEvent, Usage, } from "../schema";
|
|
9
9
|
import { classifyProviderFailure } from "../provider-error";
|
|
10
10
|
import { isRecord, JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared";
|
|
11
11
|
import { OpenAIOptions } from "./utils/openai-options";
|
|
@@ -444,7 +444,7 @@ const mapFinishReason = (reason) => {
|
|
|
444
444
|
// OpenAI Chat reports `prompt_tokens` (inclusive total) with a
|
|
445
445
|
// cached-read and cache-write subsets, and `completion_tokens` (inclusive
|
|
446
446
|
// total) with a `reasoning_tokens` subset. We pass the inclusive totals
|
|
447
|
-
// through and derive the non-cached breakdown so the `
|
|
447
|
+
// through and derive the non-cached breakdown so the `AI.Usage` contract is
|
|
448
448
|
// satisfied on both sides.
|
|
449
449
|
const mapUsage = (usage) => {
|
|
450
450
|
if (!usage)
|
|
@@ -524,7 +524,7 @@ const reasoningMetadata = (field, details) => ({
|
|
|
524
524
|
});
|
|
525
525
|
const step = (state, event) => Effect.gen(function* () {
|
|
526
526
|
if (event.error)
|
|
527
|
-
return yield* new
|
|
527
|
+
return yield* new AIError({
|
|
528
528
|
module: ADAPTER,
|
|
529
529
|
method: "stream",
|
|
530
530
|
reason: classifyProviderFailure({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Route, type
|
|
2
|
-
export type
|
|
1
|
+
import { Route, type RouteRoutedLanguageModelInput } from "../route/client";
|
|
2
|
+
export type OpenAICompatibleChatLanguageModelInput = RouteRoutedLanguageModelInput;
|
|
3
3
|
/**
|
|
4
4
|
* Route for non-OpenAI providers that expose an OpenAI Chat-compatible
|
|
5
5
|
* `/chat/completions` endpoint. Reuses `OpenAIChat.protocol` end-to-end and
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Route, type
|
|
2
|
-
export type
|
|
1
|
+
import { Route, type RouteRoutedLanguageModelInput } from "../route/client";
|
|
2
|
+
export type OpenAICompatibleResponsesLanguageModelInput = RouteRoutedLanguageModelInput;
|
|
3
3
|
/**
|
|
4
4
|
* Deployment adapter for providers that expose an Open Responses-compatible
|
|
5
5
|
* `/responses` endpoint. Provider helpers configure identity, endpoint, and
|
|
@@ -2,7 +2,7 @@ import { Effect, Encoding, Schema } from "effect";
|
|
|
2
2
|
import { Headers, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
|
|
3
3
|
import { ImageModel, GeneratedImage, ImageResponse, } from "../image";
|
|
4
4
|
import { Auth } from "../route/auth";
|
|
5
|
-
import { InvalidProviderOutputReason,
|
|
5
|
+
import { InvalidProviderOutputReason, AIError, Usage, mergeHttpOptions, mergeJsonRecords, } from "../schema";
|
|
6
6
|
import { ProviderShared } from "./shared";
|
|
7
7
|
import { ImageInputs } from "./utils/image-input";
|
|
8
8
|
import { OpenAIImage } from "./utils/openai-image";
|
|
@@ -35,7 +35,7 @@ const nativeOptions = (options) => {
|
|
|
35
35
|
...native,
|
|
36
36
|
};
|
|
37
37
|
};
|
|
38
|
-
const invalidOutput = (message) => new
|
|
38
|
+
const invalidOutput = (message) => new AIError({
|
|
39
39
|
module: ADAPTER,
|
|
40
40
|
method: "generate",
|
|
41
41
|
reason: new InvalidProviderOutputReason({ message, route: ADAPTER }),
|
|
@@ -2,7 +2,7 @@ import { Buffer } from "node:buffer";
|
|
|
2
2
|
import { Tool } from "@opencode-ai/schema/tool";
|
|
3
3
|
import { Effect, Schema, Stream } from "effect";
|
|
4
4
|
import { Headers, HttpClientRequest } from "effect/unstable/http";
|
|
5
|
-
import {
|
|
5
|
+
import { AIError, type ContentPart, type LLMRequest, type ToolResultPart } from "../schema";
|
|
6
6
|
import { isRecord } from "../utils/record";
|
|
7
7
|
export { isRecord };
|
|
8
8
|
export declare const Json: Schema.fromJsonString<Schema.Unknown>;
|
|
@@ -27,7 +27,7 @@ export interface ToolAccumulator {
|
|
|
27
27
|
* when at least one is defined. Returns `undefined` when neither input nor
|
|
28
28
|
* output is known so routes don't publish a misleading `0`.
|
|
29
29
|
*
|
|
30
|
-
* Under the additive `
|
|
30
|
+
* Under the additive `AI.Usage` contract, `inputTokens` and `outputTokens`
|
|
31
31
|
* are the non-cached input and visible output only. The provider-supplied
|
|
32
32
|
* `total` is the source of truth when present; the computed fallback
|
|
33
33
|
* under-counts cache and reasoning by design and exists mainly so
|
|
@@ -55,8 +55,8 @@ export declare const subtractTokens: (total: number | undefined, subtrahend: num
|
|
|
55
55
|
* (e.g. Anthropic, whose `input_tokens` is already non-cached only).
|
|
56
56
|
*/
|
|
57
57
|
export declare const sumTokens: (...values: ReadonlyArray<number | undefined>) => number | undefined;
|
|
58
|
-
export declare const eventError: (route: string, message: string, raw?: string) =>
|
|
59
|
-
export declare const parseJson: (route: string, input: string, message: string) => Effect.Effect<unknown,
|
|
58
|
+
export declare const eventError: (route: string, message: string, raw?: string) => AIError;
|
|
59
|
+
export declare const parseJson: (route: string, input: string, message: string) => Effect.Effect<unknown, AIError, never>;
|
|
60
60
|
/**
|
|
61
61
|
* Join the `text` field of a list of parts with newlines. Used by routes
|
|
62
62
|
* that flatten system / message content arrays into a single provider string
|
|
@@ -92,20 +92,20 @@ export declare const systemUpdateText: (route: string, message: import("..").Mes
|
|
|
92
92
|
readonly [x: string]: unknown;
|
|
93
93
|
};
|
|
94
94
|
} | undefined;
|
|
95
|
-
}[],
|
|
95
|
+
}[], AIError, never>;
|
|
96
96
|
/** Lower an unsupported privileged update into visible, in-order user text. */
|
|
97
97
|
export declare const wrappedSystemUpdate: (route: string, message: import("..").Message) => Effect.Effect<{
|
|
98
98
|
type: "text";
|
|
99
99
|
text: string;
|
|
100
100
|
cache: import("..").CacheHint | undefined;
|
|
101
|
-
},
|
|
101
|
+
}, AIError, never>;
|
|
102
102
|
/**
|
|
103
103
|
* Parse the streamed JSON input of a tool call. Treats an empty string as
|
|
104
104
|
* `"{}"` — providers occasionally finish a tool call without ever emitting
|
|
105
105
|
* input deltas (e.g. zero-arg tools). The error message is uniform across
|
|
106
106
|
* routes: `Invalid JSON input for <route> tool call <name>`.
|
|
107
107
|
*/
|
|
108
|
-
export declare const parseToolInput: (route: string, name: string, raw: string) => Effect.Effect<unknown,
|
|
108
|
+
export declare const parseToolInput: (route: string, name: string, raw: string) => Effect.Effect<unknown, AIError, never>;
|
|
109
109
|
export declare const IMAGE_MIMES: readonly ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
110
110
|
export declare const VIDEO_MIMES: readonly ["video/mp4", "video/webm", "video/quicktime"];
|
|
111
111
|
export declare const AUDIO_MIMES: readonly ["audio/wav", "audio/mp3", "audio/aiff", "audio/aac", "audio/ogg", "audio/flac"];
|
|
@@ -132,13 +132,13 @@ export declare const validateMedia: (route: string, part: {
|
|
|
132
132
|
base64: string;
|
|
133
133
|
dataUrl: string;
|
|
134
134
|
bytes: Buffer<ArrayBuffer>;
|
|
135
|
-
},
|
|
135
|
+
}, AIError, never>;
|
|
136
136
|
export declare const validateToolFile: (route: string, part: Tool.FileContent, supportedMimes: ReadonlySet<string>) => Effect.Effect<{
|
|
137
137
|
mime: string;
|
|
138
138
|
base64: string;
|
|
139
139
|
dataUrl: string;
|
|
140
140
|
bytes: Buffer<ArrayBuffer>;
|
|
141
|
-
},
|
|
141
|
+
}, AIError, never>;
|
|
142
142
|
export declare const trimBaseUrl: (value: string) => string;
|
|
143
143
|
export declare const toolResultText: (part: ToolResultPart) => string;
|
|
144
144
|
export declare const errorText: (error: unknown) => string;
|
|
@@ -148,9 +148,9 @@ export declare const errorText: (error: unknown) => string;
|
|
|
148
148
|
* `decodeChunk` sees one JSON string per element. The SSE channel emits a
|
|
149
149
|
* `Retry` control event on its error channel; we drop it here (we don't
|
|
150
150
|
* implement client-driven retries) so the public error channel stays
|
|
151
|
-
* `
|
|
151
|
+
* `AIError`.
|
|
152
152
|
*/
|
|
153
|
-
export declare const sseFraming: (bytes: Stream.Stream<Uint8Array,
|
|
153
|
+
export declare const sseFraming: (bytes: Stream.Stream<Uint8Array, AIError>) => Stream.Stream<string, AIError>;
|
|
154
154
|
/**
|
|
155
155
|
* Canonical invalid-request constructor. Lift one-line `const invalid =
|
|
156
156
|
* (message) => invalidRequest(message)` aliases out of every
|
|
@@ -158,27 +158,27 @@ export declare const sseFraming: (bytes: Stream.Stream<Uint8Array, LLMError>) =>
|
|
|
158
158
|
* `InvalidRequestReason` with route context or trace metadata, the change
|
|
159
159
|
* lands here.
|
|
160
160
|
*/
|
|
161
|
-
export declare const invalidRequest: (message: string) =>
|
|
161
|
+
export declare const invalidRequest: (message: string) => AIError;
|
|
162
162
|
export declare const matchToolChoice: <Auto, None, Required, Tool>(route: string, toolChoice: NonNullable<LLMRequest["toolChoice"]>, cases: {
|
|
163
163
|
readonly auto: () => Auto;
|
|
164
164
|
readonly none: () => None;
|
|
165
165
|
readonly required: () => Required;
|
|
166
166
|
readonly tool: (name: string) => Tool;
|
|
167
|
-
}) => Effect.Effect<Auto | None | Required | Tool,
|
|
167
|
+
}) => Effect.Effect<Auto | None | Required | Tool, AIError, never>;
|
|
168
168
|
type ContentType = ContentPart["type"];
|
|
169
169
|
export declare const supportsContent: <const Type extends ContentType>(part: ContentPart, types: ReadonlyArray<Type>) => part is Extract<ContentPart, {
|
|
170
170
|
readonly type: Type;
|
|
171
171
|
}>;
|
|
172
|
-
export declare const unsupportedContent: (route: string, role: LLMRequest["messages"][number]["role"], types: ReadonlyArray<ContentType>) =>
|
|
172
|
+
export declare const unsupportedContent: (route: string, role: LLMRequest["messages"][number]["role"], types: ReadonlyArray<ContentType>) => AIError;
|
|
173
173
|
/**
|
|
174
174
|
* Build a `validate` step from a Schema decoder. Replaces the per-route
|
|
175
175
|
* lambda body `(payload) => decode(payload).pipe(Effect.mapError((e) =>
|
|
176
176
|
* invalid(e.message)))`. Any decode error is translated into
|
|
177
|
-
* `
|
|
177
|
+
* `AIError` carrying the original parse-error message.
|
|
178
178
|
*/
|
|
179
179
|
export declare const validateWith: <A, I, E extends {
|
|
180
180
|
readonly message: string;
|
|
181
|
-
}>(decode: (input: I) => Effect.Effect<A, E>) => (payload: I) => Effect.Effect<A,
|
|
181
|
+
}>(decode: (input: I) => Effect.Effect<A, E>) => (payload: I) => Effect.Effect<A, AIError, never>;
|
|
182
182
|
/**
|
|
183
183
|
* Build an HTTP POST with a JSON body. Sets `content-type: application/json`
|
|
184
184
|
* automatically after caller-supplied headers so routes cannot accidentally
|