@opencode/ai 2.0.14 → 2.0.15
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 +115 -56
- package/dist/experimental/evaluation-client.d.ts +1 -1
- package/dist/experimental/evaluation-client.js +39 -3
- package/dist/experimental/evaluation.d.ts +4 -4
- package/dist/experimental/evaluation.js +2 -2
- package/dist/experimental/system-one.d.ts +3 -3
- package/dist/experimental/system-one.js +40 -51
- package/dist/generation.d.ts +69 -0
- package/dist/generation.js +84 -0
- package/dist/image-client.d.ts +6 -4
- package/dist/image-client.js +11 -11
- package/dist/image.d.ts +1040 -62
- package/dist/image.js +80 -52
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist/llm.d.ts +9 -1
- package/dist/media.d.ts +212 -0
- package/dist/media.js +228 -0
- package/dist/promise.d.ts +554 -0
- package/dist/promise.js +44 -0
- package/dist/protocols/anthropic-messages.js +7 -17
- package/dist/protocols/bedrock-converse.d.ts +4 -4
- package/dist/protocols/bedrock-converse.js +1 -6
- package/dist/protocols/gemini.d.ts +21 -0
- package/dist/protocols/gemini.js +42 -6
- package/dist/protocols/google-images.d.ts +9 -21
- package/dist/protocols/google-images.js +169 -132
- package/dist/protocols/meta-images.d.ts +7 -12
- package/dist/protocols/meta-images.js +92 -66
- package/dist/protocols/mistral-chat.js +7 -6
- package/dist/protocols/open-responses.d.ts +11 -3
- package/dist/protocols/open-responses.js +23 -12
- package/dist/protocols/openai-chat.d.ts +34 -1
- package/dist/protocols/openai-chat.js +100 -31
- package/dist/protocols/openai-images.d.ts +9 -20
- package/dist/protocols/openai-images.js +112 -142
- package/dist/protocols/shared.d.ts +17 -17
- package/dist/protocols/shared.js +32 -35
- package/dist/protocols/utils/bedrock-media.d.ts +2 -3
- package/dist/protocols/utils/bedrock-media.js +4 -4
- package/dist/protocols/utils/media-input.d.ts +10 -0
- package/dist/protocols/utils/media-input.js +17 -0
- package/dist/protocols/utils/responses-compaction.js +6 -5
- package/dist/protocols/utils/tool-stream.d.ts +27 -3
- package/dist/protocols/xai-images.d.ts +9 -15
- package/dist/protocols/xai-images.js +85 -83
- package/dist/protocols/zai-images.d.ts +9 -13
- package/dist/protocols/zai-images.js +59 -57
- package/dist/providers/amazon-bedrock.d.ts +2 -2
- package/dist/providers/cerebras.js +6 -1
- package/dist/providers/deepinfra.js +6 -1
- package/dist/providers/google-vertex.d.ts +7 -0
- package/dist/providers/google.d.ts +7 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/openrouter.d.ts +19 -0
- package/dist/providers/openrouter.js +13 -1
- package/dist/providers/vercel-ai-gateway.d.ts +41 -0
- package/dist/providers/vercel-ai-gateway.js +85 -0
- package/dist/route/client.d.ts +9 -1
- package/dist/route/endpoint.d.ts +10 -10
- package/dist/route/executor-service.d.ts +12 -0
- package/dist/route/executor-service.js +3 -0
- package/dist/route/executor.d.ts +4 -9
- package/dist/route/executor.js +3 -3
- package/dist/route/index.d.ts +2 -0
- package/dist/route/index.js +2 -0
- package/dist/route/media-protocol.d.ts +45 -0
- package/dist/route/media-protocol.js +40 -0
- package/dist/route/media.d.ts +46 -0
- package/dist/route/media.js +64 -0
- package/dist/schema/errors.d.ts +13 -3
- package/dist/schema/errors.js +7 -0
- package/dist/schema/events.d.ts +563 -40
- package/dist/schema/events.js +35 -2
- package/dist/schema/messages.d.ts +98 -8
- package/dist/schema/messages.js +8 -6
- package/dist/schema/options.d.ts +2 -0
- package/dist/schema/options.js +3 -0
- package/dist/testing.d.ts +72 -8
- package/dist/utils/media-type.d.ts +6 -0
- package/dist/utils/media-type.js +49 -0
- package/dist/utils/sanitize.js +3 -1
- package/package.json +7 -3
- package/dist/protocols/utils/image-input.d.ts +0 -21
- package/dist/protocols/utils/image-input.js +0 -20
|
@@ -244,6 +244,14 @@ export declare const finish: <K extends StreamKey>(route: string, tools: State<K
|
|
|
244
244
|
};
|
|
245
245
|
} | undefined;
|
|
246
246
|
readonly namespace?: string | undefined;
|
|
247
|
+
} | {
|
|
248
|
+
readonly type: "media";
|
|
249
|
+
readonly media: import("../../media.js").Asset;
|
|
250
|
+
readonly providerMetadata?: {
|
|
251
|
+
readonly [x: string]: {
|
|
252
|
+
readonly [x: string]: unknown;
|
|
253
|
+
};
|
|
254
|
+
} | undefined;
|
|
247
255
|
} | {
|
|
248
256
|
readonly type: "step-finish";
|
|
249
257
|
readonly reason: {
|
|
@@ -272,12 +280,12 @@ export declare const finish: <K extends StreamKey>(route: string, tools: State<K
|
|
|
272
280
|
} | {
|
|
273
281
|
readonly type: "provider-error";
|
|
274
282
|
readonly message: string;
|
|
283
|
+
readonly classification?: "context-overflow" | "payload-too-large" | undefined;
|
|
275
284
|
readonly providerMetadata?: {
|
|
276
285
|
readonly [x: string]: {
|
|
277
286
|
readonly [x: string]: unknown;
|
|
278
287
|
};
|
|
279
288
|
} | undefined;
|
|
280
|
-
readonly classification?: "context-overflow" | "payload-too-large" | undefined;
|
|
281
289
|
})[];
|
|
282
290
|
}, AIError, never>;
|
|
283
291
|
/**
|
|
@@ -459,6 +467,14 @@ export declare const finishWithInput: <K extends StreamKey>(route: string, tools
|
|
|
459
467
|
};
|
|
460
468
|
} | undefined;
|
|
461
469
|
readonly namespace?: string | undefined;
|
|
470
|
+
} | {
|
|
471
|
+
readonly type: "media";
|
|
472
|
+
readonly media: import("../../media.js").Asset;
|
|
473
|
+
readonly providerMetadata?: {
|
|
474
|
+
readonly [x: string]: {
|
|
475
|
+
readonly [x: string]: unknown;
|
|
476
|
+
};
|
|
477
|
+
} | undefined;
|
|
462
478
|
} | {
|
|
463
479
|
readonly type: "step-finish";
|
|
464
480
|
readonly reason: {
|
|
@@ -487,12 +503,12 @@ export declare const finishWithInput: <K extends StreamKey>(route: string, tools
|
|
|
487
503
|
} | {
|
|
488
504
|
readonly type: "provider-error";
|
|
489
505
|
readonly message: string;
|
|
506
|
+
readonly classification?: "context-overflow" | "payload-too-large" | undefined;
|
|
490
507
|
readonly providerMetadata?: {
|
|
491
508
|
readonly [x: string]: {
|
|
492
509
|
readonly [x: string]: unknown;
|
|
493
510
|
};
|
|
494
511
|
} | undefined;
|
|
495
|
-
readonly classification?: "context-overflow" | "payload-too-large" | undefined;
|
|
496
512
|
})[];
|
|
497
513
|
}, AIError, never>;
|
|
498
514
|
/**
|
|
@@ -671,6 +687,14 @@ export declare const finishAll: <K extends StreamKey>(route: string, tools: Stat
|
|
|
671
687
|
};
|
|
672
688
|
} | undefined;
|
|
673
689
|
readonly namespace?: string | undefined;
|
|
690
|
+
} | {
|
|
691
|
+
readonly type: "media";
|
|
692
|
+
readonly media: import("../../media.js").Asset;
|
|
693
|
+
readonly providerMetadata?: {
|
|
694
|
+
readonly [x: string]: {
|
|
695
|
+
readonly [x: string]: unknown;
|
|
696
|
+
};
|
|
697
|
+
} | undefined;
|
|
674
698
|
} | {
|
|
675
699
|
readonly type: "step-finish";
|
|
676
700
|
readonly reason: {
|
|
@@ -699,12 +723,12 @@ export declare const finishAll: <K extends StreamKey>(route: string, tools: Stat
|
|
|
699
723
|
} | {
|
|
700
724
|
readonly type: "provider-error";
|
|
701
725
|
readonly message: string;
|
|
726
|
+
readonly classification?: "context-overflow" | "payload-too-large" | undefined;
|
|
702
727
|
readonly providerMetadata?: {
|
|
703
728
|
readonly [x: string]: {
|
|
704
729
|
readonly [x: string]: unknown;
|
|
705
730
|
};
|
|
706
731
|
} | undefined;
|
|
707
|
-
readonly classification?: "context-overflow" | "payload-too-large" | undefined;
|
|
708
732
|
})[];
|
|
709
733
|
}, AIError, never>;
|
|
710
734
|
export * as ToolStream from "./tool-stream.js";
|
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
import { ImageModel } from "../image.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js";
|
|
2
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
3
|
+
import { MediaRoute } from "../route/media.js";
|
|
4
4
|
export declare const DEFAULT_BASE_URL = "https://api.x.ai/v1";
|
|
5
5
|
export declare const PATH = "/images/generations";
|
|
6
6
|
export declare const EDIT_PATH = "/images/edits";
|
|
7
7
|
export type XAIImageString<Known extends string> = Known | (string & {});
|
|
8
|
+
/** Provider-native options. Common fields (`n`, `aspectRatio`, `images`) live on the request. */
|
|
8
9
|
export type XAIImageOptions = {
|
|
9
|
-
readonly n?: number;
|
|
10
|
-
readonly aspectRatio?: XAIImageString<"1:1" | "3:4" | "4:3" | "9:16" | "16:9" | "2:3" | "3:2" | "9:19.5" | "19.5:9" | "9:20" | "20:9" | "1:2" | "2:1" | "auto">;
|
|
11
|
-
readonly aspect_ratio?: XAIImageString<"1:1" | "3:4" | "4:3" | "9:16" | "16:9" | "2:3" | "3:2" | "9:19.5" | "19.5:9" | "9:20" | "20:9" | "1:2" | "2:1" | "auto">;
|
|
12
10
|
readonly resolution?: XAIImageString<"1k" | "2k">;
|
|
13
11
|
readonly responseFormat?: XAIImageString<"url" | "b64_json">;
|
|
14
12
|
readonly response_format?: XAIImageString<"url" | "b64_json">;
|
|
15
13
|
} & Record<string, unknown>;
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
readonly baseURL?: string;
|
|
20
|
-
readonly headers?: Record<string, string>;
|
|
21
|
-
readonly http?: HttpOptions;
|
|
22
|
-
}
|
|
23
|
-
export declare const model: (input: ModelInput) => ImageModel<XAIImageOptions>;
|
|
14
|
+
export type Request = ImageRequestFor<XAIImageOptions>;
|
|
15
|
+
export declare const protocol: MediaProtocol.Inline<Request, ImageResponse>;
|
|
16
|
+
export declare const model: (input: MediaRoute.ModelInput) => ImageModel<XAIImageOptions>;
|
|
24
17
|
export declare const XAIImages: {
|
|
25
|
-
readonly
|
|
18
|
+
readonly protocol: MediaProtocol.Inline<Request, ImageResponse>;
|
|
19
|
+
readonly model: (input: MediaRoute.ModelInput) => ImageModel<XAIImageOptions>;
|
|
26
20
|
};
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import { Effect,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { ImageModel, ImageResponse } from "../image.js";
|
|
3
|
+
import { Media } from "../media.js";
|
|
4
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
5
|
+
import { MediaRoute } from "../route/media.js";
|
|
6
|
+
import { ProviderID, mergeJsonRecords } from "../schema/index.js";
|
|
6
7
|
import { ProviderShared, optionalNull } from "./shared.js";
|
|
7
|
-
import {
|
|
8
|
+
import { MediaInput } from "./utils/media-input.js";
|
|
8
9
|
const ADAPTER = "xai-images";
|
|
10
|
+
const NAME = "xAI Images";
|
|
11
|
+
const PROVIDER = ProviderID.make("xai");
|
|
9
12
|
export const DEFAULT_BASE_URL = "https://api.x.ai/v1";
|
|
10
13
|
export const PATH = "/images/generations";
|
|
11
14
|
export const EDIT_PATH = "/images/edits";
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// 2. Response schema
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
12
18
|
const XAIImageResponse = Schema.Struct({
|
|
13
19
|
data: Schema.Array(Schema.Struct({
|
|
14
20
|
b64_json: optionalNull(Schema.String),
|
|
@@ -18,89 +24,85 @@ const XAIImageResponse = Schema.Struct({
|
|
|
18
24
|
})),
|
|
19
25
|
usage: Schema.optional(Schema.Unknown),
|
|
20
26
|
});
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// 5. Request body construction
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
21
30
|
const nativeOptions = (options) => {
|
|
22
31
|
if (!options)
|
|
23
32
|
return undefined;
|
|
24
|
-
const {
|
|
25
|
-
return {
|
|
26
|
-
aspect_ratio: aspectRatio,
|
|
27
|
-
response_format: responseFormat,
|
|
28
|
-
...native,
|
|
29
|
-
};
|
|
33
|
+
const { responseFormat, ...native } = options;
|
|
34
|
+
return { response_format: responseFormat, ...native };
|
|
30
35
|
};
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
const isEdit = (request) => (request.images?.length ?? 0) > 0;
|
|
37
|
+
const reference = (asset) => {
|
|
38
|
+
const inline = asset.inline();
|
|
39
|
+
if (inline)
|
|
40
|
+
return Effect.succeed({ url: inline.dataUrl, type: "image_url" });
|
|
41
|
+
const url = ProviderShared.mediaUrl(asset);
|
|
42
|
+
if (url)
|
|
43
|
+
return Effect.succeed({ url, type: "image_url" });
|
|
44
|
+
const id = MediaInput.refID(asset, PROVIDER);
|
|
45
|
+
if (id)
|
|
46
|
+
return Effect.succeed({ file_id: id });
|
|
47
|
+
return Effect.fail(ProviderShared.invalidRequest(`${NAME} accepts image URLs, data URLs, bytes, and xAI file IDs`));
|
|
37
48
|
};
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
request,
|
|
64
|
-
method: "POST",
|
|
65
|
-
url,
|
|
66
|
-
body: text,
|
|
67
|
-
headers: Headers.fromInput({ ...input.headers, ...http?.headers }),
|
|
68
|
-
});
|
|
69
|
-
const response = yield* execute(HttpClientRequest.post(url).pipe(HttpClientRequest.setHeaders(headers), HttpClientRequest.bodyText(text, "application/json")));
|
|
70
|
-
const output = yield* ProviderShared.imageResponse(ADAPTER, "xAI Images", response);
|
|
71
|
-
const decoded = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(XAIImageResponse))(output.body).pipe(Effect.mapError((cause) => output.invalid("xAI Images returned an invalid response", cause)));
|
|
72
|
-
const images = yield* Effect.forEach(decoded.data, (item, index) => {
|
|
73
|
-
const mediaType = item.mime_type ?? "application/octet-stream";
|
|
74
|
-
if (item.b64_json)
|
|
75
|
-
return Effect.fromResult(Encoding.decodeBase64(item.b64_json)).pipe(Effect.mapError((cause) => output.invalid(`xAI Images result ${index} contains invalid base64 data`, cause)), Effect.map((data) => new GeneratedImage({
|
|
76
|
-
mediaType,
|
|
77
|
-
data,
|
|
78
|
-
providerMetadata: item.revised_prompt === undefined || item.revised_prompt === null
|
|
79
|
-
? undefined
|
|
80
|
-
: { xai: { revisedPrompt: item.revised_prompt } },
|
|
81
|
-
})));
|
|
82
|
-
if (item.url)
|
|
83
|
-
return Effect.succeed(new GeneratedImage({
|
|
84
|
-
mediaType,
|
|
85
|
-
data: item.url,
|
|
86
|
-
providerMetadata: item.revised_prompt === undefined || item.revised_prompt === null
|
|
87
|
-
? undefined
|
|
88
|
-
: { xai: { revisedPrompt: item.revised_prompt } },
|
|
89
|
-
}));
|
|
90
|
-
return Effect.fail(output.invalid(`xAI Images result ${index} has neither image data nor a URL`));
|
|
91
|
-
});
|
|
92
|
-
if (images.length === 0)
|
|
93
|
-
return yield* output.invalid("xAI Images returned no images");
|
|
94
|
-
const usage = ProviderShared.isRecord(decoded.usage) ? decoded.usage : undefined;
|
|
95
|
-
return new ImageResponse({
|
|
96
|
-
images,
|
|
97
|
-
usage: usage === undefined ? undefined : new Usage({ providerMetadata: { xai: usage } }),
|
|
98
|
-
providerMetadata: usage === undefined ? undefined : { xai: { usage } },
|
|
49
|
+
const fromRequest = Effect.fn("XAIImages.fromRequest")(function* (request) {
|
|
50
|
+
const references = yield* Effect.forEach(request.images ?? [], reference);
|
|
51
|
+
return MediaProtocol.json(mergeJsonRecords({
|
|
52
|
+
model: request.model.id,
|
|
53
|
+
prompt: request.prompt,
|
|
54
|
+
// xAI takes one edit source as `image` and several as `images`.
|
|
55
|
+
image: references.length === 1 ? references[0] : undefined,
|
|
56
|
+
images: references.length > 1 ? references : undefined,
|
|
57
|
+
n: request.n,
|
|
58
|
+
aspect_ratio: request.aspectRatio,
|
|
59
|
+
}, nativeOptions(request.providerOptions), request.http?.body) ?? {});
|
|
60
|
+
});
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// 6. Response decoding
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
const decodeResponse = Effect.fn("XAIImages.decodeResponse")(function* (response) {
|
|
65
|
+
const output = yield* MediaProtocol.decodeJson(ADAPTER, NAME, XAIImageResponse)(response);
|
|
66
|
+
const decoded = output.value;
|
|
67
|
+
const images = yield* Effect.forEach(decoded.data, (item, index) => {
|
|
68
|
+
const providerMetadata = item.revised_prompt === undefined || item.revised_prompt === null
|
|
69
|
+
? undefined
|
|
70
|
+
: { xai: { revisedPrompt: item.revised_prompt } };
|
|
71
|
+
if (item.b64_json)
|
|
72
|
+
return MediaInput.decodedAsset(output.invalid, `${NAME} result ${index}`, item.b64_json, item.mime_type ?? undefined, {
|
|
73
|
+
providerMetadata,
|
|
99
74
|
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
};
|
|
75
|
+
if (item.url)
|
|
76
|
+
return Effect.succeed(Media.url(item.url, { mediaType: item.mime_type ?? undefined, providerMetadata }));
|
|
77
|
+
return Effect.fail(output.invalid(`${NAME} result ${index} has neither image data nor a URL`));
|
|
78
|
+
});
|
|
79
|
+
if (images.length === 0)
|
|
80
|
+
return yield* output.invalid(`${NAME} returned no images`);
|
|
81
|
+
const usage = ProviderShared.isRecord(decoded.usage) ? decoded.usage : undefined;
|
|
82
|
+
// xAI reports image counts rather than tokens, seconds, or credits; the raw record stays in provider metadata.
|
|
83
|
+
return new ImageResponse({
|
|
84
|
+
images,
|
|
85
|
+
providerMetadata: usage === undefined ? undefined : { xai: { usage } },
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// 7. Protocol and route
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
export const protocol = MediaProtocol.inline({
|
|
92
|
+
id: ADAPTER,
|
|
93
|
+
name: NAME,
|
|
94
|
+
unsupported: ["mask", "size", "seed", "format"],
|
|
95
|
+
body: { from: fromRequest },
|
|
96
|
+
response: { decode: decodeResponse },
|
|
97
|
+
});
|
|
98
|
+
export const model = (input) => ImageModel.fromRoute({
|
|
99
|
+
id: ADAPTER,
|
|
100
|
+
provider: PROVIDER,
|
|
101
|
+
protocol,
|
|
102
|
+
baseURL: DEFAULT_BASE_URL,
|
|
103
|
+
path: ({ request }) => (isEdit(request) ? EDIT_PATH : PATH),
|
|
104
|
+
}, input);
|
|
104
105
|
export const XAIImages = {
|
|
106
|
+
protocol,
|
|
105
107
|
model,
|
|
106
108
|
};
|
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
import { ImageModel } from "../image.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ImageModel, ImageResponse, type ImageRequestFor } from "../image.js";
|
|
2
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
3
|
+
import { MediaRoute } from "../route/media.js";
|
|
4
4
|
export declare const DEFAULT_BASE_URL = "https://api.z.ai/api/paas/v4";
|
|
5
5
|
export declare const PATH = "/images/generations";
|
|
6
6
|
export type ZAIImageString<Known extends string> = Known | (string & {});
|
|
7
|
+
/** Provider-native options. The common `size` field lives on the request. */
|
|
7
8
|
export type ZAIImageOptions = {
|
|
8
|
-
readonly size?: ZAIImageString<"1024x1024" | "768x1344" | "864x1152" | "1344x768" | "1152x864" | "1440x720" | "720x1440">;
|
|
9
9
|
readonly quality?: ZAIImageString<"hd" | "standard">;
|
|
10
10
|
readonly userID?: string;
|
|
11
11
|
} & Record<string, unknown>;
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
readonly baseURL?: string;
|
|
16
|
-
readonly headers?: Record<string, string>;
|
|
17
|
-
readonly http?: HttpOptions;
|
|
18
|
-
}
|
|
19
|
-
export declare const model: (input: ModelInput) => ImageModel<ZAIImageOptions>;
|
|
12
|
+
export type Request = ImageRequestFor<ZAIImageOptions>;
|
|
13
|
+
export declare const protocol: MediaProtocol.Inline<Request, ImageResponse>;
|
|
14
|
+
export declare const model: (input: MediaRoute.ModelInput) => ImageModel<ZAIImageOptions>;
|
|
20
15
|
export declare const ZAIImages: {
|
|
21
|
-
readonly
|
|
16
|
+
readonly protocol: MediaProtocol.Inline<Request, ImageResponse>;
|
|
17
|
+
readonly model: (input: MediaRoute.ModelInput) => ImageModel<ZAIImageOptions>;
|
|
22
18
|
};
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { ImageInputs } from "./utils/image-input.js";
|
|
2
|
+
import { ImageModel, ImageResponse } from "../image.js";
|
|
3
|
+
import { Media } from "../media.js";
|
|
4
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
5
|
+
import { MediaRoute } from "../route/media.js";
|
|
6
|
+
import { ProviderID, mergeJsonRecords } from "../schema/index.js";
|
|
8
7
|
const ADAPTER = "zai-images";
|
|
8
|
+
const NAME = "Z.ai Images";
|
|
9
|
+
const PROVIDER = ProviderID.make("zai");
|
|
9
10
|
export const DEFAULT_BASE_URL = "https://api.z.ai/api/paas/v4";
|
|
10
11
|
export const PATH = "/images/generations";
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// 2. Response schema
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
11
15
|
const ZAIImageResponse = Schema.Struct({
|
|
12
16
|
created: Schema.optional(Schema.Int),
|
|
13
17
|
id: Schema.optional(Schema.String),
|
|
@@ -18,62 +22,60 @@ const ZAIImageResponse = Schema.Struct({
|
|
|
18
22
|
level: Schema.optional(Schema.Number),
|
|
19
23
|
}))),
|
|
20
24
|
});
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// 5. Request body construction
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
21
28
|
const nativeOptions = (options) => {
|
|
22
29
|
if (!options)
|
|
23
30
|
return undefined;
|
|
24
31
|
const { userID, ...native } = options;
|
|
25
|
-
return {
|
|
26
|
-
user_id: userID,
|
|
27
|
-
...native,
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
const applyQuery = (url, query) => {
|
|
31
|
-
if (!query)
|
|
32
|
-
return url;
|
|
33
|
-
const next = new URL(url);
|
|
34
|
-
Object.entries(query).forEach(([key, value]) => next.searchParams.set(key, value));
|
|
35
|
-
return next.toString();
|
|
36
|
-
};
|
|
37
|
-
export const model = (input) => {
|
|
38
|
-
const route = {
|
|
39
|
-
id: ADAPTER,
|
|
40
|
-
generate: Effect.fn("ZAIImages.generate")(function* (request, execute) {
|
|
41
|
-
if ((request.images?.length ?? 0) > 0)
|
|
42
|
-
return yield* ImageInputs.invalid("Z.ai hosted image generation does not support image inputs");
|
|
43
|
-
const http = mergeHttpOptions(request.model.http, request.http);
|
|
44
|
-
const requestBody = mergeJsonRecords({ model: request.model.id, prompt: request.prompt }, nativeOptions(request.options), http?.body);
|
|
45
|
-
const text = ProviderShared.encodeJson(requestBody);
|
|
46
|
-
const url = applyQuery(`${(input.baseURL ?? DEFAULT_BASE_URL).replace(/\/$/, "")}${PATH}`, http?.query);
|
|
47
|
-
const headers = yield* Auth.toEffect(input.auth)({
|
|
48
|
-
request,
|
|
49
|
-
method: "POST",
|
|
50
|
-
url,
|
|
51
|
-
body: text,
|
|
52
|
-
headers: Headers.fromInput({ ...input.headers, ...http?.headers }),
|
|
53
|
-
});
|
|
54
|
-
const response = yield* execute(HttpClientRequest.post(url).pipe(HttpClientRequest.setHeaders(headers), HttpClientRequest.bodyText(text, "application/json")));
|
|
55
|
-
const output = yield* ProviderShared.imageResponse(ADAPTER, "Z.ai Images", response);
|
|
56
|
-
const decoded = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ZAIImageResponse))(output.body).pipe(Effect.mapError((cause) => output.invalid("Z.ai Images returned an invalid response", cause)));
|
|
57
|
-
if (decoded.data.length === 0)
|
|
58
|
-
return yield* output.invalid("Z.ai Images returned no images");
|
|
59
|
-
return new ImageResponse({
|
|
60
|
-
images: decoded.data.map((item) => new GeneratedImage({
|
|
61
|
-
mediaType: "application/octet-stream",
|
|
62
|
-
data: item.url,
|
|
63
|
-
})),
|
|
64
|
-
providerMetadata: {
|
|
65
|
-
zai: {
|
|
66
|
-
created: decoded.created,
|
|
67
|
-
id: decoded.id,
|
|
68
|
-
requestID: decoded.request_id,
|
|
69
|
-
contentFilter: decoded.content_filter,
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}),
|
|
74
|
-
};
|
|
75
|
-
return ImageModel.make({ id: input.id, provider: "zai", route, http: input.http });
|
|
32
|
+
return { user_id: userID, ...native };
|
|
76
33
|
};
|
|
34
|
+
const fromRequest = Effect.fn("ZAIImages.fromRequest")(function* (request) {
|
|
35
|
+
return MediaProtocol.json(mergeJsonRecords({ model: request.model.id, prompt: request.prompt, size: request.size }, nativeOptions(request.providerOptions), request.http?.body) ?? {});
|
|
36
|
+
});
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// 6. Response decoding
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
const decodeResponse = Effect.fn("ZAIImages.decodeResponse")(function* (response) {
|
|
41
|
+
const output = yield* MediaProtocol.decodeJson(ADAPTER, NAME, ZAIImageResponse)(response);
|
|
42
|
+
const decoded = output.value;
|
|
43
|
+
if (decoded.data.length === 0)
|
|
44
|
+
return yield* output.invalid(`${NAME} returned no images`);
|
|
45
|
+
const filters = decoded.content_filter ?? [];
|
|
46
|
+
return new ImageResponse({
|
|
47
|
+
// Z.ai returns only URLs and no content type; the media type resolves when the asset is materialized.
|
|
48
|
+
images: decoded.data.map((item) => Media.url(item.url)),
|
|
49
|
+
// Z.ai reports applied content filters alongside a successful result; surface them instead of dropping them.
|
|
50
|
+
notices: filters.length === 0
|
|
51
|
+
? undefined
|
|
52
|
+
: filters.map((filter) => ({
|
|
53
|
+
type: "moderated",
|
|
54
|
+
message: `${NAME} applied a content filter${filter.role === undefined ? "" : ` for ${filter.role}`}${filter.level === undefined ? "" : ` at level ${filter.level}`}`,
|
|
55
|
+
providerMetadata: { zai: filter },
|
|
56
|
+
})),
|
|
57
|
+
providerMetadata: {
|
|
58
|
+
zai: {
|
|
59
|
+
created: decoded.created,
|
|
60
|
+
id: decoded.id,
|
|
61
|
+
requestID: decoded.request_id,
|
|
62
|
+
contentFilter: decoded.content_filter,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// 7. Protocol and route
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
export const protocol = MediaProtocol.inline({
|
|
71
|
+
id: ADAPTER,
|
|
72
|
+
name: NAME,
|
|
73
|
+
unsupported: ["images", "mask", "n", "aspectRatio", "seed", "format"],
|
|
74
|
+
body: { from: fromRequest },
|
|
75
|
+
response: { decode: decodeResponse },
|
|
76
|
+
});
|
|
77
|
+
export const model = (input) => ImageModel.fromRoute({ id: ADAPTER, provider: PROVIDER, protocol, baseURL: DEFAULT_BASE_URL, path: PATH }, input);
|
|
77
78
|
export const ZAIImages = {
|
|
79
|
+
protocol,
|
|
78
80
|
model,
|
|
79
81
|
};
|
|
@@ -44,7 +44,7 @@ export declare const routes: import("../route/client.js").Route<{
|
|
|
44
44
|
};
|
|
45
45
|
} | {
|
|
46
46
|
readonly document: {
|
|
47
|
-
readonly format: "pdf" | "
|
|
47
|
+
readonly format: "pdf" | "txt" | "md" | "csv" | "doc" | "docx" | "xls" | "xlsx" | "html";
|
|
48
48
|
readonly name: string;
|
|
49
49
|
readonly source: {
|
|
50
50
|
readonly bytes: string;
|
|
@@ -63,7 +63,7 @@ export declare const routes: import("../route/client.js").Route<{
|
|
|
63
63
|
};
|
|
64
64
|
} | {
|
|
65
65
|
readonly document: {
|
|
66
|
-
readonly format: "pdf" | "
|
|
66
|
+
readonly format: "pdf" | "txt" | "md" | "csv" | "doc" | "docx" | "xls" | "xlsx" | "html";
|
|
67
67
|
readonly name: string;
|
|
68
68
|
readonly source: {
|
|
69
69
|
readonly bytes: string;
|
|
@@ -25,7 +25,12 @@ export const configure = (input = {}) => {
|
|
|
25
25
|
id,
|
|
26
26
|
model: (modelID) => configured.model({
|
|
27
27
|
id: modelID,
|
|
28
|
-
compatibility: {
|
|
28
|
+
compatibility: {
|
|
29
|
+
maxTokensField: "max_tokens",
|
|
30
|
+
reasoningField: "reasoning",
|
|
31
|
+
supportsStore: false,
|
|
32
|
+
supportsPromptCacheKey: true,
|
|
33
|
+
},
|
|
29
34
|
}),
|
|
30
35
|
configure,
|
|
31
36
|
};
|
|
@@ -28,7 +28,12 @@ export const configure = (input = {}) => {
|
|
|
28
28
|
id,
|
|
29
29
|
model: (modelID) => configured.model({
|
|
30
30
|
id: modelID,
|
|
31
|
-
compatibility: {
|
|
31
|
+
compatibility: {
|
|
32
|
+
maxTokensField: "max_tokens",
|
|
33
|
+
reasoningField: "reasoning_content",
|
|
34
|
+
supportsStore: false,
|
|
35
|
+
supportsPromptCacheKey: true,
|
|
36
|
+
},
|
|
32
37
|
}),
|
|
33
38
|
configure,
|
|
34
39
|
};
|
|
@@ -32,10 +32,16 @@ export declare const routes: Route<{
|
|
|
32
32
|
readonly mimeType: string;
|
|
33
33
|
readonly data: string;
|
|
34
34
|
};
|
|
35
|
+
readonly thoughtSignature?: string | null | undefined;
|
|
35
36
|
} | {
|
|
36
37
|
readonly text: string;
|
|
37
38
|
readonly thought?: boolean | null | undefined;
|
|
38
39
|
readonly thoughtSignature?: string | null | undefined;
|
|
40
|
+
} | {
|
|
41
|
+
readonly fileData: {
|
|
42
|
+
readonly mimeType: string;
|
|
43
|
+
readonly fileUri: string;
|
|
44
|
+
};
|
|
39
45
|
} | {
|
|
40
46
|
readonly functionCall: {
|
|
41
47
|
readonly name: string;
|
|
@@ -53,6 +59,7 @@ export declare const routes: Route<{
|
|
|
53
59
|
readonly mimeType: string;
|
|
54
60
|
readonly data: string;
|
|
55
61
|
};
|
|
62
|
+
readonly thoughtSignature?: string | null | undefined;
|
|
56
63
|
}[] | undefined;
|
|
57
64
|
};
|
|
58
65
|
})[] | null | undefined;
|
|
@@ -14,10 +14,16 @@ export declare const routes: import("../route/client.js").Route<{
|
|
|
14
14
|
readonly mimeType: string;
|
|
15
15
|
readonly data: string;
|
|
16
16
|
};
|
|
17
|
+
readonly thoughtSignature?: string | null | undefined;
|
|
17
18
|
} | {
|
|
18
19
|
readonly text: string;
|
|
19
20
|
readonly thought?: boolean | null | undefined;
|
|
20
21
|
readonly thoughtSignature?: string | null | undefined;
|
|
22
|
+
} | {
|
|
23
|
+
readonly fileData: {
|
|
24
|
+
readonly mimeType: string;
|
|
25
|
+
readonly fileUri: string;
|
|
26
|
+
};
|
|
21
27
|
} | {
|
|
22
28
|
readonly functionCall: {
|
|
23
29
|
readonly name: string;
|
|
@@ -35,6 +41,7 @@ export declare const routes: import("../route/client.js").Route<{
|
|
|
35
41
|
readonly mimeType: string;
|
|
36
42
|
readonly data: string;
|
|
37
43
|
};
|
|
44
|
+
readonly thoughtSignature?: string | null | undefined;
|
|
38
45
|
}[] | undefined;
|
|
39
46
|
};
|
|
40
47
|
})[] | null | undefined;
|
|
@@ -28,6 +28,7 @@ export * as OpenCodeZen from "./opencode-zen.js";
|
|
|
28
28
|
export * as OpenRouter from "./openrouter.js";
|
|
29
29
|
export * as TogetherAI from "./togetherai.js";
|
|
30
30
|
export * as TypeSafeAI from "./typesafe-ai.js";
|
|
31
|
+
export * as VercelAIGateway from "./vercel-ai-gateway.js";
|
|
31
32
|
export * as XAI from "./xai.js";
|
|
32
33
|
export * as ZAI from "./zai.js";
|
|
33
34
|
export * as ZAICodingPlan from "./zai-coding-plan.js";
|
package/dist/providers/index.js
CHANGED
|
@@ -28,6 +28,7 @@ export * as OpenCodeZen from "./opencode-zen.js";
|
|
|
28
28
|
export * as OpenRouter from "./openrouter.js";
|
|
29
29
|
export * as TogetherAI from "./togetherai.js";
|
|
30
30
|
export * as TypeSafeAI from "./typesafe-ai.js";
|
|
31
|
+
export * as VercelAIGateway from "./vercel-ai-gateway.js";
|
|
31
32
|
export * as XAI from "./xai.js";
|
|
32
33
|
export * as ZAI from "./zai.js";
|
|
33
34
|
export * as ZAICodingPlan from "./zai-coding-plan.js";
|
|
@@ -73,6 +73,13 @@ export interface OpenRouterOptions {
|
|
|
73
73
|
}>;
|
|
74
74
|
}
|
|
75
75
|
export type OpenRouterProviderOptionsInput = OpenRouterOptions;
|
|
76
|
+
export interface OpenRouterEvaluationOptions {
|
|
77
|
+
readonly [key: string]: unknown;
|
|
78
|
+
readonly provider?: OpenRouterProviderRouting;
|
|
79
|
+
readonly session_id?: string;
|
|
80
|
+
readonly trace?: Readonly<Record<string, unknown>>;
|
|
81
|
+
readonly user?: string;
|
|
82
|
+
}
|
|
76
83
|
export type LanguageModelOptions = Omit<RouteDefaultsInput, "providerOptions"> & ProviderAuthOption<"optional"> & {
|
|
77
84
|
readonly baseURL?: string;
|
|
78
85
|
readonly providerOptions?: OpenRouterProviderOptionsInput;
|
|
@@ -548,16 +555,28 @@ export declare const routes: Route<{
|
|
|
548
555
|
export declare const configure: (input?: LanguageModelOptions) => {
|
|
549
556
|
id: string & import("effect/Brand").Brand<"AI.ProviderID">;
|
|
550
557
|
model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<OpenRouterOptions, import("../route/client.js").CompactionOperations | undefined>;
|
|
558
|
+
experimental: {
|
|
559
|
+
evaluation: (modelID: string | ModelID) => import("../experimental.js").EvaluationModel<OpenRouterEvaluationOptions>;
|
|
560
|
+
};
|
|
551
561
|
configure: (input?: LanguageModelOptions) => /*elided*/ any;
|
|
552
562
|
};
|
|
553
563
|
export declare const provider: {
|
|
554
564
|
id: string & import("effect/Brand").Brand<"AI.ProviderID">;
|
|
555
565
|
model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<OpenRouterOptions, import("../route/client.js").CompactionOperations | undefined>;
|
|
566
|
+
experimental: {
|
|
567
|
+
evaluation: (modelID: string | ModelID) => import("../experimental.js").EvaluationModel<OpenRouterEvaluationOptions>;
|
|
568
|
+
};
|
|
556
569
|
configure: (input?: LanguageModelOptions) => {
|
|
557
570
|
id: string & import("effect/Brand").Brand<"AI.ProviderID">;
|
|
558
571
|
model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<OpenRouterOptions, import("../route/client.js").CompactionOperations | undefined>;
|
|
572
|
+
experimental: {
|
|
573
|
+
evaluation: (modelID: string | ModelID) => import("../experimental.js").EvaluationModel<OpenRouterEvaluationOptions>;
|
|
574
|
+
};
|
|
559
575
|
configure: /*elided*/ any;
|
|
560
576
|
};
|
|
561
577
|
};
|
|
578
|
+
export declare const experimental: {
|
|
579
|
+
evaluation: (modelID: string | ModelID) => import("../experimental.js").EvaluationModel<OpenRouterEvaluationOptions>;
|
|
580
|
+
};
|
|
562
581
|
export declare const model: ProviderPackage.Definition<Settings, OpenRouterProviderOptionsInput>["model"];
|
|
563
582
|
export {};
|