@opencode/ai 2.0.15 → 2.0.16
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 +286 -2
- package/dist/generation.d.ts +36 -22
- package/dist/generation.js +53 -24
- package/dist/image-client.d.ts +14 -7
- package/dist/image-client.js +24 -8
- package/dist/image.d.ts +398 -47
- package/dist/image.js +47 -45
- package/dist/index.d.ts +13 -1
- package/dist/index.js +9 -0
- package/dist/media-model.d.ts +44 -0
- package/dist/media-model.js +49 -0
- package/dist/media.d.ts +10 -9
- package/dist/media.js +9 -10
- package/dist/promise.d.ts +428 -8
- package/dist/promise.js +40 -3
- package/dist/protocols/alibaba-chat.d.ts +12 -0
- package/dist/protocols/alibaba-responses.d.ts +2 -2
- package/dist/protocols/anthropic-messages.js +1 -2
- package/dist/protocols/assemblyai-transcription.d.ts +40 -0
- package/dist/protocols/assemblyai-transcription.js +138 -0
- package/dist/protocols/bedrock-converse.js +5 -11
- package/dist/protocols/bfl-images.d.ts +32 -0
- package/dist/protocols/bfl-images.js +153 -0
- package/dist/protocols/cartesia-speech.d.ts +127 -0
- package/dist/protocols/cartesia-speech.js +126 -0
- package/dist/protocols/deepgram-speech.d.ts +119 -0
- package/dist/protocols/deepgram-speech.js +92 -0
- package/dist/protocols/deepgram-transcription.d.ts +25 -0
- package/dist/protocols/deepgram-transcription.js +129 -0
- package/dist/protocols/elevenlabs-speech.d.ts +122 -0
- package/dist/protocols/elevenlabs-speech.js +115 -0
- package/dist/protocols/fal-images.d.ts +24 -0
- package/dist/protocols/fal-images.js +114 -0
- package/dist/protocols/fal-video.d.ts +29 -0
- package/dist/protocols/fal-video.js +88 -0
- package/dist/protocols/gemini.d.ts +9 -9
- package/dist/protocols/gemini.js +8 -34
- package/dist/protocols/google-images.js +2 -14
- package/dist/protocols/google-speech.d.ts +130 -0
- package/dist/protocols/google-speech.js +84 -0
- package/dist/protocols/google-transcription.d.ts +173 -0
- package/dist/protocols/google-transcription.js +138 -0
- package/dist/protocols/google-video.d.ts +26 -0
- package/dist/protocols/google-video.js +158 -0
- package/dist/protocols/meta-images.js +2 -9
- package/dist/protocols/meta-responses.d.ts +4 -4
- package/dist/protocols/meta-responses.js +1 -1
- package/dist/protocols/open-responses.d.ts +6 -6
- package/dist/protocols/open-responses.js +1 -2
- package/dist/protocols/openai-chat.d.ts +84 -0
- package/dist/protocols/openai-chat.js +26 -14
- package/dist/protocols/openai-compatible-chat.d.ts +12 -0
- package/dist/protocols/openai-compatible-responses.d.ts +2 -2
- package/dist/protocols/openai-images.d.ts +124 -3
- package/dist/protocols/openai-images.js +107 -54
- package/dist/protocols/openai-responses.d.ts +15 -15
- package/dist/protocols/openai-responses.js +5 -6
- package/dist/protocols/openai-speech.d.ts +116 -0
- package/dist/protocols/openai-speech.js +98 -0
- package/dist/protocols/openai-transcription.d.ts +207 -0
- package/dist/protocols/openai-transcription.js +190 -0
- package/dist/protocols/replicate-images.d.ts +28 -0
- package/dist/protocols/replicate-images.js +133 -0
- package/dist/protocols/runway-video.d.ts +38 -0
- package/dist/protocols/runway-video.js +146 -0
- package/dist/protocols/shared.d.ts +13 -3
- package/dist/protocols/shared.js +23 -3
- package/dist/protocols/stability-images.d.ts +38 -0
- package/dist/protocols/stability-images.js +148 -0
- package/dist/protocols/utils/fal-queue.d.ts +28 -0
- package/dist/protocols/utils/fal-queue.js +69 -0
- package/dist/protocols/utils/gemini-generate-content.d.ts +65 -0
- package/dist/protocols/utils/gemini-generate-content.js +65 -0
- package/dist/protocols/utils/gemini-json-schema.d.ts +3 -0
- package/dist/protocols/utils/gemini-json-schema.js +76 -0
- package/dist/protocols/utils/media-input.d.ts +8 -0
- package/dist/protocols/utils/media-input.js +18 -0
- package/dist/protocols/utils/speech-stream.d.ts +49 -0
- package/dist/protocols/utils/speech-stream.js +67 -0
- package/dist/protocols/utils/tool-schema.d.ts +2 -2
- package/dist/protocols/utils/tool-schema.js +40 -17
- package/dist/protocols/xai-images.js +1 -12
- package/dist/protocols/xai-responses.d.ts +2 -2
- package/dist/protocols/xai-video.d.ts +34 -0
- package/dist/protocols/xai-video.js +147 -0
- package/dist/protocols/zai-chat.d.ts +13 -1
- package/dist/provider-error.js +3 -0
- package/dist/providers/alibaba.d.ts +14 -2
- package/dist/providers/amazon-bedrock-mantle.d.ts +14 -2
- package/dist/providers/assemblyai.d.ts +25 -0
- package/dist/providers/assemblyai.js +29 -0
- package/dist/providers/azure.d.ts +18 -6
- package/dist/providers/baseten.d.ts +24 -0
- package/dist/providers/black-forest-labs.d.ts +25 -0
- package/dist/providers/black-forest-labs.js +28 -0
- package/dist/providers/cartesia.d.ts +24 -0
- package/dist/providers/cartesia.js +22 -0
- package/dist/providers/cerebras.d.ts +24 -0
- package/dist/providers/cloudflare-ai-gateway.d.ts +30 -6
- package/dist/providers/cloudflare-workers-ai.d.ts +24 -0
- package/dist/providers/deepgram.d.ts +29 -0
- package/dist/providers/deepgram.js +31 -0
- package/dist/providers/deepinfra.d.ts +24 -0
- package/dist/providers/deepseek.d.ts +24 -0
- package/dist/providers/elevenlabs.d.ts +24 -0
- package/dist/providers/elevenlabs.js +28 -0
- package/dist/providers/fal.d.ts +29 -0
- package/dist/providers/fal.js +33 -0
- package/dist/providers/fireworks.d.ts +24 -0
- package/dist/providers/google-vertex-chat.d.ts +12 -0
- package/dist/providers/google-vertex-responses.d.ts +2 -2
- package/dist/providers/google-vertex.d.ts +3 -3
- package/dist/providers/google.d.ts +18 -3
- package/dist/providers/google.js +11 -2
- package/dist/providers/groq.d.ts +24 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/meta.d.ts +14 -2
- package/dist/providers/minimax.d.ts +14 -2
- package/dist/providers/moonshot.d.ts +14 -2
- package/dist/providers/moonshot.js +3 -3
- package/dist/providers/openai-compatible-responses.d.ts +2 -2
- package/dist/providers/openai-compatible.d.ts +12 -0
- package/dist/providers/openai.d.ts +25 -3
- package/dist/providers/openai.js +10 -1
- package/dist/providers/openrouter.d.ts +48 -0
- package/dist/providers/replicate.d.ts +25 -0
- package/dist/providers/replicate.js +22 -0
- package/dist/providers/runway.d.ts +24 -0
- package/dist/providers/runway.js +22 -0
- package/dist/providers/stability.d.ts +28 -0
- package/dist/providers/stability.js +23 -0
- package/dist/providers/togetherai.d.ts +24 -0
- package/dist/providers/xai.d.ts +17 -0
- package/dist/providers/xai.js +5 -2
- package/dist/providers/zai-coding-plan.d.ts +15 -3
- package/dist/providers/zai.d.ts +13 -1
- package/dist/route/auth.d.ts +4 -1
- package/dist/route/auth.js +6 -0
- package/dist/route/framing.d.ts +5 -1
- package/dist/route/framing.js +9 -0
- package/dist/route/media-protocol.d.ts +116 -3
- package/dist/route/media-protocol.js +60 -4
- package/dist/route/media.d.ts +58 -7
- package/dist/route/media.js +201 -29
- package/dist/schema/events.d.ts +0 -6
- package/dist/schema/messages.d.ts +0 -3
- package/dist/schema/options.d.ts +4 -3
- package/dist/schema/options.js +3 -2
- package/dist/speech-client.d.ts +21 -0
- package/dist/speech-client.js +25 -0
- package/dist/speech.d.ts +1150 -0
- package/dist/speech.js +119 -0
- package/dist/transcription-client.d.ts +28 -0
- package/dist/transcription-client.js +44 -0
- package/dist/transcription.d.ts +1504 -0
- package/dist/transcription.js +133 -0
- package/dist/utils/bytes.d.ts +1 -0
- package/dist/utils/bytes.js +10 -0
- package/dist/utils/media-type.d.ts +1 -0
- package/dist/utils/media-type.js +22 -1
- package/dist/video-client.d.ts +28 -0
- package/dist/video-client.js +40 -0
- package/dist/video.d.ts +1359 -0
- package/dist/video.js +119 -0
- package/package.json +3 -3
- package/dist/protocols/utils/gemini-tool-schema.d.ts +0 -2
- package/dist/protocols/utils/gemini-tool-schema.js +0 -103
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { isRecord } from "../../utils/record.js";
|
|
2
|
+
// Gemini's `parametersJsonSchema` accepts standard JSON Schema, but rejects a few shapes that
|
|
3
|
+
// published tool schemas commonly contain. Rewrite only those and send everything else unchanged.
|
|
4
|
+
const SCHEMA_MAPS = new Set([
|
|
5
|
+
"properties",
|
|
6
|
+
"patternProperties",
|
|
7
|
+
"$defs",
|
|
8
|
+
"definitions",
|
|
9
|
+
"dependentSchemas",
|
|
10
|
+
"dependencies",
|
|
11
|
+
]);
|
|
12
|
+
const VALUES = new Set(["const", "default", "enum", "examples", "dependentRequired"]);
|
|
13
|
+
const mapValues = (record, map) => Object.fromEntries(Object.entries(record).map(([key, value]) => [key, map(value, key)]));
|
|
14
|
+
const normalizeNode = (schema) => {
|
|
15
|
+
if (Array.isArray(schema))
|
|
16
|
+
return schema.map(normalizeNode);
|
|
17
|
+
if (!isRecord(schema))
|
|
18
|
+
return schema;
|
|
19
|
+
const properties = isRecord(schema.properties) ? schema.properties : undefined;
|
|
20
|
+
return Object.fromEntries(Object.entries(schema).flatMap(([key, value]) => {
|
|
21
|
+
if (VALUES.has(key))
|
|
22
|
+
return [[key, value]];
|
|
23
|
+
if (SCHEMA_MAPS.has(key) && isRecord(value))
|
|
24
|
+
return [[key, mapValues(value, normalizeNode)]];
|
|
25
|
+
// `required` may only name declared properties.
|
|
26
|
+
if (key === "required" && properties && Array.isArray(value))
|
|
27
|
+
return [[key, value.filter((name) => typeof name === "string" && Object.hasOwn(properties, name))]];
|
|
28
|
+
// Draft-04 boolean exclusive bounds become the numeric form.
|
|
29
|
+
if (key === "exclusiveMinimum" && typeof value === "boolean")
|
|
30
|
+
return value && typeof schema.minimum === "number" ? [[key, schema.minimum]] : [];
|
|
31
|
+
if (key === "exclusiveMaximum" && typeof value === "boolean")
|
|
32
|
+
return value && typeof schema.maximum === "number" ? [[key, schema.maximum]] : [];
|
|
33
|
+
if (key === "minimum" && schema.exclusiveMinimum === true)
|
|
34
|
+
return [];
|
|
35
|
+
if (key === "maximum" && schema.exclusiveMaximum === true)
|
|
36
|
+
return [];
|
|
37
|
+
// Draft-07 tuples (`items` array plus `additionalItems`) are `prefixItems` plus `items` in 2020-12.
|
|
38
|
+
if (key === "items" && Array.isArray(value))
|
|
39
|
+
return [["prefixItems", value.map(normalizeNode)]];
|
|
40
|
+
if (key === "additionalItems" && Array.isArray(schema.items))
|
|
41
|
+
return [["items", normalizeNode(value)]];
|
|
42
|
+
return [[key, normalizeNode(value)]];
|
|
43
|
+
}));
|
|
44
|
+
};
|
|
45
|
+
// Gemini accepts a recursive `$ref` only when the loop passes through an optional property or
|
|
46
|
+
// potentially empty array `items`. Replace other self-references with an unconstrained schema.
|
|
47
|
+
const cutLoops = (schema, target, safe) => {
|
|
48
|
+
if (Array.isArray(schema))
|
|
49
|
+
return schema.map((item) => cutLoops(item, target, safe));
|
|
50
|
+
if (!isRecord(schema))
|
|
51
|
+
return schema;
|
|
52
|
+
if (schema.$ref === target && !safe)
|
|
53
|
+
return {};
|
|
54
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
55
|
+
return mapValues(schema, (value, key) => {
|
|
56
|
+
if (VALUES.has(key))
|
|
57
|
+
return value;
|
|
58
|
+
if (key === "items")
|
|
59
|
+
return cutLoops(value, target, safe || !(Number(schema.minItems) > 0));
|
|
60
|
+
if (key === "properties" && isRecord(value))
|
|
61
|
+
return mapValues(value, (child, name) => cutLoops(child, target, safe || !required.includes(name)));
|
|
62
|
+
if (SCHEMA_MAPS.has(key) && isRecord(value))
|
|
63
|
+
return mapValues(value, (child) => cutLoops(child, target, safe));
|
|
64
|
+
return cutLoops(value, target, safe);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
export const normalize = (schema) => {
|
|
68
|
+
const normalized = normalizeNode(schema);
|
|
69
|
+
if (!isRecord(normalized))
|
|
70
|
+
return {};
|
|
71
|
+
const result = cutLoops(mapValues(normalized, (value, key) => (key === "$defs" || key === "definitions") && isRecord(value)
|
|
72
|
+
? mapValues(value, (def, name) => cutLoops(def, `#/${key}/${name}`, false))
|
|
73
|
+
: value), "#", false);
|
|
74
|
+
return isRecord(result) ? result : {};
|
|
75
|
+
};
|
|
76
|
+
export * as GeminiJsonSchema from "./gemini-json-schema.js";
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { Media } from "../../media.js";
|
|
3
|
+
import type { MediaProtocol } from "../../route/media-protocol.js";
|
|
3
4
|
import type { AIError, ProviderID } from "../../schema/index.js";
|
|
4
5
|
/** Owned bytes for multipart uploads; decodes `base64` sources and rejects remote sources. */
|
|
5
6
|
export declare const inlineBytes: (route: string, asset: Media.Asset) => Effect.Effect<Uint8Array, AIError>;
|
|
7
|
+
/** Copied because `BlobPart` requires a plain `ArrayBuffer`. */
|
|
8
|
+
export declare const blob: (data: Uint8Array, mediaType: string) => Blob;
|
|
9
|
+
export declare const query: (route: string, values: Record<string, unknown>) => Effect.Effect<MediaProtocol.Query, AIError>;
|
|
10
|
+
export declare const dimensions: (size: string) => {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
6
14
|
/** Provider file handle when the ref belongs to this provider; refs from other providers are never forwarded. */
|
|
7
15
|
export declare const refID: (asset: Media.Asset, provider: ProviderID) => string | undefined;
|
|
8
16
|
/** Decode a provider's base64 output once into an owned `bytes` asset, sniffing the type when it is not declared. */
|
|
@@ -10,6 +10,24 @@ export const inlineBytes = (route, asset) => {
|
|
|
10
10
|
return Effect.fail(ProviderShared.inlineRequired(route, asset));
|
|
11
11
|
return Effect.fromResult(Encoding.decodeBase64(inline.base64)).pipe(Effect.mapError((cause) => ProviderShared.invalidRequest(`${route} media contains invalid base64 data`, cause)));
|
|
12
12
|
};
|
|
13
|
+
/** Copied because `BlobPart` requires a plain `ArrayBuffer`. */
|
|
14
|
+
export const blob = (data, mediaType) => {
|
|
15
|
+
const buffer = new ArrayBuffer(data.byteLength);
|
|
16
|
+
new Uint8Array(buffer).set(data);
|
|
17
|
+
return new Blob([buffer], { type: mediaType });
|
|
18
|
+
};
|
|
19
|
+
const isScalar = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
20
|
+
export const query = (route, values) => {
|
|
21
|
+
const entries = Object.entries(values).filter(([, value]) => value !== undefined);
|
|
22
|
+
const invalid = entries.find(([, value]) => !isScalar(value) && !(Array.isArray(value) && value.every(isScalar)));
|
|
23
|
+
if (invalid !== undefined)
|
|
24
|
+
return Effect.fail(ProviderShared.invalidRequest(`${route} cannot send "${invalid[0]}" as a query parameter`));
|
|
25
|
+
return Effect.succeed(Object.fromEntries(entries.map(([key, value]) => [key, Array.isArray(value) ? value.map(String) : String(value)])));
|
|
26
|
+
};
|
|
27
|
+
export const dimensions = (size) => {
|
|
28
|
+
const [width, height] = size.split("x").map(Number);
|
|
29
|
+
return { width, height };
|
|
30
|
+
};
|
|
13
31
|
/** Provider file handle when the ref belongs to this provider; refs from other providers are never forwarded. */
|
|
14
32
|
export const refID = (asset, provider) => asset.source.type === "ref" && asset.source.provider === provider ? asset.source.id : undefined;
|
|
15
33
|
/** Decode a provider's base64 output once into an owned `bytes` asset, sniffing the type when it is not declared. */
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Media } from "../../media.js";
|
|
3
|
+
import type { AIError, MediaUsage, ProviderID, ProviderMetadata } from "../../schema/index.js";
|
|
4
|
+
import { type SpeechEvent, type SpeechVoice } from "../../speech.js";
|
|
5
|
+
export interface Audio {
|
|
6
|
+
/** Appended in place: the route creates fresh state for each response through `initial`. */
|
|
7
|
+
readonly chunks: Array<Uint8Array>;
|
|
8
|
+
}
|
|
9
|
+
export type StepResult<State> = readonly [State, ReadonlyArray<SpeechEvent>];
|
|
10
|
+
/** Empty chunks (keep-alive records) emit nothing. */
|
|
11
|
+
export declare const delta: <State extends Audio>(state: State, chunk: Uint8Array) => StepResult<State>;
|
|
12
|
+
export declare const step: <State extends Audio>(onRecord: (state: State, frame: string) => Effect.Effect<StepResult<State>, AIError>) => (state: State, frame: string | Uint8Array) => Effect.Effect<StepResult<State>, AIError, never>;
|
|
13
|
+
export declare const timestamps: (texts: ReadonlyArray<string>, starts: ReadonlyArray<number>, ends: ReadonlyArray<number>) => ReadonlyArray<SpeechEvent>;
|
|
14
|
+
export declare const voiceID: (voice: SpeechVoice | undefined) => string | undefined;
|
|
15
|
+
export declare const container: (format: string, sampleRate?: number) => {
|
|
16
|
+
mediaType: string;
|
|
17
|
+
info: {
|
|
18
|
+
format: string;
|
|
19
|
+
sampleRate: number | undefined;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
declare const PCM_MEDIA_TYPES: {
|
|
23
|
+
readonly pcm_s16le: "audio/pcm";
|
|
24
|
+
readonly pcm_f32le: "audio/pcm";
|
|
25
|
+
readonly pcm_mulaw: "audio/mulaw";
|
|
26
|
+
readonly pcm_alaw: "audio/alaw";
|
|
27
|
+
};
|
|
28
|
+
export type PcmEncoding = keyof typeof PCM_MEDIA_TYPES;
|
|
29
|
+
export declare const pcm: (encoding: PcmEncoding, sampleRate: number | undefined, mediaType?: string) => {
|
|
30
|
+
mediaType: string;
|
|
31
|
+
info: {
|
|
32
|
+
format: string;
|
|
33
|
+
encoding: "pcm_s16le" | "pcm_f32le" | "pcm_mulaw" | "pcm_alaw";
|
|
34
|
+
sampleRate: number | undefined;
|
|
35
|
+
channels: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export declare const sampleRate: (mediaType: string | undefined) => number | undefined;
|
|
39
|
+
export declare const unsupportedFormat: (provider: ProviderID, route: string, message: string) => AIError;
|
|
40
|
+
/** A declared `mediaType` wins over sniffing: headerless PCM can start with bytes that look like an MPEG frame sync. */
|
|
41
|
+
export declare const finish: (route: string, state: Audio, output: {
|
|
42
|
+
readonly mediaType: string | undefined;
|
|
43
|
+
readonly info?: Media.Info;
|
|
44
|
+
readonly usage?: MediaUsage;
|
|
45
|
+
readonly providerMetadata?: ProviderMetadata;
|
|
46
|
+
readonly detail?: string;
|
|
47
|
+
}) => Effect.Effect<ReadonlyArray<SpeechEvent>, AIError>;
|
|
48
|
+
export declare const headerUsage: (type: "characters" | "credits", value: string | undefined) => MediaUsage | undefined;
|
|
49
|
+
export * as SpeechStream from "./speech-stream.js";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Media } from "../../media.js";
|
|
3
|
+
import { MediaProtocol } from "../../route/media-protocol.js";
|
|
4
|
+
import { SpeechAudioDeltaEvent, SpeechFinishEvent, SpeechTimestampsEvent, } from "../../speech.js";
|
|
5
|
+
import { concatBytes } from "../../utils/bytes.js";
|
|
6
|
+
import { ProviderShared } from "../shared.js";
|
|
7
|
+
/** Empty chunks (keep-alive records) emit nothing. */
|
|
8
|
+
export const delta = (state, chunk) => {
|
|
9
|
+
if (chunk.length === 0)
|
|
10
|
+
return [state, []];
|
|
11
|
+
state.chunks.push(chunk);
|
|
12
|
+
return [state, [SpeechAudioDeltaEvent.make({ chunk })]];
|
|
13
|
+
};
|
|
14
|
+
export const step = (onRecord) => (state, frame) => typeof frame === "string" ? onRecord(state, frame) : Effect.succeed(delta(state, frame));
|
|
15
|
+
export const timestamps = (texts, starts, ends) => texts.length === 0
|
|
16
|
+
? []
|
|
17
|
+
: [
|
|
18
|
+
SpeechTimestampsEvent.make({
|
|
19
|
+
items: texts.map((text, index) => ({ text, startSeconds: starts[index] ?? 0, endSeconds: ends[index] ?? 0 })),
|
|
20
|
+
}),
|
|
21
|
+
];
|
|
22
|
+
export const voiceID = (voice) => (typeof voice === "object" ? voice.id : voice);
|
|
23
|
+
const CONTAINER_MEDIA_TYPES = {
|
|
24
|
+
mp3: "audio/mpeg",
|
|
25
|
+
wav: "audio/wav",
|
|
26
|
+
opus: "audio/ogg",
|
|
27
|
+
aac: "audio/aac",
|
|
28
|
+
flac: "audio/flac",
|
|
29
|
+
};
|
|
30
|
+
export const container = (format, sampleRate) => ({
|
|
31
|
+
mediaType: CONTAINER_MEDIA_TYPES[format],
|
|
32
|
+
info: { format, sampleRate },
|
|
33
|
+
});
|
|
34
|
+
const PCM_MEDIA_TYPES = {
|
|
35
|
+
pcm_s16le: "audio/pcm",
|
|
36
|
+
pcm_f32le: "audio/pcm",
|
|
37
|
+
pcm_mulaw: "audio/mulaw",
|
|
38
|
+
pcm_alaw: "audio/alaw",
|
|
39
|
+
};
|
|
40
|
+
export const pcm = (encoding, sampleRate, mediaType) => ({
|
|
41
|
+
mediaType: mediaType ?? PCM_MEDIA_TYPES[encoding],
|
|
42
|
+
info: { format: "pcm", encoding, sampleRate, channels: 1 },
|
|
43
|
+
});
|
|
44
|
+
export const sampleRate = (mediaType) => {
|
|
45
|
+
const rate = /rate=(\d+)/i.exec(mediaType ?? "")?.[1];
|
|
46
|
+
return rate === undefined ? undefined : Number(rate);
|
|
47
|
+
};
|
|
48
|
+
export const unsupportedFormat = (provider, route, message) => ProviderShared.unsupportedOperation({ operation: "media.format", provider, route, message });
|
|
49
|
+
/** A declared `mediaType` wins over sniffing: headerless PCM can start with bytes that look like an MPEG frame sync. */
|
|
50
|
+
export const finish = (route, state, output) => {
|
|
51
|
+
if (state.chunks.length === 0)
|
|
52
|
+
return Effect.fail(MediaProtocol.frameError(route, `The provider returned no audio${output.detail === undefined ? "" : ` (${output.detail})`}`));
|
|
53
|
+
return Effect.succeed([
|
|
54
|
+
SpeechFinishEvent.make({
|
|
55
|
+
audio: Media.bytes(concatBytes(state.chunks), output.mediaType, { info: output.info }),
|
|
56
|
+
usage: output.usage,
|
|
57
|
+
providerMetadata: output.providerMetadata,
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
60
|
+
};
|
|
61
|
+
export const headerUsage = (type, value) => {
|
|
62
|
+
const amount = Number(value);
|
|
63
|
+
if (!Number.isFinite(amount))
|
|
64
|
+
return undefined;
|
|
65
|
+
return type === "credits" ? { type, credits: amount } : { type, characters: amount };
|
|
66
|
+
};
|
|
67
|
+
export * as SpeechStream from "./speech-stream.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { JsonSchema,
|
|
1
|
+
import type { JsonSchema, LanguageModel, LanguageModelSanitizerCompatibility } from "../../schema/index.js";
|
|
2
2
|
export declare const ToolSchemaProjection: {
|
|
3
3
|
readonly gemini: (schema: JsonSchema) => JsonSchema;
|
|
4
|
-
readonly modelCompatibility: (schema: JsonSchema,
|
|
4
|
+
readonly modelCompatibility: (schema: JsonSchema, model: LanguageModel, protocolDefault?: LanguageModelSanitizerCompatibility) => JsonSchema;
|
|
5
5
|
readonly moonshot: (schema: JsonSchema) => JsonSchema;
|
|
6
6
|
readonly openAI: (schema: JsonSchema) => JsonSchema;
|
|
7
7
|
readonly responses: (schema: JsonSchema) => JsonSchema;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isRecord } from "../../utils/record.js";
|
|
2
|
-
import {
|
|
2
|
+
import { GeminiJsonSchema } from "./gemini-json-schema.js";
|
|
3
3
|
const tupleItemsSchema = (items) => {
|
|
4
4
|
const projected = items.map(moonshotNode);
|
|
5
5
|
if (projected.length === 0)
|
|
@@ -8,6 +8,17 @@ const tupleItemsSchema = (items) => {
|
|
|
8
8
|
return projected[0];
|
|
9
9
|
return { anyOf: projected };
|
|
10
10
|
};
|
|
11
|
+
// Moonshot rejects an `enum` without a sibling `type`. Its `type` may be one type, or one type plus "null".
|
|
12
|
+
const enumType = (values) => {
|
|
13
|
+
const types = [
|
|
14
|
+
...new Set(values.map((value) => (value === null ? "null" : Array.isArray(value) ? "array" : typeof value))),
|
|
15
|
+
];
|
|
16
|
+
if (types.length === 1)
|
|
17
|
+
return types[0];
|
|
18
|
+
if (types.length === 2 && types.includes("null"))
|
|
19
|
+
return [...types.filter((type) => type !== "null"), "null"];
|
|
20
|
+
return undefined;
|
|
21
|
+
};
|
|
11
22
|
const moonshotNode = (schema) => {
|
|
12
23
|
if (Array.isArray(schema))
|
|
13
24
|
return schema.map(moonshotNode);
|
|
@@ -15,18 +26,22 @@ const moonshotNode = (schema) => {
|
|
|
15
26
|
return schema;
|
|
16
27
|
if (typeof schema.$ref === "string")
|
|
17
28
|
return { $ref: schema.$ref };
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if ("items"
|
|
29
|
+
const type = schema.type === undefined && Array.isArray(schema.enum) ? enumType(schema.enum) : undefined;
|
|
30
|
+
return Object.fromEntries([
|
|
31
|
+
...(type === undefined ? [] : [["type", type]]),
|
|
32
|
+
...Object.entries(schema).flatMap(([key, value]) => {
|
|
33
|
+
if (key === "items" && Array.isArray(value))
|
|
34
|
+
return [[key, tupleItemsSchema(value)]];
|
|
35
|
+
if (key === "prefixItems") {
|
|
36
|
+
if ("items" in schema)
|
|
37
|
+
return [];
|
|
38
|
+
return [["items", tupleItemsSchema(Array.isArray(value) ? value : [])]];
|
|
39
|
+
}
|
|
40
|
+
if (key === "unevaluatedItems")
|
|
23
41
|
return [];
|
|
24
|
-
return [[
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return [];
|
|
28
|
-
return [[key, moonshotNode(value)]];
|
|
29
|
-
}));
|
|
42
|
+
return [[key, moonshotNode(value)]];
|
|
43
|
+
}),
|
|
44
|
+
]);
|
|
30
45
|
};
|
|
31
46
|
const moonshot = (schema) => {
|
|
32
47
|
const projected = moonshotNode(schema);
|
|
@@ -34,15 +49,23 @@ const moonshot = (schema) => {
|
|
|
34
49
|
};
|
|
35
50
|
const openAI = (schema) => schema;
|
|
36
51
|
const responses = openAI;
|
|
37
|
-
const gemini =
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
52
|
+
const gemini = GeminiJsonSchema.normalize;
|
|
53
|
+
const MODEL_NAMES = [
|
|
54
|
+
[/gemini/i, "gemini"],
|
|
55
|
+
[/kimi/i, "moonshot"],
|
|
56
|
+
];
|
|
57
|
+
// An explicit `sanitizer` wins, and `none` opts out. Otherwise the protocol's own default
|
|
58
|
+
// applies (the Gemini API always uses Gemini's rules), then the model name selects the family's rules
|
|
59
|
+
// so models reached through gateways and OpenAI-compatible endpoints get the same handling.
|
|
60
|
+
const modelCompatibility = (schema, model, protocolDefault) => {
|
|
61
|
+
switch (model.compatibility?.sanitizer ?? protocolDefault ?? MODEL_NAMES.find(([name]) => name.test(model.id))?.[1]) {
|
|
42
62
|
case "gemini":
|
|
43
63
|
return gemini(schema);
|
|
44
64
|
case "moonshot":
|
|
45
65
|
return moonshot(schema);
|
|
66
|
+
case "none":
|
|
67
|
+
case undefined:
|
|
68
|
+
return schema;
|
|
46
69
|
}
|
|
47
70
|
};
|
|
48
71
|
export const ToolSchemaProjection = {
|
|
@@ -34,18 +34,7 @@ const nativeOptions = (options) => {
|
|
|
34
34
|
return { response_format: responseFormat, ...native };
|
|
35
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`));
|
|
48
|
-
};
|
|
37
|
+
const reference = (asset) => ProviderShared.mediaReference(asset, PROVIDER, NAME).pipe(Effect.map((item) => item.type === "ref" ? { file_id: item.value } : { url: item.value, type: "image_url" }));
|
|
49
38
|
const fromRequest = Effect.fn("XAIImages.fromRequest")(function* (request) {
|
|
50
39
|
const references = yield* Effect.forEach(request.images ?? [], reference);
|
|
51
40
|
return MediaProtocol.json(mergeJsonRecords({
|
|
@@ -67,8 +67,8 @@ export declare const protocol: Protocol<{
|
|
|
67
67
|
} | {
|
|
68
68
|
readonly type: "input_file";
|
|
69
69
|
readonly filename: string;
|
|
70
|
-
readonly detail?: string | undefined;
|
|
71
70
|
readonly file_data?: string | undefined;
|
|
71
|
+
readonly detail?: string | undefined;
|
|
72
72
|
readonly file_url?: string | undefined;
|
|
73
73
|
} | {
|
|
74
74
|
readonly type: "input_text";
|
|
@@ -104,8 +104,8 @@ export declare const protocol: Protocol<{
|
|
|
104
104
|
} | {
|
|
105
105
|
readonly type: "input_file";
|
|
106
106
|
readonly filename: string;
|
|
107
|
-
readonly detail?: string | undefined;
|
|
108
107
|
readonly file_data?: string | undefined;
|
|
108
|
+
readonly detail?: string | undefined;
|
|
109
109
|
readonly file_url?: string | undefined;
|
|
110
110
|
} | {
|
|
111
111
|
readonly type: "input_text";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
3
|
+
import { MediaRoute } from "../route/media.js";
|
|
4
|
+
import { VideoModel, VideoResponse, type VideoRequestFor } from "../video.js";
|
|
5
|
+
export declare const DEFAULT_BASE_URL = "https://api.x.ai/v1";
|
|
6
|
+
export declare const PATH = "/videos/generations";
|
|
7
|
+
export declare const EDIT_PATH = "/videos/edits";
|
|
8
|
+
export declare const EXTEND_PATH = "/videos/extensions";
|
|
9
|
+
export declare const STATUS_PATH = "/videos";
|
|
10
|
+
/**
|
|
11
|
+
* Provider-native options. Common fields (`frames`, `references`, `video`, `durationSeconds`, `aspectRatio`,
|
|
12
|
+
* `resolution`, `audio`) live on the request. `mode` selects the endpoint a `video` input is sent to.
|
|
13
|
+
*/
|
|
14
|
+
export type XAIVideoOptions = {
|
|
15
|
+
readonly mode?: "edit" | "extend";
|
|
16
|
+
readonly reference_audios?: ReadonlyArray<{
|
|
17
|
+
readonly voice_id: string;
|
|
18
|
+
}>;
|
|
19
|
+
} & Record<string, unknown>;
|
|
20
|
+
export type Request = VideoRequestFor<XAIVideoOptions>;
|
|
21
|
+
export declare const Token: Schema.Struct<{
|
|
22
|
+
readonly requestID: Schema.String;
|
|
23
|
+
}>;
|
|
24
|
+
export type Token = Schema.Schema.Type<typeof Token>;
|
|
25
|
+
export declare const protocol: MediaProtocol.Queued<Request, VideoResponse, {
|
|
26
|
+
readonly requestID: string;
|
|
27
|
+
}>;
|
|
28
|
+
export declare const model: (input: MediaRoute.ModelInput) => VideoModel<XAIVideoOptions>;
|
|
29
|
+
export declare const XAIVideo: {
|
|
30
|
+
readonly protocol: MediaProtocol.Queued<Request, VideoResponse, {
|
|
31
|
+
readonly requestID: string;
|
|
32
|
+
}>;
|
|
33
|
+
readonly model: (input: MediaRoute.ModelInput) => VideoModel<XAIVideoOptions>;
|
|
34
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { Media } from "../media.js";
|
|
3
|
+
import { MediaProtocol } from "../route/media-protocol.js";
|
|
4
|
+
import { MediaRoute } from "../route/media.js";
|
|
5
|
+
import { ProviderID, mergeJsonRecords } from "../schema/index.js";
|
|
6
|
+
import { VideoModel, VideoResponse } from "../video.js";
|
|
7
|
+
import { ProviderShared, optionalNull } from "./shared.js";
|
|
8
|
+
const ADAPTER = "xai-video";
|
|
9
|
+
const NAME = "xAI Video";
|
|
10
|
+
const PROVIDER = ProviderID.make("xai");
|
|
11
|
+
export const DEFAULT_BASE_URL = "https://api.x.ai/v1";
|
|
12
|
+
export const PATH = "/videos/generations";
|
|
13
|
+
export const EDIT_PATH = "/videos/edits";
|
|
14
|
+
export const EXTEND_PATH = "/videos/extensions";
|
|
15
|
+
export const STATUS_PATH = "/videos";
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// 2. Token and response schemas
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
export const Token = Schema.Struct({ requestID: Schema.String });
|
|
20
|
+
const StartResponse = Schema.Struct({ request_id: Schema.String });
|
|
21
|
+
const VideoStatus = Schema.Struct({
|
|
22
|
+
status: Schema.String,
|
|
23
|
+
progress: optionalNull(Schema.Number),
|
|
24
|
+
video: optionalNull(Schema.Struct({
|
|
25
|
+
url: optionalNull(Schema.String),
|
|
26
|
+
duration: optionalNull(Schema.Number),
|
|
27
|
+
respect_moderation: optionalNull(Schema.Boolean),
|
|
28
|
+
})),
|
|
29
|
+
error: optionalNull(Schema.Struct({
|
|
30
|
+
code: optionalNull(Schema.String),
|
|
31
|
+
message: optionalNull(Schema.String),
|
|
32
|
+
})),
|
|
33
|
+
model: optionalNull(Schema.String),
|
|
34
|
+
});
|
|
35
|
+
const STATUS = {
|
|
36
|
+
pending: "running",
|
|
37
|
+
done: "completed",
|
|
38
|
+
failed: "failed",
|
|
39
|
+
expired: "expired",
|
|
40
|
+
};
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// 5. Request body construction
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
const mediaInput = (asset) => ProviderShared.mediaReference(asset, PROVIDER, NAME).pipe(Effect.map((reference) => (reference.type === "ref" ? { file_id: reference.value } : { url: reference.value })));
|
|
45
|
+
const nativeOptions = (options) => {
|
|
46
|
+
if (!options)
|
|
47
|
+
return undefined;
|
|
48
|
+
const { mode: _mode, ...native } = options;
|
|
49
|
+
return native;
|
|
50
|
+
};
|
|
51
|
+
const fromRequest = Effect.fn("XAIVideo.fromRequest")(function* (request) {
|
|
52
|
+
const image = request.frames?.first === undefined ? undefined : yield* mediaInput(request.frames.first);
|
|
53
|
+
const lastFrame = request.frames?.last === undefined ? undefined : yield* mediaInput(request.frames.last);
|
|
54
|
+
const video = request.video === undefined ? undefined : yield* mediaInput(request.video);
|
|
55
|
+
const references = yield* Effect.forEach(request.references ?? [], mediaInput);
|
|
56
|
+
return MediaProtocol.json(mergeJsonRecords({
|
|
57
|
+
model: request.model.id,
|
|
58
|
+
prompt: request.prompt,
|
|
59
|
+
image,
|
|
60
|
+
last_frame: lastFrame,
|
|
61
|
+
reference_images: references.length === 0 ? undefined : references,
|
|
62
|
+
video,
|
|
63
|
+
duration: request.durationSeconds,
|
|
64
|
+
aspect_ratio: request.aspectRatio,
|
|
65
|
+
resolution: request.resolution,
|
|
66
|
+
generate_audio: request.audio,
|
|
67
|
+
}, nativeOptions(request.providerOptions), request.http?.body) ?? {});
|
|
68
|
+
});
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// 6. Response decoding
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
const decodeStart = MediaProtocol.decodeStarted(ADAPTER, NAME, StartResponse, (value) => ({
|
|
73
|
+
token: { requestID: value.request_id },
|
|
74
|
+
snapshot: { id: value.request_id, status: "running" },
|
|
75
|
+
}));
|
|
76
|
+
// `progress` is undocumented but observed live as a 0..100 percentage (recorded cassette: 1 → 10 → 37 → 100).
|
|
77
|
+
const fraction = (progress) => progress !== undefined && progress !== null && progress >= 0 && progress <= 100 ? progress / 100 : undefined;
|
|
78
|
+
const decodeVideoStatus = MediaProtocol.decodeJson(ADAPTER, NAME, VideoStatus);
|
|
79
|
+
const decodeStatus = Effect.fn("XAIVideo.decodeStatus")(function* (response, context) {
|
|
80
|
+
const output = yield* decodeVideoStatus(response);
|
|
81
|
+
const status = yield* MediaProtocol.status(STATUS, output.value.status, output);
|
|
82
|
+
return { id: context.token.requestID, status, progress: fraction(output.value.progress) };
|
|
83
|
+
});
|
|
84
|
+
const decodeResult = Effect.fn("XAIVideo.decodeResult")(function* (response, context) {
|
|
85
|
+
const output = yield* decodeVideoStatus(response);
|
|
86
|
+
const decoded = output.value;
|
|
87
|
+
const status = yield* MediaProtocol.status(STATUS, decoded.status, output);
|
|
88
|
+
if (status === "running")
|
|
89
|
+
return yield* output.invalid(`${NAME} request ${context.token.requestID} has not finished`);
|
|
90
|
+
if (status === "failed") {
|
|
91
|
+
const code = decoded.error?.code ?? undefined;
|
|
92
|
+
const message = decoded.error?.message ?? undefined;
|
|
93
|
+
return yield* output.ended("failed", `${NAME} generation failed${code === undefined ? "" : ` (${code})`}${message === undefined ? "" : `: ${message}`}`);
|
|
94
|
+
}
|
|
95
|
+
if (status !== "completed")
|
|
96
|
+
return yield* output.ended("expired", `${NAME} request ${context.token.requestID} expired`);
|
|
97
|
+
// `respect_moderation: false` marks a filtered result; a URL may still be present, so report it as a notice.
|
|
98
|
+
const notices = decoded.video?.respect_moderation === false
|
|
99
|
+
? [{ type: "moderated", message: `${NAME} flagged the generated video for moderation` }]
|
|
100
|
+
: undefined;
|
|
101
|
+
const url = decoded.video?.url ?? undefined;
|
|
102
|
+
if (url === undefined && notices !== undefined)
|
|
103
|
+
return yield* output.contentPolicy(`${NAME} withheld the video for moderation`);
|
|
104
|
+
if (url === undefined)
|
|
105
|
+
return yield* output.invalid(`${NAME} completed without a video URL`);
|
|
106
|
+
const duration = decoded.video?.duration ?? undefined;
|
|
107
|
+
return new VideoResponse({
|
|
108
|
+
videos: [
|
|
109
|
+
Media.url(url, {
|
|
110
|
+
mediaType: "video/mp4",
|
|
111
|
+
info: duration === undefined ? undefined : { durationSeconds: duration },
|
|
112
|
+
}),
|
|
113
|
+
],
|
|
114
|
+
notices,
|
|
115
|
+
providerMetadata: { xai: { requestId: context.token.requestID, model: decoded.model ?? undefined } },
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// 7. Protocol and route
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
const statusPath = (token) => `${STATUS_PATH}/${token.requestID}`;
|
|
122
|
+
export const protocol = MediaProtocol.queued({
|
|
123
|
+
id: ADAPTER,
|
|
124
|
+
name: NAME,
|
|
125
|
+
token: Token,
|
|
126
|
+
unsupported: ["n", "seed", "negativePrompt"],
|
|
127
|
+
start: { body: { from: fromRequest }, decode: decodeStart },
|
|
128
|
+
status: { path: statusPath, decode: decodeStatus },
|
|
129
|
+
result: { path: statusPath, decode: decodeResult },
|
|
130
|
+
});
|
|
131
|
+
// A source video goes to `/videos/edits` unless `providerOptions.mode` asks for an extension.
|
|
132
|
+
const startPath = (request) => {
|
|
133
|
+
if (request.video === undefined)
|
|
134
|
+
return PATH;
|
|
135
|
+
return request.providerOptions?.mode === "extend" ? EXTEND_PATH : EDIT_PATH;
|
|
136
|
+
};
|
|
137
|
+
export const model = (input) => VideoModel.fromRoute({
|
|
138
|
+
id: ADAPTER,
|
|
139
|
+
provider: PROVIDER,
|
|
140
|
+
protocol,
|
|
141
|
+
baseURL: DEFAULT_BASE_URL,
|
|
142
|
+
path: ({ request }) => startPath(request),
|
|
143
|
+
}, input);
|
|
144
|
+
export const XAIVideo = {
|
|
145
|
+
protocol,
|
|
146
|
+
model,
|
|
147
|
+
};
|
|
@@ -39,6 +39,12 @@ export declare const protocol: Protocol<{
|
|
|
39
39
|
readonly image_url: {
|
|
40
40
|
readonly url: string;
|
|
41
41
|
};
|
|
42
|
+
} | {
|
|
43
|
+
readonly type: "file";
|
|
44
|
+
readonly file: {
|
|
45
|
+
readonly filename: string;
|
|
46
|
+
readonly file_data: string;
|
|
47
|
+
};
|
|
42
48
|
})[];
|
|
43
49
|
} | {
|
|
44
50
|
readonly role: "user";
|
|
@@ -54,6 +60,12 @@ export declare const protocol: Protocol<{
|
|
|
54
60
|
readonly image_url: {
|
|
55
61
|
readonly url: string;
|
|
56
62
|
};
|
|
63
|
+
} | {
|
|
64
|
+
readonly type: "file";
|
|
65
|
+
readonly file: {
|
|
66
|
+
readonly filename: string;
|
|
67
|
+
readonly file_data: string;
|
|
68
|
+
};
|
|
57
69
|
})[];
|
|
58
70
|
} | {
|
|
59
71
|
readonly [x: string]: unknown;
|
|
@@ -129,8 +141,8 @@ export declare const protocol: Protocol<{
|
|
|
129
141
|
readonly response_format?: {
|
|
130
142
|
readonly type: string;
|
|
131
143
|
} | undefined;
|
|
132
|
-
readonly do_sample?: boolean | undefined;
|
|
133
144
|
readonly request_id?: string | undefined;
|
|
145
|
+
readonly do_sample?: boolean | undefined;
|
|
134
146
|
}, string, "[DONE]" | {
|
|
135
147
|
readonly [x: string]: unknown;
|
|
136
148
|
readonly error?: {
|
package/dist/provider-error.js
CHANGED
|
@@ -65,6 +65,7 @@ const INVALID_REQUEST_CODES = new Set(["invalid_prompt", "invalid_request_error"
|
|
|
65
65
|
// emits `image_content_policy_violation` as the native code.
|
|
66
66
|
const CONTENT_POLICY_CODES = new Set([
|
|
67
67
|
"content_filter",
|
|
68
|
+
"content_moderation",
|
|
68
69
|
"responsibleaipolicyviolation",
|
|
69
70
|
"content_policy_violation",
|
|
70
71
|
"image_content_policy_violation",
|
|
@@ -157,6 +158,8 @@ function providerCodes(value) {
|
|
|
157
158
|
const exception = isRecord(decoded.exception) ? decoded.exception : undefined;
|
|
158
159
|
return [
|
|
159
160
|
decoded.code,
|
|
161
|
+
// Stability's `{ id, name, errors }` bodies carry the code in `name`.
|
|
162
|
+
Array.isArray(decoded.errors) ? decoded.name : undefined,
|
|
160
163
|
decoded.error_type,
|
|
161
164
|
error?.code,
|
|
162
165
|
error?.type,
|
|
@@ -39,6 +39,12 @@ export declare const routes: (Route<{
|
|
|
39
39
|
readonly image_url: {
|
|
40
40
|
readonly url: string;
|
|
41
41
|
};
|
|
42
|
+
} | {
|
|
43
|
+
readonly type: "file";
|
|
44
|
+
readonly file: {
|
|
45
|
+
readonly filename: string;
|
|
46
|
+
readonly file_data: string;
|
|
47
|
+
};
|
|
42
48
|
})[];
|
|
43
49
|
} | {
|
|
44
50
|
readonly role: "user";
|
|
@@ -54,6 +60,12 @@ export declare const routes: (Route<{
|
|
|
54
60
|
readonly image_url: {
|
|
55
61
|
readonly url: string;
|
|
56
62
|
};
|
|
63
|
+
} | {
|
|
64
|
+
readonly type: "file";
|
|
65
|
+
readonly file: {
|
|
66
|
+
readonly filename: string;
|
|
67
|
+
readonly file_data: string;
|
|
68
|
+
};
|
|
57
69
|
})[];
|
|
58
70
|
} | {
|
|
59
71
|
readonly [x: string]: unknown;
|
|
@@ -470,8 +482,8 @@ export declare const routes: (Route<{
|
|
|
470
482
|
} | {
|
|
471
483
|
readonly type: "input_file";
|
|
472
484
|
readonly filename: string;
|
|
473
|
-
readonly detail?: string | undefined;
|
|
474
485
|
readonly file_data?: string | undefined;
|
|
486
|
+
readonly detail?: string | undefined;
|
|
475
487
|
readonly file_url?: string | undefined;
|
|
476
488
|
} | {
|
|
477
489
|
readonly type: "input_text";
|
|
@@ -507,8 +519,8 @@ export declare const routes: (Route<{
|
|
|
507
519
|
} | {
|
|
508
520
|
readonly type: "input_file";
|
|
509
521
|
readonly filename: string;
|
|
510
|
-
readonly detail?: string | undefined;
|
|
511
522
|
readonly file_data?: string | undefined;
|
|
523
|
+
readonly detail?: string | undefined;
|
|
512
524
|
readonly file_url?: string | undefined;
|
|
513
525
|
} | {
|
|
514
526
|
readonly type: "input_text";
|