@opencode-ai/ai 0.0.0-beta-17492

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.
Files changed (194) hide show
  1. package/README.md +392 -0
  2. package/dist/cache-policy.d.ts +2 -0
  3. package/dist/cache-policy.js +121 -0
  4. package/dist/image-client.d.ts +19 -0
  5. package/dist/image-client.js +19 -0
  6. package/dist/image.d.ts +110 -0
  7. package/dist/image.js +102 -0
  8. package/dist/index.d.ts +18 -0
  9. package/dist/index.js +12 -0
  10. package/dist/llm.d.ts +230 -0
  11. package/dist/llm.js +77 -0
  12. package/dist/protocols/anthropic-messages.d.ts +633 -0
  13. package/dist/protocols/anthropic-messages.js +860 -0
  14. package/dist/protocols/bedrock-converse.d.ts +533 -0
  15. package/dist/protocols/bedrock-converse.js +584 -0
  16. package/dist/protocols/bedrock-event-stream.d.ts +9 -0
  17. package/dist/protocols/bedrock-event-stream.js +73 -0
  18. package/dist/protocols/gemini.d.ts +300 -0
  19. package/dist/protocols/gemini.js +512 -0
  20. package/dist/protocols/google-images.d.ts +30 -0
  21. package/dist/protocols/google-images.js +191 -0
  22. package/dist/protocols/index.d.ts +10 -0
  23. package/dist/protocols/index.js +10 -0
  24. package/dist/protocols/open-responses-channel.d.ts +26 -0
  25. package/dist/protocols/open-responses-channel.js +120 -0
  26. package/dist/protocols/open-responses.d.ts +951 -0
  27. package/dist/protocols/open-responses.js +873 -0
  28. package/dist/protocols/openai-chat.d.ts +795 -0
  29. package/dist/protocols/openai-chat.js +718 -0
  30. package/dist/protocols/openai-compatible-chat.d.ts +107 -0
  31. package/dist/protocols/openai-compatible-chat.js +20 -0
  32. package/dist/protocols/openai-compatible-responses.d.ts +96 -0
  33. package/dist/protocols/openai-compatible-responses.js +17 -0
  34. package/dist/protocols/openai-images.d.ts +32 -0
  35. package/dist/protocols/openai-images.js +188 -0
  36. package/dist/protocols/openai-responses-channel.d.ts +12 -0
  37. package/dist/protocols/openai-responses-channel.js +142 -0
  38. package/dist/protocols/openai-responses.d.ts +596 -0
  39. package/dist/protocols/openai-responses.js +208 -0
  40. package/dist/protocols/shared.d.ts +194 -0
  41. package/dist/protocols/shared.js +238 -0
  42. package/dist/protocols/utils/bedrock-auth.d.ts +21 -0
  43. package/dist/protocols/utils/bedrock-auth.js +43 -0
  44. package/dist/protocols/utils/bedrock-cache.d.ts +15 -0
  45. package/dist/protocols/utils/bedrock-cache.js +29 -0
  46. package/dist/protocols/utils/bedrock-media.d.ts +49 -0
  47. package/dist/protocols/utils/bedrock-media.js +70 -0
  48. package/dist/protocols/utils/cache.d.ts +6 -0
  49. package/dist/protocols/utils/cache.js +8 -0
  50. package/dist/protocols/utils/gemini-tool-schema.d.ts +2 -0
  51. package/dist/protocols/utils/gemini-tool-schema.js +103 -0
  52. package/dist/protocols/utils/image-input.d.ts +21 -0
  53. package/dist/protocols/utils/image-input.js +22 -0
  54. package/dist/protocols/utils/lifecycle.d.ts +20 -0
  55. package/dist/protocols/utils/lifecycle.js +68 -0
  56. package/dist/protocols/utils/open-responses-options.d.ts +21 -0
  57. package/dist/protocols/utils/open-responses-options.js +41 -0
  58. package/dist/protocols/utils/openai-image.d.ts +5 -0
  59. package/dist/protocols/utils/openai-image.js +18 -0
  60. package/dist/protocols/utils/openai-options.d.ts +14 -0
  61. package/dist/protocols/utils/openai-options.js +14 -0
  62. package/dist/protocols/utils/tool-schema.d.ts +8 -0
  63. package/dist/protocols/utils/tool-schema.js +81 -0
  64. package/dist/protocols/utils/tool-stream.d.ts +639 -0
  65. package/dist/protocols/utils/tool-stream.js +141 -0
  66. package/dist/protocols/xai-images.d.ts +26 -0
  67. package/dist/protocols/xai-images.js +111 -0
  68. package/dist/protocols/zai-images.d.ts +22 -0
  69. package/dist/protocols/zai-images.js +84 -0
  70. package/dist/protocols.d.ts +1 -0
  71. package/dist/protocols.js +1 -0
  72. package/dist/provider-error.d.ts +14 -0
  73. package/dist/provider-error.js +130 -0
  74. package/dist/provider-package.d.ts +15 -0
  75. package/dist/provider-package.js +1 -0
  76. package/dist/provider.d.ts +23 -0
  77. package/dist/provider.js +2 -0
  78. package/dist/providers/amazon-bedrock/mantle/chat.d.ts +2 -0
  79. package/dist/providers/amazon-bedrock/mantle/chat.js +1 -0
  80. package/dist/providers/amazon-bedrock/mantle/responses.d.ts +2 -0
  81. package/dist/providers/amazon-bedrock/mantle/responses.js +1 -0
  82. package/dist/providers/amazon-bedrock/mantle.d.ts +2 -0
  83. package/dist/providers/amazon-bedrock/mantle.js +1 -0
  84. package/dist/providers/amazon-bedrock-mantle.d.ts +247 -0
  85. package/dist/providers/amazon-bedrock-mantle.js +68 -0
  86. package/dist/providers/amazon-bedrock.d.ts +172 -0
  87. package/dist/providers/amazon-bedrock.js +41 -0
  88. package/dist/providers/anthropic-compatible.d.ts +218 -0
  89. package/dist/providers/anthropic-compatible.js +45 -0
  90. package/dist/providers/anthropic.d.ts +216 -0
  91. package/dist/providers/anthropic.js +40 -0
  92. package/dist/providers/azure/chat.d.ts +2 -0
  93. package/dist/providers/azure/chat.js +1 -0
  94. package/dist/providers/azure/responses.d.ts +2 -0
  95. package/dist/providers/azure/responses.js +1 -0
  96. package/dist/providers/azure.d.ts +248 -0
  97. package/dist/providers/azure.js +90 -0
  98. package/dist/providers/cloudflare.d.ts +338 -0
  99. package/dist/providers/cloudflare.js +87 -0
  100. package/dist/providers/google-vertex/chat.d.ts +2 -0
  101. package/dist/providers/google-vertex/chat.js +1 -0
  102. package/dist/providers/google-vertex/gemini.d.ts +2 -0
  103. package/dist/providers/google-vertex/gemini.js +1 -0
  104. package/dist/providers/google-vertex/messages.d.ts +2 -0
  105. package/dist/providers/google-vertex/messages.js +1 -0
  106. package/dist/providers/google-vertex/responses.d.ts +2 -0
  107. package/dist/providers/google-vertex/responses.js +1 -0
  108. package/dist/providers/google-vertex-chat.d.ts +131 -0
  109. package/dist/providers/google-vertex-chat.js +50 -0
  110. package/dist/providers/google-vertex-messages.d.ts +215 -0
  111. package/dist/providers/google-vertex-messages.js +75 -0
  112. package/dist/providers/google-vertex-responses.d.ts +122 -0
  113. package/dist/providers/google-vertex-responses.js +51 -0
  114. package/dist/providers/google-vertex-shared.d.ts +22 -0
  115. package/dist/providers/google-vertex-shared.js +61 -0
  116. package/dist/providers/google-vertex.d.ts +115 -0
  117. package/dist/providers/google-vertex.js +64 -0
  118. package/dist/providers/google.d.ts +112 -0
  119. package/dist/providers/google.js +43 -0
  120. package/dist/providers/index.d.ts +18 -0
  121. package/dist/providers/index.js +18 -0
  122. package/dist/providers/open-responses-options.d.ts +16 -0
  123. package/dist/providers/open-responses-options.js +1 -0
  124. package/dist/providers/openai/chat.d.ts +2 -0
  125. package/dist/providers/openai/chat.js +1 -0
  126. package/dist/providers/openai/responses.d.ts +2 -0
  127. package/dist/providers/openai/responses.js +1 -0
  128. package/dist/providers/openai-compatible/responses.d.ts +1 -0
  129. package/dist/providers/openai-compatible/responses.js +1 -0
  130. package/dist/providers/openai-compatible-profile.d.ts +43 -0
  131. package/dist/providers/openai-compatible-profile.js +12 -0
  132. package/dist/providers/openai-compatible-responses.d.ts +120 -0
  133. package/dist/providers/openai-compatible-responses.js +33 -0
  134. package/dist/providers/openai-compatible.d.ts +167 -0
  135. package/dist/providers/openai-compatible.js +55 -0
  136. package/dist/providers/openai-options.d.ts +21 -0
  137. package/dist/providers/openai-options.js +41 -0
  138. package/dist/providers/openai.d.ts +264 -0
  139. package/dist/providers/openai.js +83 -0
  140. package/dist/providers/openrouter.d.ts +537 -0
  141. package/dist/providers/openrouter.js +117 -0
  142. package/dist/providers/xai.d.ts +249 -0
  143. package/dist/providers/xai.js +79 -0
  144. package/dist/providers/zai.d.ts +24 -0
  145. package/dist/providers/zai.js +21 -0
  146. package/dist/providers.d.ts +1 -0
  147. package/dist/providers.js +1 -0
  148. package/dist/route/auth-options.d.ts +34 -0
  149. package/dist/route/auth-options.js +14 -0
  150. package/dist/route/auth.d.ts +51 -0
  151. package/dist/route/auth.js +89 -0
  152. package/dist/route/client.d.ts +348 -0
  153. package/dist/route/client.js +214 -0
  154. package/dist/route/endpoint.d.ts +28 -0
  155. package/dist/route/endpoint.js +21 -0
  156. package/dist/route/executor.d.ts +23 -0
  157. package/dist/route/executor.js +227 -0
  158. package/dist/route/framing.d.ts +23 -0
  159. package/dist/route/framing.js +4 -0
  160. package/dist/route/index.d.ts +16 -0
  161. package/dist/route/index.js +9 -0
  162. package/dist/route/protocol.d.ts +77 -0
  163. package/dist/route/protocol.js +17 -0
  164. package/dist/route/transport/http.d.ts +34 -0
  165. package/dist/route/transport/http.js +63 -0
  166. package/dist/route/transport/index.d.ts +39 -0
  167. package/dist/route/transport/index.js +4 -0
  168. package/dist/route/transport/websocket-channel.d.ts +56 -0
  169. package/dist/route/transport/websocket-channel.js +1 -0
  170. package/dist/route/transport/websocket.d.ts +55 -0
  171. package/dist/route/transport/websocket.js +326 -0
  172. package/dist/route.d.ts +1 -0
  173. package/dist/route.js +1 -0
  174. package/dist/schema/errors.d.ts +159 -0
  175. package/dist/schema/errors.js +155 -0
  176. package/dist/schema/events.d.ts +4587 -0
  177. package/dist/schema/events.js +492 -0
  178. package/dist/schema/ids.d.ts +30 -0
  179. package/dist/schema/ids.js +19 -0
  180. package/dist/schema/index.d.ts +5 -0
  181. package/dist/schema/index.js +5 -0
  182. package/dist/schema/messages.d.ts +402 -0
  183. package/dist/schema/messages.js +244 -0
  184. package/dist/schema/options.d.ts +159 -0
  185. package/dist/schema/options.js +202 -0
  186. package/dist/testing.d.ts +1493 -0
  187. package/dist/testing.js +88 -0
  188. package/dist/tool-runtime.d.ts +15 -0
  189. package/dist/tool-runtime.js +54 -0
  190. package/dist/tool.d.ts +135 -0
  191. package/dist/tool.js +66 -0
  192. package/dist/utils/record.d.ts +2 -0
  193. package/dist/utils/record.js +2 -0
  194. package/package.json +47 -0
@@ -0,0 +1,43 @@
1
+ import { AwsV4Signer } from "aws4fetch";
2
+ import { Effect } from "effect";
3
+ import { Headers } from "effect/unstable/http";
4
+ import { Auth } from "../../route/auth.js";
5
+ import { ProviderShared } from "../shared.js";
6
+ const signRequest = (input) => Effect.tryPromise({
7
+ try: async () => {
8
+ const signed = await new AwsV4Signer({
9
+ url: input.url,
10
+ method: "POST",
11
+ headers: Object.entries(input.headers),
12
+ body: input.body,
13
+ region: input.credentials.region,
14
+ accessKeyId: input.credentials.accessKeyId,
15
+ secretAccessKey: input.credentials.secretAccessKey,
16
+ sessionToken: input.credentials.sessionToken,
17
+ service: input.service,
18
+ }).sign();
19
+ return Object.fromEntries(signed.headers.entries());
20
+ },
21
+ catch: (error) => ProviderShared.invalidRequest(`${input.name} SigV4 signing failed: ${error instanceof Error ? error.message : String(error)}`),
22
+ });
23
+ /** Sign the exact JSON bytes with SigV4 using credentials configured on the route. */
24
+ export const sigV4 = (credentials, options = {}) => Auth.custom((input) => {
25
+ return Effect.gen(function* () {
26
+ if (!credentials) {
27
+ return yield* ProviderShared.invalidRequest(`${options.name ?? "Bedrock Converse"} requires either route bearer auth or AWS credentials configured on the route`);
28
+ }
29
+ const headersForSigning = Headers.set(input.headers, "content-type", "application/json");
30
+ const signed = yield* signRequest({
31
+ url: input.url,
32
+ body: input.body,
33
+ headers: headersForSigning,
34
+ credentials,
35
+ service: options.service ?? "bedrock",
36
+ name: options.name ?? "Bedrock Converse",
37
+ });
38
+ return Headers.setAll(headersForSigning, signed);
39
+ });
40
+ });
41
+ /** Bedrock route auth defaults to SigV4 and expects credentials from route configuration. */
42
+ export const auth = sigV4(undefined);
43
+ export * as BedrockAuth from "./bedrock-auth.js";
@@ -0,0 +1,15 @@
1
+ import { Schema } from "effect";
2
+ import type { CacheHint } from "../../schema/index.js";
3
+ import { type Breakpoints } from "./cache.js";
4
+ export declare const CachePointBlock: Schema.Struct<{
5
+ readonly cachePoint: Schema.Struct<{
6
+ readonly type: Schema.tag<"default">;
7
+ readonly ttl: Schema.optional<Schema.Literals<readonly ["5m", "1h"]>>;
8
+ }>;
9
+ }>;
10
+ export type CachePointBlock = Schema.Schema.Type<typeof CachePointBlock>;
11
+ export declare const BEDROCK_BREAKPOINT_CAP = 4;
12
+ export type { Breakpoints } from "./cache.js";
13
+ export declare const breakpoints: () => Breakpoints;
14
+ export declare const block: (breakpoints: Breakpoints, cache: CacheHint | undefined) => CachePointBlock | undefined;
15
+ export * as BedrockCache from "./bedrock-cache.js";
@@ -0,0 +1,29 @@
1
+ import { Schema } from "effect";
2
+ import { newBreakpoints, ttlBucket } from "./cache.js";
3
+ // Bedrock cache markers are positional: emit a `cachePoint` block immediately
4
+ // after the content the caller wants treated as a cacheable prefix. Bedrock
5
+ // accepts optional `ttl: "5m" | "1h"` on cachePoint, mirroring Anthropic.
6
+ export const CachePointBlock = Schema.Struct({
7
+ cachePoint: Schema.Struct({
8
+ type: Schema.tag("default"),
9
+ ttl: Schema.optional(Schema.Literals(["5m", "1h"])),
10
+ }),
11
+ });
12
+ // Bedrock-Claude enforces the same 4-breakpoint cap as the Anthropic Messages
13
+ // API. Callers pass a shared counter through every `block()` call site so the
14
+ // budget is respected across `system`, `messages`, and `tools`.
15
+ export const BEDROCK_BREAKPOINT_CAP = 4;
16
+ export const breakpoints = () => newBreakpoints(BEDROCK_BREAKPOINT_CAP);
17
+ const DEFAULT_5M = { cachePoint: { type: "default" } };
18
+ const DEFAULT_1H = { cachePoint: { type: "default", ttl: "1h" } };
19
+ export const block = (breakpoints, cache) => {
20
+ if (cache?.type !== "ephemeral" && cache?.type !== "persistent")
21
+ return undefined;
22
+ if (breakpoints.remaining <= 0) {
23
+ breakpoints.dropped += 1;
24
+ return undefined;
25
+ }
26
+ breakpoints.remaining -= 1;
27
+ return ttlBucket(cache.ttlSeconds) === "1h" ? DEFAULT_1H : DEFAULT_5M;
28
+ };
29
+ export * as BedrockCache from "./bedrock-cache.js";
@@ -0,0 +1,49 @@
1
+ import { Effect, Schema } from "effect";
2
+ export declare const ImageFormat: Schema.Literals<readonly ["png", "jpeg", "gif", "webp"]>;
3
+ export type ImageFormat = Schema.Schema.Type<typeof ImageFormat>;
4
+ export declare const ImageBlock: Schema.Struct<{
5
+ readonly image: Schema.Struct<{
6
+ readonly format: Schema.Literals<readonly ["png", "jpeg", "gif", "webp"]>;
7
+ readonly source: Schema.Struct<{
8
+ readonly bytes: Schema.String;
9
+ }>;
10
+ }>;
11
+ }>;
12
+ export type ImageBlock = Schema.Schema.Type<typeof ImageBlock>;
13
+ export declare const DocumentFormat: Schema.Literals<readonly ["pdf", "csv", "doc", "docx", "xls", "xlsx", "html", "txt", "md"]>;
14
+ export type DocumentFormat = Schema.Schema.Type<typeof DocumentFormat>;
15
+ export declare const DocumentBlock: Schema.Struct<{
16
+ readonly document: Schema.Struct<{
17
+ readonly format: Schema.Literals<readonly ["pdf", "csv", "doc", "docx", "xls", "xlsx", "html", "txt", "md"]>;
18
+ readonly name: Schema.String;
19
+ readonly source: Schema.Struct<{
20
+ readonly bytes: Schema.String;
21
+ }>;
22
+ }>;
23
+ }>;
24
+ export type DocumentBlock = Schema.Schema.Type<typeof DocumentBlock>;
25
+ export declare const lower: (part: {
26
+ readonly data: string | Uint8Array<ArrayBufferLike>;
27
+ readonly type: "media";
28
+ readonly mediaType: string;
29
+ readonly metadata?: {
30
+ readonly [x: string]: unknown;
31
+ } | undefined;
32
+ readonly filename?: string | undefined;
33
+ }) => Effect.Effect<{
34
+ readonly document: {
35
+ readonly format: "pdf" | "csv" | "doc" | "docx" | "xls" | "xlsx" | "html" | "txt" | "md";
36
+ readonly name: string;
37
+ readonly source: {
38
+ readonly bytes: string;
39
+ };
40
+ };
41
+ } | {
42
+ image: {
43
+ format: "png" | "jpeg" | "gif" | "webp";
44
+ source: {
45
+ bytes: string;
46
+ };
47
+ };
48
+ }, import("../../schema/errors.js").AIError, never>;
49
+ export * as BedrockMedia from "./bedrock-media.js";
@@ -0,0 +1,70 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { ProviderShared } from "../shared.js";
3
+ // Bedrock Converse accepts image `format` as the file extension and
4
+ // `source.bytes` as base64 in the JSON wire format.
5
+ export const ImageFormat = Schema.Literals(["png", "jpeg", "gif", "webp"]);
6
+ export const ImageBlock = Schema.Struct({
7
+ image: Schema.Struct({
8
+ format: ImageFormat,
9
+ source: Schema.Struct({ bytes: Schema.String }),
10
+ }),
11
+ });
12
+ // Bedrock document blocks require a user-facing name so the model can refer to
13
+ // the uploaded document.
14
+ export const DocumentFormat = Schema.Literals(["pdf", "csv", "doc", "docx", "xls", "xlsx", "html", "txt", "md"]);
15
+ export const DocumentBlock = Schema.Struct({
16
+ document: Schema.Struct({
17
+ format: DocumentFormat,
18
+ name: Schema.String,
19
+ source: Schema.Struct({ bytes: Schema.String }),
20
+ }),
21
+ });
22
+ const IMAGE_FORMATS = {
23
+ "image/png": "png",
24
+ "image/jpeg": "jpeg",
25
+ "image/jpg": "jpeg",
26
+ "image/gif": "gif",
27
+ "image/webp": "webp",
28
+ };
29
+ const DOCUMENT_FORMATS = {
30
+ "application/pdf": "pdf",
31
+ "text/csv": "csv",
32
+ "application/msword": "doc",
33
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
34
+ "application/vnd.ms-excel": "xls",
35
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
36
+ "text/html": "html",
37
+ "text/plain": "txt",
38
+ "text/markdown": "md",
39
+ };
40
+ const documentBlock = (name, format, bytes) => ({
41
+ document: {
42
+ format,
43
+ name,
44
+ source: { bytes },
45
+ },
46
+ });
47
+ // Route by MIME. Known image/document formats lower into a typed block; anything
48
+ // else fails with a clear error instead of silently degrading to a malformed
49
+ // document block. Image MIME types not in `IMAGE_FORMATS` (e.g. `image/svg+xml`)
50
+ // get an image-specific error so the caller knows it's a format-support issue,
51
+ // not a kind-detection issue.
52
+ export const lower = Effect.fn("BedrockMedia.lower")(function* (part) {
53
+ const mime = part.mediaType.toLowerCase();
54
+ const imageFormat = IMAGE_FORMATS[mime];
55
+ if (imageFormat) {
56
+ const media = yield* ProviderShared.validateMedia("Bedrock Converse", part, new Set(Object.keys(IMAGE_FORMATS)));
57
+ return { image: { format: imageFormat, source: { bytes: media.base64 } } };
58
+ }
59
+ if (mime.startsWith("image/"))
60
+ return yield* ProviderShared.invalidRequest(`Bedrock Converse does not support image media type ${part.mediaType}`);
61
+ const documentFormat = DOCUMENT_FORMATS[mime];
62
+ if (documentFormat) {
63
+ if (!part.filename)
64
+ return yield* ProviderShared.invalidRequest("Bedrock Converse document media requires a filename");
65
+ const media = yield* ProviderShared.validateMedia("Bedrock Converse", part, new Set(Object.keys(DOCUMENT_FORMATS)));
66
+ return documentBlock(part.filename, documentFormat, media.base64);
67
+ }
68
+ return yield* ProviderShared.invalidRequest(`Bedrock Converse does not support media type ${part.mediaType}`);
69
+ });
70
+ export * as BedrockMedia from "./bedrock-media.js";
@@ -0,0 +1,6 @@
1
+ export interface Breakpoints {
2
+ remaining: number;
3
+ dropped: number;
4
+ }
5
+ export declare const newBreakpoints: (cap: number) => Breakpoints;
6
+ export declare const ttlBucket: (ttlSeconds: number | undefined) => "1h" | undefined;
@@ -0,0 +1,8 @@
1
+ // Shared helpers for provider cache-marker lowering. Anthropic and Bedrock
2
+ // both enforce a 4-breakpoint cap per request and accept the same `5m`/`1h`
3
+ // TTL buckets, so the counter and TTL mapping live here.
4
+ export const newBreakpoints = (cap) => ({ remaining: cap, dropped: 0 });
5
+ // Returns `"1h"` for any `ttlSeconds >= 3600`, otherwise `undefined` (the
6
+ // provider default 5m). Anthropic & Bedrock both treat anything shorter than
7
+ // an hour as 5m.
8
+ export const ttlBucket = (ttlSeconds) => ttlSeconds !== undefined && ttlSeconds >= 3600 ? "1h" : undefined;
@@ -0,0 +1,2 @@
1
+ export declare const convert: (schema: unknown) => Record<string, unknown> | undefined;
2
+ export * as GeminiToolSchema from "./gemini-tool-schema.js";
@@ -0,0 +1,103 @@
1
+ import { isRecord } from "../../utils/record.js";
2
+ // Gemini accepts a JSON Schema-like dialect for tool parameters, but rejects a
3
+ // handful of common JSON Schema shapes. Keep this projection isolated so the
4
+ // Gemini protocol file still reads like the other protocol modules.
5
+ const SCHEMA_INTENT_KEYS = [
6
+ "type",
7
+ "properties",
8
+ "items",
9
+ "prefixItems",
10
+ "enum",
11
+ "const",
12
+ "$ref",
13
+ "additionalProperties",
14
+ "patternProperties",
15
+ "required",
16
+ "not",
17
+ "if",
18
+ "then",
19
+ "else",
20
+ ];
21
+ const hasCombiner = (schema) => isRecord(schema) && (Array.isArray(schema.anyOf) || Array.isArray(schema.oneOf) || Array.isArray(schema.allOf));
22
+ const hasSchemaIntent = (schema) => isRecord(schema) && (hasCombiner(schema) || SCHEMA_INTENT_KEYS.some((key) => key in schema));
23
+ const sanitizeNode = (schema) => {
24
+ if (!isRecord(schema))
25
+ return Array.isArray(schema) ? schema.map(sanitizeNode) : schema;
26
+ const result = Object.fromEntries(Object.entries(schema).map(([key, value]) => [
27
+ key,
28
+ key === "enum" && Array.isArray(value) ? value.map(String) : sanitizeNode(value),
29
+ ]));
30
+ if (Array.isArray(result.enum) && (result.type === "integer" || result.type === "number"))
31
+ result.type = "string";
32
+ const properties = result.properties;
33
+ if (result.type === "object" && isRecord(properties) && Array.isArray(result.required)) {
34
+ result.required = result.required.filter((field) => typeof field === "string" && field in properties);
35
+ }
36
+ if (result.type === "array" && !hasCombiner(result)) {
37
+ result.items = result.items ?? {};
38
+ if (isRecord(result.items) && !hasSchemaIntent(result.items))
39
+ result.items = { ...result.items, type: "string" };
40
+ }
41
+ if (typeof result.type === "string" && result.type !== "object" && !hasCombiner(result)) {
42
+ delete result.properties;
43
+ delete result.required;
44
+ }
45
+ return result;
46
+ };
47
+ const emptyObjectSchema = (schema) => schema.type === "object" &&
48
+ (!isRecord(schema.properties) || Object.keys(schema.properties).length === 0) &&
49
+ !schema.additionalProperties;
50
+ const projectNode = (schema, nested = false) => {
51
+ if (!isRecord(schema))
52
+ return undefined;
53
+ if (!nested && emptyObjectSchema(schema))
54
+ return undefined;
55
+ const types = Array.isArray(schema.type) ? schema.type.filter((type) => type !== "null") : undefined;
56
+ const anyOf = Array.isArray(schema.anyOf) ? schema.anyOf : undefined;
57
+ const hasNullAnyOf = anyOf?.some((item) => isRecord(item) && item.type === "null") ?? false;
58
+ const anyOfTypes = hasNullAnyOf ? anyOf?.filter((item) => !isRecord(item) || item.type !== "null") : anyOf;
59
+ const flattenedAnyOf = hasNullAnyOf && anyOfTypes?.length === 1 ? projectNode(anyOfTypes[0], true) : undefined;
60
+ const result = Object.fromEntries([
61
+ ["description", schema.description],
62
+ ["required", schema.required],
63
+ ["format", schema.format],
64
+ ["type", types ? (types.length === 0 ? "null" : undefined) : schema.type],
65
+ [
66
+ "nullable",
67
+ (Array.isArray(schema.type) && schema.type.includes("null") && types && types.length > 0) || hasNullAnyOf
68
+ ? true
69
+ : undefined,
70
+ ],
71
+ ["enum", schema.const !== undefined ? [schema.const] : schema.enum],
72
+ [
73
+ "properties",
74
+ isRecord(schema.properties)
75
+ ? Object.fromEntries(Object.entries(schema.properties).map(([key, value]) => [key, projectNode(value, true)]))
76
+ : undefined,
77
+ ],
78
+ [
79
+ "items",
80
+ Array.isArray(schema.items)
81
+ ? schema.items.map((item) => projectNode(item, true))
82
+ : schema.items === undefined
83
+ ? undefined
84
+ : projectNode(schema.items, true),
85
+ ],
86
+ ["allOf", Array.isArray(schema.allOf) ? schema.allOf.map((item) => projectNode(item, true)) : undefined],
87
+ [
88
+ "anyOf",
89
+ anyOfTypes
90
+ ? hasNullAnyOf && anyOfTypes.length === 1
91
+ ? undefined
92
+ : anyOfTypes.map((item) => projectNode(item, true))
93
+ : types && types.length > 0
94
+ ? types.map((type) => ({ type }))
95
+ : undefined,
96
+ ],
97
+ ["oneOf", Array.isArray(schema.oneOf) ? schema.oneOf.map((item) => projectNode(item, true)) : undefined],
98
+ ["minLength", schema.minLength],
99
+ ].filter((entry) => entry[1] !== undefined));
100
+ return flattenedAnyOf ? { ...result, ...flattenedAnyOf } : result;
101
+ };
102
+ export const convert = (schema) => projectNode(sanitizeNode(schema));
103
+ export * as GeminiToolSchema from "./gemini-tool-schema.js";
@@ -0,0 +1,21 @@
1
+ import { Effect } from "effect";
2
+ import type { ImageInput } from "../../image.js";
3
+ import { AIError } from "../../schema/index.js";
4
+ export declare const dataUrl: (input: Extract<ImageInput, {
5
+ readonly type: "bytes";
6
+ }>) => string;
7
+ export declare const decodeDataUrl: (url: string, module: string) => Effect.Effect<{
8
+ readonly mediaType: string;
9
+ readonly data: Uint8Array;
10
+ } | undefined, AIError>;
11
+ export declare const invalidImageInput: (module: string, message: string) => AIError;
12
+ export declare const ImageInputs: {
13
+ readonly dataUrl: (input: Extract<ImageInput, {
14
+ readonly type: "bytes";
15
+ }>) => string;
16
+ readonly decodeDataUrl: (url: string, module: string) => Effect.Effect<{
17
+ readonly mediaType: string;
18
+ readonly data: Uint8Array;
19
+ } | undefined, AIError>;
20
+ readonly invalid: (module: string, message: string) => AIError;
21
+ };
@@ -0,0 +1,22 @@
1
+ import { Effect, Encoding } from "effect";
2
+ import { InvalidRequestReason, AIError } from "../../schema/index.js";
3
+ const invalid = (module, message) => new AIError({
4
+ module,
5
+ method: "generate",
6
+ reason: new InvalidRequestReason({ message }),
7
+ });
8
+ export const dataUrl = (input) => `data:${input.mediaType};base64,${Encoding.encodeBase64(input.data)}`;
9
+ export const decodeDataUrl = (url, module) => {
10
+ if (!url.startsWith("data:"))
11
+ return Effect.succeed(undefined);
12
+ const match = /^data:([^;,]+);base64,(.*)$/s.exec(url);
13
+ if (!match)
14
+ return Effect.fail(invalid(module, "Image data URLs must contain a MIME type and base64 data"));
15
+ return Effect.fromResult(Encoding.decodeBase64(match[2])).pipe(Effect.mapError(() => invalid(module, "Image data URL contains invalid base64 data")), Effect.map((data) => ({ mediaType: match[1], data })));
16
+ };
17
+ export const invalidImageInput = invalid;
18
+ export const ImageInputs = {
19
+ dataUrl,
20
+ decodeDataUrl,
21
+ invalid: invalidImageInput,
22
+ };
@@ -0,0 +1,20 @@
1
+ import { LLMEvent, type FinishReasonDetails, type ProviderMetadata, type Usage } from "../../schema/index.js";
2
+ export interface State {
3
+ readonly stepStarted: boolean;
4
+ readonly text: ReadonlySet<string>;
5
+ readonly reasoning: ReadonlySet<string>;
6
+ }
7
+ export declare const initial: () => State;
8
+ export declare const stepStart: (state: State, events: LLMEvent[]) => State;
9
+ export declare const textStart: (state: State, events: LLMEvent[], id: string, providerMetadata?: ProviderMetadata) => State;
10
+ export declare const textDelta: (state: State, events: LLMEvent[], id: string, text: string) => State;
11
+ export declare const reasoningStart: (state: State, events: LLMEvent[], id: string, providerMetadata?: ProviderMetadata) => State;
12
+ export declare const reasoningDelta: (state: State, events: LLMEvent[], id: string, text: string, providerMetadata?: ProviderMetadata) => State;
13
+ export declare const reasoningEnd: (state: State, events: LLMEvent[], id: string, providerMetadata?: ProviderMetadata) => State;
14
+ export declare const textEnd: (state: State, events: LLMEvent[], id: string, providerMetadata?: ProviderMetadata) => State;
15
+ export declare const finish: (state: State, events: LLMEvent[], input: {
16
+ readonly reason: FinishReasonDetails;
17
+ readonly usage?: Usage;
18
+ readonly providerMetadata?: ProviderMetadata;
19
+ }) => State;
20
+ export * as Lifecycle from "./lifecycle.js";
@@ -0,0 +1,68 @@
1
+ import { LLMEvent } from "../../schema/index.js";
2
+ export const initial = () => ({ stepStarted: false, text: new Set(), reasoning: new Set() });
3
+ export const stepStart = (state, events) => {
4
+ if (state.stepStarted)
5
+ return state;
6
+ events.push(LLMEvent.stepStart({ index: 0 }));
7
+ return { ...state, stepStarted: true };
8
+ };
9
+ export const textStart = (state, events, id, providerMetadata) => {
10
+ if (state.text.has(id))
11
+ return state;
12
+ const stepped = stepStart(state, events);
13
+ events.push(LLMEvent.textStart({ id, providerMetadata }));
14
+ return { ...stepped, text: new Set([...stepped.text, id]) };
15
+ };
16
+ export const textDelta = (state, events, id, text) => {
17
+ const started = textStart(state, events, id);
18
+ events.push(LLMEvent.textDelta({ id, text }));
19
+ return started;
20
+ };
21
+ export const reasoningStart = (state, events, id, providerMetadata) => {
22
+ if (state.reasoning.has(id))
23
+ return state;
24
+ const stepped = stepStart(state, events);
25
+ events.push(LLMEvent.reasoningStart({ id, providerMetadata }));
26
+ return { ...stepped, reasoning: new Set([...stepped.reasoning, id]) };
27
+ };
28
+ export const reasoningDelta = (state, events, id, text, providerMetadata) => {
29
+ const started = reasoningStart(state, events, id, providerMetadata);
30
+ events.push(LLMEvent.reasoningDelta({ id, text, providerMetadata }));
31
+ return started;
32
+ };
33
+ export const reasoningEnd = (state, events, id, providerMetadata) => {
34
+ if (!state.reasoning.has(id))
35
+ return state;
36
+ const stepped = stepStart(state, events);
37
+ events.push(LLMEvent.reasoningEnd({ id, providerMetadata }));
38
+ const reasoning = new Set(stepped.reasoning);
39
+ reasoning.delete(id);
40
+ return { ...stepped, reasoning };
41
+ };
42
+ export const textEnd = (state, events, id, providerMetadata) => {
43
+ if (!state.text.has(id))
44
+ return state;
45
+ const stepped = stepStart(state, events);
46
+ events.push(LLMEvent.textEnd({ id, providerMetadata }));
47
+ const text = new Set(stepped.text);
48
+ text.delete(id);
49
+ return { ...stepped, text };
50
+ };
51
+ const closeOpenBlocks = (state, events) => {
52
+ for (const id of state.reasoning)
53
+ events.push(LLMEvent.reasoningEnd({ id }));
54
+ for (const id of state.text)
55
+ events.push(LLMEvent.textEnd({ id }));
56
+ return { ...state, text: new Set(), reasoning: new Set() };
57
+ };
58
+ export const finish = (state, events, input) => {
59
+ const stepped = closeOpenBlocks(stepStart(state, events), events);
60
+ events.push(LLMEvent.stepFinish({
61
+ index: 0,
62
+ reason: input.reason,
63
+ usage: input.usage,
64
+ providerMetadata: input.providerMetadata,
65
+ }), LLMEvent.finish(input));
66
+ return { ...stepped, stepStarted: false };
67
+ };
68
+ export * as Lifecycle from "./lifecycle.js";
@@ -0,0 +1,21 @@
1
+ import { Schema } from "effect";
2
+ import { TextVerbosity, type LLMRequest } from "../../schema/index.js";
3
+ export declare const ResponseIncludables: readonly ["file_search_call.results", "web_search_call.results", "web_search_call.action.sources", "message.input_image.image_url", "computer_call_output.output.image_url", "code_interpreter_call.outputs", "reasoning.encrypted_content", "message.output_text.logprobs"];
4
+ export type ResponseIncludable = (typeof ResponseIncludables)[number];
5
+ export declare const ServiceTiers: readonly ["auto", "default", "flex", "priority"];
6
+ export type ServiceTier = (typeof ServiceTiers)[number];
7
+ export declare const ReasoningEffort: Schema.String;
8
+ export declare const TextVerbositySchema: Schema.Literals<readonly ["low", "medium", "high"]>;
9
+ export declare const ResponseIncludableSchema: Schema.Literals<readonly ["file_search_call.results", "web_search_call.results", "web_search_call.action.sources", "message.input_image.image_url", "computer_call_output.output.image_url", "code_interpreter_call.outputs", "reasoning.encrypted_content", "message.output_text.logprobs"]>;
10
+ export declare const ServiceTierSchema: Schema.Literals<readonly ["auto", "default", "flex", "priority"]>;
11
+ export interface Resolved {
12
+ readonly instructions?: string;
13
+ readonly store?: boolean;
14
+ readonly reasoningEffort?: string;
15
+ readonly reasoningSummary?: "auto" | "concise" | "detailed";
16
+ readonly include?: ReadonlyArray<ResponseIncludable>;
17
+ readonly textVerbosity?: Schema.Schema.Type<typeof TextVerbosity>;
18
+ readonly serviceTier?: ServiceTier;
19
+ }
20
+ export declare const resolve: (request: LLMRequest) => Resolved;
21
+ export * as OpenResponsesOptions from "./open-responses-options.js";
@@ -0,0 +1,41 @@
1
+ import { Schema } from "effect";
2
+ import { TextVerbosity } from "../../schema/index.js";
3
+ export const ResponseIncludables = [
4
+ "file_search_call.results",
5
+ "web_search_call.results",
6
+ "web_search_call.action.sources",
7
+ "message.input_image.image_url",
8
+ "computer_call_output.output.image_url",
9
+ "code_interpreter_call.outputs",
10
+ "reasoning.encrypted_content",
11
+ "message.output_text.logprobs",
12
+ ];
13
+ export const ServiceTiers = ["auto", "default", "flex", "priority"];
14
+ const TEXT_VERBOSITY = new Set(["low", "medium", "high"]);
15
+ const INCLUDABLES = new Set(ResponseIncludables);
16
+ const SERVICE_TIERS = new Set(ServiceTiers);
17
+ const isTextVerbosity = (value) => typeof value === "string" && TEXT_VERBOSITY.has(value);
18
+ const isServiceTier = (value) => typeof value === "string" && SERVICE_TIERS.has(value);
19
+ export const ReasoningEffort = Schema.String;
20
+ export const TextVerbositySchema = TextVerbosity;
21
+ export const ResponseIncludableSchema = Schema.Literals(ResponseIncludables);
22
+ export const ServiceTierSchema = Schema.Literals(ServiceTiers);
23
+ export const resolve = (request) => {
24
+ const input = request.providerOptions?.[request.model.route.providerMetadataKey ?? "openresponses"];
25
+ const include = Array.isArray(input?.include)
26
+ ? input.include.filter((entry) => INCLUDABLES.has(entry))
27
+ : [];
28
+ const reasoningSummary = input?.reasoningSummary;
29
+ return {
30
+ instructions: typeof input?.instructions === "string" ? input.instructions : undefined,
31
+ store: typeof input?.store === "boolean" ? input.store : undefined,
32
+ reasoningEffort: typeof input?.reasoningEffort === "string" ? input.reasoningEffort : undefined,
33
+ reasoningSummary: reasoningSummary === "auto" || reasoningSummary === "concise" || reasoningSummary === "detailed"
34
+ ? reasoningSummary
35
+ : undefined,
36
+ include: include.length > 0 ? include : undefined,
37
+ textVerbosity: isTextVerbosity(input?.textVerbosity) ? input.textVerbosity : undefined,
38
+ serviceTier: isServiceTier(input?.serviceTier) ? input.serviceTier : undefined,
39
+ };
40
+ };
41
+ export * as OpenResponsesOptions from "./open-responses-options.js";
@@ -0,0 +1,5 @@
1
+ import { Schema } from "effect";
2
+ export declare const Size: Schema.String;
3
+ export declare const OpenAIImage: {
4
+ readonly Size: Schema.String;
5
+ };
@@ -0,0 +1,18 @@
1
+ import { Schema } from "effect";
2
+ const dimensions = (value) => {
3
+ const match = /^(\d+)x(\d+)$/.exec(value);
4
+ if (!match)
5
+ return undefined;
6
+ return { width: Number(match[1]), height: Number(match[2]) };
7
+ };
8
+ export const Size = Schema.String.check(Schema.makeFilter((value) => {
9
+ if (value === "auto")
10
+ return undefined;
11
+ const parsed = dimensions(value);
12
+ if (!parsed)
13
+ return "image size must be `auto` or `{width}x{height}`";
14
+ return parsed.width > 0 && parsed.height > 0 ? undefined : "image dimensions must be positive integers";
15
+ }));
16
+ export const OpenAIImage = {
17
+ Size,
18
+ };
@@ -0,0 +1,14 @@
1
+ import { OpenResponsesOptions } from "./open-responses-options.js";
2
+ export declare const OpenAIReasoningEfforts: readonly ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
3
+ export type OpenAIReasoningEffort = string;
4
+ export declare const OpenAIResponseIncludables: readonly ["file_search_call.results", "web_search_call.results", "web_search_call.action.sources", "message.input_image.image_url", "computer_call_output.output.image_url", "code_interpreter_call.outputs", "reasoning.encrypted_content", "message.output_text.logprobs"];
5
+ export type OpenAIResponseIncludable = OpenResponsesOptions.ResponseIncludable;
6
+ export declare const OpenAIServiceTiers: readonly ["auto", "default", "flex", "priority"];
7
+ export type OpenAIServiceTier = OpenResponsesOptions.ServiceTier;
8
+ export declare const OpenAIReasoningEffort: import("effect/Schema").String;
9
+ export declare const OpenAITextVerbosity: import("effect/Schema").Literals<readonly ["low", "medium", "high"]>;
10
+ export declare const OpenAIResponseIncludable: import("effect/Schema").Literals<readonly ["file_search_call.results", "web_search_call.results", "web_search_call.action.sources", "message.input_image.image_url", "computer_call_output.output.image_url", "code_interpreter_call.outputs", "reasoning.encrypted_content", "message.output_text.logprobs"]>;
11
+ export declare const OpenAIServiceTier: import("effect/Schema").Literals<readonly ["auto", "default", "flex", "priority"]>;
12
+ export declare const isReasoningEffort: (effort: unknown) => effort is OpenAIReasoningEffort;
13
+ export declare const resolve: (request: import("../../schema/messages.js").LLMRequest) => OpenResponsesOptions.Resolved;
14
+ export * as OpenAIOptions from "./openai-options.js";
@@ -0,0 +1,14 @@
1
+ import { ReasoningEfforts } from "../../schema/index.js";
2
+ import { OpenResponsesOptions } from "./open-responses-options.js";
3
+ export const OpenAIReasoningEfforts = ReasoningEfforts;
4
+ // Mirrors OpenAI's `ResponseIncludable` union from the official SDK. Keep this
5
+ // in lockstep with `openai-node/src/resources/responses/responses.ts`.
6
+ export const OpenAIResponseIncludables = OpenResponsesOptions.ResponseIncludables;
7
+ export const OpenAIServiceTiers = OpenResponsesOptions.ServiceTiers;
8
+ export const OpenAIReasoningEffort = OpenResponsesOptions.ReasoningEffort;
9
+ export const OpenAITextVerbosity = OpenResponsesOptions.TextVerbositySchema;
10
+ export const OpenAIResponseIncludable = OpenResponsesOptions.ResponseIncludableSchema;
11
+ export const OpenAIServiceTier = OpenResponsesOptions.ServiceTierSchema;
12
+ export const isReasoningEffort = (effort) => typeof effort === "string";
13
+ export const resolve = OpenResponsesOptions.resolve;
14
+ export * as OpenAIOptions from "./openai-options.js";
@@ -0,0 +1,8 @@
1
+ import type { JsonSchema, LanguageModelToolSchemaCompatibility } from "../../schema/index.js";
2
+ export declare const ToolSchemaProjection: {
3
+ readonly gemini: (schema: JsonSchema) => JsonSchema;
4
+ readonly modelCompatibility: (schema: JsonSchema, compatibility: LanguageModelToolSchemaCompatibility | undefined) => JsonSchema;
5
+ readonly moonshot: (schema: JsonSchema) => JsonSchema;
6
+ readonly openAI: (schema: JsonSchema) => JsonSchema;
7
+ readonly responses: (schema: JsonSchema) => JsonSchema;
8
+ };