chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
103
third_party/pi/packages/ai/src/providers/all.ts
vendored
103
third_party/pi/packages/ai/src/providers/all.ts
vendored
@@ -1,11 +1,10 @@
|
||||
import { createImagesModels, type ImagesProvider, type MutableImagesModels } from "../images-models.ts";
|
||||
import { MODELS } from "../models.generated.ts";
|
||||
import { CLASSIFIER_MODELS, IMAGE_MODELS, MODELS } from "../models.generated.ts";
|
||||
import { type CreateModelsOptions, createModels, type MutableModels, type Provider } from "../models.ts";
|
||||
import type { Api, Model } from "../types.ts";
|
||||
import type { AnyModel, Api, ClassifierApi, ClassifierModel, ImageApi, ImageModel, Model } from "../types.ts";
|
||||
import { amazonBedrockProvider } from "./amazon-bedrock.ts";
|
||||
import { antLingProvider } from "./ant-ling.ts";
|
||||
import { anthropicProvider } from "./anthropic.ts";
|
||||
import { azureOpenAIResponsesProvider } from "./azure-openai-responses.ts";
|
||||
import { azureProvider } from "./azure.ts";
|
||||
import { basetenProvider } from "./baseten.ts";
|
||||
import { cerebrasProvider } from "./cerebras.ts";
|
||||
import { cloudflareAIGatewayProvider } from "./cloudflare-ai-gateway.ts";
|
||||
@@ -19,6 +18,7 @@ import { googleVertexProvider } from "./google-vertex.ts";
|
||||
import { groqProvider } from "./groq.ts";
|
||||
import { huggingfaceProvider } from "./huggingface.ts";
|
||||
import { kimiCodingProvider } from "./kimi-coding.ts";
|
||||
import { metaProvider } from "./meta.ts";
|
||||
import { minimaxProvider } from "./minimax.ts";
|
||||
import { minimaxCnProvider } from "./minimax-cn.ts";
|
||||
import { mistralProvider } from "./mistral.ts";
|
||||
@@ -30,12 +30,12 @@ import { openaiCodexProvider } from "./openai-codex.ts";
|
||||
import { opencodeProvider } from "./opencode.ts";
|
||||
import { opencodeGoProvider } from "./opencode-go.ts";
|
||||
import { openrouterProvider } from "./openrouter.ts";
|
||||
import { openrouterImagesProvider } from "./openrouter-images.ts";
|
||||
import { qwenTokenPlanProvider } from "./qwen-token-plan.ts";
|
||||
import { qwenTokenPlanCnProvider } from "./qwen-token-plan-cn.ts";
|
||||
import { qwenTokenPlanIndividualProvider } from "./qwen-token-plan-individual.ts";
|
||||
import { radiusProvider } from "./radius.ts";
|
||||
import { togetherProvider } from "./together.ts";
|
||||
import { typesafeProvider } from "./typesafe.ts";
|
||||
import { vercelAIGatewayProvider } from "./vercel-ai-gateway.ts";
|
||||
import { xaiProvider } from "./xai.ts";
|
||||
import { xiaomiProvider } from "./xiaomi.ts";
|
||||
@@ -52,18 +52,43 @@ export { radiusProvider };
|
||||
* catalog entry. */
|
||||
export type BuiltinProvider = keyof typeof MODELS;
|
||||
|
||||
type BuiltinModelApi<
|
||||
TProvider extends BuiltinProvider,
|
||||
TModelId extends keyof (typeof MODELS)[TProvider],
|
||||
> = (typeof MODELS)[TProvider][TModelId] extends { api: infer TApi } ? (TApi extends Api ? TApi : never) : never;
|
||||
type BuiltinChatModelId<TProvider extends BuiltinProvider> = keyof (typeof MODELS)[TProvider];
|
||||
type BuiltinImageModelId<TProvider extends BuiltinProvider> = keyof (typeof IMAGE_MODELS)[TProvider];
|
||||
type BuiltinClassifierModelId<TProvider extends BuiltinProvider> = keyof (typeof CLASSIFIER_MODELS)[TProvider];
|
||||
/** API ids of catalog entries. Built-in getters return `Model<Api>` shapes, not literal entry types. */
|
||||
type CatalogApi<TEntry> = TEntry extends { api: infer TApi extends string } ? TApi : never;
|
||||
|
||||
/** Typed read of the generated built-in catalog. */
|
||||
export function getBuiltinModel<TProvider extends BuiltinProvider, TModelId extends keyof (typeof MODELS)[TProvider]>(
|
||||
/** Typed read of one generated built-in chat model. */
|
||||
export function getBuiltinModel<TProvider extends BuiltinProvider, TModelId extends BuiltinChatModelId<TProvider>>(
|
||||
provider: TProvider,
|
||||
modelId: TModelId,
|
||||
): Model<BuiltinModelApi<TProvider, TModelId>> {
|
||||
const models = MODELS[provider] as Record<string, Model<Api>> | undefined;
|
||||
return models?.[modelId as string] as Model<BuiltinModelApi<TProvider, TModelId>>;
|
||||
): Model<CatalogApi<(typeof MODELS)[TProvider][TModelId]>> {
|
||||
return (MODELS as Record<string, Record<string, Model<Api>> | undefined>)[provider]?.[modelId as string] as Model<
|
||||
CatalogApi<(typeof MODELS)[TProvider][TModelId]>
|
||||
>;
|
||||
}
|
||||
|
||||
/** Typed read of one generated built-in image model. */
|
||||
export function getBuiltinImageModel<
|
||||
TProvider extends BuiltinProvider,
|
||||
TModelId extends BuiltinImageModelId<TProvider>,
|
||||
>(provider: TProvider, modelId: TModelId): ImageModel<CatalogApi<(typeof IMAGE_MODELS)[TProvider][TModelId]>> {
|
||||
return (IMAGE_MODELS as Record<string, Record<string, ImageModel<ImageApi>> | undefined>)[provider]?.[
|
||||
modelId as string
|
||||
] as ImageModel<CatalogApi<(typeof IMAGE_MODELS)[TProvider][TModelId]>>;
|
||||
}
|
||||
|
||||
/** Typed read of one generated built-in classifier model. */
|
||||
export function getBuiltinClassifierModel<
|
||||
TProvider extends BuiltinProvider,
|
||||
TModelId extends BuiltinClassifierModelId<TProvider>,
|
||||
>(
|
||||
provider: TProvider,
|
||||
modelId: TModelId,
|
||||
): ClassifierModel<CatalogApi<(typeof CLASSIFIER_MODELS)[TProvider][TModelId]>> {
|
||||
return (CLASSIFIER_MODELS as Record<string, Record<string, ClassifierModel<ClassifierApi>> | undefined>)[provider]?.[
|
||||
modelId as string
|
||||
] as ClassifierModel<CatalogApi<(typeof CLASSIFIER_MODELS)[TProvider][TModelId]>>;
|
||||
}
|
||||
|
||||
export function getBuiltinProviders(): BuiltinProvider[] {
|
||||
@@ -78,11 +103,33 @@ export function getBuiltinModelDataGeneratedAt(): number | undefined {
|
||||
|
||||
export function getBuiltinModels<TProvider extends BuiltinProvider>(
|
||||
provider: TProvider,
|
||||
): Model<BuiltinModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[] {
|
||||
const models = MODELS[provider] as Record<string, Model<Api>> | undefined;
|
||||
return models
|
||||
? (Object.values(models) as Model<BuiltinModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[])
|
||||
: [];
|
||||
): Model<CatalogApi<(typeof MODELS)[TProvider][BuiltinChatModelId<TProvider>]>>[] {
|
||||
const models = (MODELS as Record<string, Record<string, Model<Api>> | undefined>)[provider];
|
||||
return Object.values(models ?? {}) as Model<CatalogApi<(typeof MODELS)[TProvider][BuiltinChatModelId<TProvider>]>>[];
|
||||
}
|
||||
|
||||
export function getBuiltinImageModels<TProvider extends BuiltinProvider>(
|
||||
provider: TProvider,
|
||||
): ImageModel<CatalogApi<(typeof IMAGE_MODELS)[TProvider][BuiltinImageModelId<TProvider>]>>[] {
|
||||
const models = (IMAGE_MODELS as Record<string, Record<string, ImageModel<ImageApi>> | undefined>)[provider];
|
||||
return Object.values(models ?? {}) as ImageModel<
|
||||
CatalogApi<(typeof IMAGE_MODELS)[TProvider][BuiltinImageModelId<TProvider>]>
|
||||
>[];
|
||||
}
|
||||
|
||||
export function getBuiltinClassifierModels<TProvider extends BuiltinProvider>(
|
||||
provider: TProvider,
|
||||
): ClassifierModel<CatalogApi<(typeof CLASSIFIER_MODELS)[TProvider][BuiltinClassifierModelId<TProvider>]>>[] {
|
||||
const models = (CLASSIFIER_MODELS as Record<string, Record<string, ClassifierModel<ClassifierApi>> | undefined>)[
|
||||
provider
|
||||
];
|
||||
return Object.values(models ?? {}) as ClassifierModel<
|
||||
CatalogApi<(typeof CLASSIFIER_MODELS)[TProvider][BuiltinClassifierModelId<TProvider>]>
|
||||
>[];
|
||||
}
|
||||
|
||||
export function getAllBuiltinModels<TProvider extends BuiltinProvider>(provider: TProvider): AnyModel[] {
|
||||
return [...getBuiltinModels(provider), ...getBuiltinImageModels(provider), ...getBuiltinClassifierModels(provider)];
|
||||
}
|
||||
|
||||
/** All built-in providers, freshly constructed. */
|
||||
@@ -91,7 +138,7 @@ export function builtinProviders(): Provider[] {
|
||||
amazonBedrockProvider(),
|
||||
antLingProvider(),
|
||||
anthropicProvider(),
|
||||
azureOpenAIResponsesProvider(),
|
||||
azureProvider(),
|
||||
basetenProvider(),
|
||||
cerebrasProvider(),
|
||||
cloudflareAIGatewayProvider(),
|
||||
@@ -104,6 +151,7 @@ export function builtinProviders(): Provider[] {
|
||||
groqProvider(),
|
||||
huggingfaceProvider(),
|
||||
kimiCodingProvider(),
|
||||
metaProvider(),
|
||||
minimaxProvider(),
|
||||
minimaxCnProvider(),
|
||||
mistralProvider(),
|
||||
@@ -120,6 +168,7 @@ export function builtinProviders(): Provider[] {
|
||||
qwenTokenPlanIndividualProvider(),
|
||||
radiusProvider(),
|
||||
togetherProvider(),
|
||||
typesafeProvider(),
|
||||
vercelAIGatewayProvider(),
|
||||
xaiProvider(),
|
||||
xiaomiProvider(),
|
||||
@@ -139,17 +188,3 @@ export function builtinModels(options?: CreateModelsOptions): MutableModels {
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
/** All built-in image-generation providers, freshly constructed. */
|
||||
export function builtinImagesProviders(): ImagesProvider[] {
|
||||
return [openrouterImagesProvider()];
|
||||
}
|
||||
|
||||
/** An `ImagesModels` collection with every built-in image-generation provider registered. */
|
||||
export function builtinImagesModels(options?: CreateModelsOptions): MutableImagesModels {
|
||||
const models = createImagesModels(options);
|
||||
for (const provider of builtinImagesProviders()) {
|
||||
models.setProvider(provider);
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/amazon-bedrock.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const AMAZON_BEDROCK_MODELS: ModelCatalog<typeof values, "amazon-bedrock"> =
|
||||
flattenModelCatalog("amazon-bedrock", values);
|
||||
export const AMAZON_BEDROCK_MODELS: ChatModelCatalog<typeof values, "amazon-bedrock"> =
|
||||
flattenChatModelCatalog("amazon-bedrock", values);
|
||||
|
||||
export const AMAZON_BEDROCK_IMAGE_MODELS: ImageModelCatalog<typeof values, "amazon-bedrock"> =
|
||||
flattenImageModelCatalog("amazon-bedrock", values);
|
||||
|
||||
export const AMAZON_BEDROCK_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "amazon-bedrock"> =
|
||||
flattenClassifierModelCatalog("amazon-bedrock", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/ant-ling.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const ANT_LING_MODELS: ModelCatalog<typeof values, "ant-ling"> =
|
||||
flattenModelCatalog("ant-ling", values);
|
||||
export const ANT_LING_MODELS: ChatModelCatalog<typeof values, "ant-ling"> =
|
||||
flattenChatModelCatalog("ant-ling", values);
|
||||
|
||||
export const ANT_LING_IMAGE_MODELS: ImageModelCatalog<typeof values, "ant-ling"> =
|
||||
flattenImageModelCatalog("ant-ling", values);
|
||||
|
||||
export const ANT_LING_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "ant-ling"> =
|
||||
flattenClassifierModelCatalog("ant-ling", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/anthropic.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const ANTHROPIC_MODELS: ModelCatalog<typeof values, "anthropic"> =
|
||||
flattenModelCatalog("anthropic", values);
|
||||
export const ANTHROPIC_MODELS: ChatModelCatalog<typeof values, "anthropic"> =
|
||||
flattenChatModelCatalog("anthropic", values);
|
||||
|
||||
export const ANTHROPIC_IMAGE_MODELS: ImageModelCatalog<typeof values, "anthropic"> =
|
||||
flattenImageModelCatalog("anthropic", values);
|
||||
|
||||
export const ANTHROPIC_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "anthropic"> =
|
||||
flattenClassifierModelCatalog("anthropic", values);
|
||||
|
||||
@@ -2,8 +2,18 @@ import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadAnthropicOAuth } from "../auth/oauth/load.ts";
|
||||
import type { ApiKeyAuth } from "../auth/types.ts";
|
||||
import { ANTHROPIC_API_KEY_ENV, ANTHROPIC_AUTH_TOKEN_ENV, ANTHROPIC_OAUTH_TOKEN_ENV } from "../env-api-keys.ts";
|
||||
import {
|
||||
ANTHROPIC_API_KEY_ENV,
|
||||
ANTHROPIC_AUTH_TOKEN_ENV,
|
||||
ANTHROPIC_FEDERATION_RULE_ID_ENV,
|
||||
ANTHROPIC_IDENTITY_TOKEN_FILE_ENV,
|
||||
ANTHROPIC_OAUTH_TOKEN_ENV,
|
||||
ANTHROPIC_ORGANIZATION_ID_ENV,
|
||||
ANTHROPIC_SERVICE_ACCOUNT_ID_ENV,
|
||||
ANTHROPIC_WORKSPACE_ID_ENV,
|
||||
} from "../env-api-keys.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import type { ProviderEnv } from "../types.ts";
|
||||
import { ANTHROPIC_MODELS } from "./anthropic.models.ts";
|
||||
|
||||
function anthropicApiKeyAuth(): ApiKeyAuth {
|
||||
@@ -35,7 +45,28 @@ function anthropicApiKeyAuth(): ApiKeyAuth {
|
||||
signal.throwIfAborted();
|
||||
if (apiKey) return { auth: { apiKey }, source: envVar };
|
||||
}
|
||||
return undefined;
|
||||
|
||||
// Workload identity federation: the Anthropic SDK exchanges the identity
|
||||
// token for a short-lived access token and refreshes it itself. Last in
|
||||
// line so keys and ANTHROPIC_AUTH_TOKEN keep winning, as in the SDK. The
|
||||
// ids are provider config rather than auth, so they travel in `env`.
|
||||
const federation: ProviderEnv = {};
|
||||
for (const envVar of [
|
||||
ANTHROPIC_FEDERATION_RULE_ID_ENV,
|
||||
ANTHROPIC_ORGANIZATION_ID_ENV,
|
||||
ANTHROPIC_IDENTITY_TOKEN_FILE_ENV,
|
||||
]) {
|
||||
const value = await ctx.env(envVar);
|
||||
signal.throwIfAborted();
|
||||
if (!value) return undefined;
|
||||
federation[envVar] = value;
|
||||
}
|
||||
for (const envVar of [ANTHROPIC_SERVICE_ACCOUNT_ID_ENV, ANTHROPIC_WORKSPACE_ID_ENV]) {
|
||||
const value = await ctx.env(envVar);
|
||||
signal.throwIfAborted();
|
||||
if (value) federation[envVar] = value;
|
||||
}
|
||||
return { auth: {}, env: federation, source: "workload identity federation" };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// This file is auto-generated by scripts/generate-models.ts
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/azure-openai-responses.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const AZURE_OPENAI_RESPONSES_MODELS: ModelCatalog<typeof values, "azure-openai-responses"> =
|
||||
flattenModelCatalog("azure-openai-responses", values);
|
||||
@@ -1,14 +0,0 @@
|
||||
import { azureOpenAIResponsesApi } from "../api/azure-openai-responses.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { AZURE_OPENAI_RESPONSES_MODELS } from "./azure-openai-responses.models.ts";
|
||||
|
||||
export function azureOpenAIResponsesProvider(): Provider<"azure-openai-responses"> {
|
||||
return createProvider({
|
||||
id: "azure-openai-responses",
|
||||
name: "Azure OpenAI",
|
||||
auth: { apiKey: envApiKeyAuth("Azure OpenAI API key", ["AZURE_OPENAI_API_KEY"]) },
|
||||
models: Object.values(AZURE_OPENAI_RESPONSES_MODELS),
|
||||
api: azureOpenAIResponsesApi(),
|
||||
});
|
||||
}
|
||||
14
third_party/pi/packages/ai/src/providers/azure.models.ts
vendored
Normal file
14
third_party/pi/packages/ai/src/providers/azure.models.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is auto-generated by scripts/generate-models.ts
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/azure.json" with { type: "json" };
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const AZURE_MODELS: ChatModelCatalog<typeof values, "azure"> =
|
||||
flattenChatModelCatalog("azure", values);
|
||||
|
||||
export const AZURE_IMAGE_MODELS: ImageModelCatalog<typeof values, "azure"> =
|
||||
flattenImageModelCatalog("azure", values);
|
||||
|
||||
export const AZURE_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "azure"> =
|
||||
flattenClassifierModelCatalog("azure", values);
|
||||
55
third_party/pi/packages/ai/src/providers/azure.ts
vendored
Normal file
55
third_party/pi/packages/ai/src/providers/azure.ts
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import { resolveAzureBaseUrl, resolveDeploymentName } from "../api/azure-openai-config.ts";
|
||||
import { azureOpenAIResponsesApi } from "../api/azure-openai-responses.lazy.ts";
|
||||
import { lazyStream } from "../api/lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import type { Api, Model, ProviderStreams, StreamOptions } from "../types.ts";
|
||||
import { AZURE_MODELS } from "./azure.models.ts";
|
||||
|
||||
function resolveAzureModel(model: Model<Api>, options: StreamOptions | undefined): Model<Api> {
|
||||
return { ...model, baseUrl: resolveAzureBaseUrl(model, options) };
|
||||
}
|
||||
|
||||
/** Send the deployment name as the request's model, keeping `model.id` as the catalog id. */
|
||||
function withDeploymentName<T extends StreamOptions>(model: Model<Api>, options: T | undefined): T | undefined {
|
||||
const deploymentName = resolveDeploymentName(model, options);
|
||||
if (deploymentName === model.id) return options;
|
||||
return {
|
||||
...options,
|
||||
onPayload: async (payload, payloadModel) => {
|
||||
const params = { ...(payload as object), model: deploymentName };
|
||||
return (await options?.onPayload?.(params, payloadModel)) ?? params;
|
||||
},
|
||||
} as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the Azure endpoint and deployment before dispatch, inside `lazyStream` so an
|
||||
* unconfigured endpoint errors on the stream instead of throwing out of `stream()`.
|
||||
*/
|
||||
function azureStreams(streams: ProviderStreams): ProviderStreams {
|
||||
return {
|
||||
stream: (model, context, options) =>
|
||||
lazyStream(model, async () =>
|
||||
streams.stream(resolveAzureModel(model, options), context, withDeploymentName(model, options)),
|
||||
),
|
||||
streamSimple: (model, context, options) =>
|
||||
lazyStream(model, async () =>
|
||||
streams.streamSimple(resolveAzureModel(model, options), context, withDeploymentName(model, options)),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export function azureProvider(): Provider<"azure-openai-responses" | "openai-completions"> {
|
||||
return createProvider({
|
||||
id: "azure",
|
||||
name: "Azure",
|
||||
auth: { apiKey: envApiKeyAuth("Azure OpenAI API key", ["AZURE_OPENAI_API_KEY"]) },
|
||||
models: Object.values(AZURE_MODELS),
|
||||
api: {
|
||||
"azure-openai-responses": azureOpenAIResponsesApi(),
|
||||
"openai-completions": azureStreams(openAICompletionsApi()),
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/baseten.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const BASETEN_MODELS: ModelCatalog<typeof values, "baseten"> =
|
||||
flattenModelCatalog("baseten", values);
|
||||
export const BASETEN_MODELS: ChatModelCatalog<typeof values, "baseten"> =
|
||||
flattenChatModelCatalog("baseten", values);
|
||||
|
||||
export const BASETEN_IMAGE_MODELS: ImageModelCatalog<typeof values, "baseten"> =
|
||||
flattenImageModelCatalog("baseten", values);
|
||||
|
||||
export const BASETEN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "baseten"> =
|
||||
flattenClassifierModelCatalog("baseten", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/cerebras.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const CEREBRAS_MODELS: ModelCatalog<typeof values, "cerebras"> =
|
||||
flattenModelCatalog("cerebras", values);
|
||||
export const CEREBRAS_MODELS: ChatModelCatalog<typeof values, "cerebras"> =
|
||||
flattenChatModelCatalog("cerebras", values);
|
||||
|
||||
export const CEREBRAS_IMAGE_MODELS: ImageModelCatalog<typeof values, "cerebras"> =
|
||||
flattenImageModelCatalog("cerebras", values);
|
||||
|
||||
export const CEREBRAS_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "cerebras"> =
|
||||
flattenClassifierModelCatalog("cerebras", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/cloudflare-ai-gateway.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const CLOUDFLARE_AI_GATEWAY_MODELS: ModelCatalog<typeof values, "cloudflare-ai-gateway"> =
|
||||
flattenModelCatalog("cloudflare-ai-gateway", values);
|
||||
export const CLOUDFLARE_AI_GATEWAY_MODELS: ChatModelCatalog<typeof values, "cloudflare-ai-gateway"> =
|
||||
flattenChatModelCatalog("cloudflare-ai-gateway", values);
|
||||
|
||||
export const CLOUDFLARE_AI_GATEWAY_IMAGE_MODELS: ImageModelCatalog<typeof values, "cloudflare-ai-gateway"> =
|
||||
flattenImageModelCatalog("cloudflare-ai-gateway", values);
|
||||
|
||||
export const CLOUDFLARE_AI_GATEWAY_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "cloudflare-ai-gateway"> =
|
||||
flattenClassifierModelCatalog("cloudflare-ai-gateway", values);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { Api, Model, ProviderEnv, ProviderStreams } from "../types.ts";
|
||||
import type { ProviderClassifier, ProviderEnv, ProviderStreams } from "../types.ts";
|
||||
|
||||
const CLOUDFLARE_ACCOUNT_ID = "CLOUDFLARE_ACCOUNT_ID";
|
||||
const CLOUDFLARE_GATEWAY_ID = "CLOUDFLARE_GATEWAY_ID";
|
||||
|
||||
export function resolveCloudflareModel<TApi extends Api>(
|
||||
model: Model<TApi>,
|
||||
export function resolveCloudflareModel<TModel extends { baseUrl: string }>(
|
||||
model: TModel,
|
||||
env: ProviderEnv | undefined,
|
||||
): Model<TApi> {
|
||||
): TModel {
|
||||
if (!env) return model;
|
||||
const baseUrl = model.baseUrl
|
||||
.replaceAll(`{${CLOUDFLARE_ACCOUNT_ID}}`, env[CLOUDFLARE_ACCOUNT_ID] ?? `{${CLOUDFLARE_ACCOUNT_ID}}`)
|
||||
@@ -26,3 +26,11 @@ export function cloudflareStreams(streams: ProviderStreams): ProviderStreams {
|
||||
streams.streamSimple(resolveCloudflareModel(model, options?.env), context, options),
|
||||
};
|
||||
}
|
||||
|
||||
/** Classifier counterpart of {@link cloudflareStreams}. */
|
||||
export function cloudflareClassifier(classifier: ProviderClassifier): ProviderClassifier {
|
||||
return {
|
||||
classify: (model, context, options) =>
|
||||
classifier.classify(resolveCloudflareModel(model, options?.env), context, options),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/cloudflare-workers-ai.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const CLOUDFLARE_WORKERS_AI_MODELS: ModelCatalog<typeof values, "cloudflare-workers-ai"> =
|
||||
flattenModelCatalog("cloudflare-workers-ai", values);
|
||||
export const CLOUDFLARE_WORKERS_AI_MODELS: ChatModelCatalog<typeof values, "cloudflare-workers-ai"> =
|
||||
flattenChatModelCatalog("cloudflare-workers-ai", values);
|
||||
|
||||
export const CLOUDFLARE_WORKERS_AI_IMAGE_MODELS: ImageModelCatalog<typeof values, "cloudflare-workers-ai"> =
|
||||
flattenImageModelCatalog("cloudflare-workers-ai", values);
|
||||
|
||||
export const CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "cloudflare-workers-ai"> =
|
||||
flattenClassifierModelCatalog("cloudflare-workers-ai", values);
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
import { cloudflareWorkersAISystemOneApi } from "../api/cloudflare-workers-ai-system-one.lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { cloudflareWorkersAIAuth } from "./cloudflare-auth.ts";
|
||||
import { cloudflareStreams } from "./cloudflare-stream.ts";
|
||||
import { CLOUDFLARE_WORKERS_AI_MODELS } from "./cloudflare-workers-ai.models.ts";
|
||||
import { cloudflareClassifier, cloudflareStreams } from "./cloudflare-stream.ts";
|
||||
import {
|
||||
CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS,
|
||||
CLOUDFLARE_WORKERS_AI_MODELS,
|
||||
} from "./cloudflare-workers-ai.models.ts";
|
||||
|
||||
export function cloudflareWorkersAIProvider(): Provider<"openai-completions"> {
|
||||
return createProvider({
|
||||
return createProvider<"openai-completions">({
|
||||
id: "cloudflare-workers-ai",
|
||||
name: "Cloudflare Workers AI",
|
||||
auth: { apiKey: cloudflareWorkersAIAuth() },
|
||||
models: Object.values(CLOUDFLARE_WORKERS_AI_MODELS),
|
||||
models: [
|
||||
...Object.values(CLOUDFLARE_WORKERS_AI_MODELS),
|
||||
...Object.values(CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS),
|
||||
],
|
||||
api: cloudflareStreams(openAICompletionsApi()),
|
||||
classifiers: {
|
||||
"cloudflare-workers-ai-system-one": cloudflareClassifier(cloudflareWorkersAISystemOneApi()),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
641
third_party/pi/packages/ai/src/providers/compat-schema.ts
vendored
Normal file
641
third_party/pi/packages/ai/src/providers/compat-schema.ts
vendored
Normal file
@@ -0,0 +1,641 @@
|
||||
import { type Static, type TProperties, type TSchemaOptions, Type } from "typebox";
|
||||
import { ModelCostSchema } from "./model-schema.ts";
|
||||
|
||||
function sessionAffinityFormat(options?: TSchemaOptions) {
|
||||
return Type.Union([Type.Literal("openai"), Type.Literal("openai-nosession"), Type.Literal("openrouter")], options);
|
||||
}
|
||||
|
||||
export const SessionAffinityFormatSchema = sessionAffinityFormat({
|
||||
description: "Session-affinity header format used to route related requests consistently.",
|
||||
});
|
||||
|
||||
function thinkingTokenBudgetField(options?: TSchemaOptions) {
|
||||
return Type.Union(
|
||||
[Type.Literal("thinking_token_budget"), Type.Literal("thinking_budget"), Type.Literal("thinking_budget_tokens")],
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
export const ThinkingTokenBudgetFieldSchema = thinkingTokenBudgetField({
|
||||
description:
|
||||
'Top-level request field name used by OpenAI-compatible endpoints to cap reasoning tokens. "thinking_token_budget" is used by vLLM, "thinking_budget" by Qwen, DashScope, or SGLang, and "thinking_budget_tokens" by llama.cpp.',
|
||||
});
|
||||
|
||||
export const ChatTemplateKwargValueSchema = Type.Union([
|
||||
Type.String(),
|
||||
Type.Number(),
|
||||
Type.Boolean(),
|
||||
Type.Null(),
|
||||
Type.Object({
|
||||
$var: Type.Union([
|
||||
Type.Literal("thinking.enabled"),
|
||||
Type.Literal("thinking.effort"),
|
||||
Type.Literal("thinking.budget"),
|
||||
]),
|
||||
omitWhenOff: Type.Optional(Type.Boolean()),
|
||||
}),
|
||||
]);
|
||||
|
||||
function percentileCutoffs(metric: string) {
|
||||
return Type.Object({
|
||||
p50: Type.Optional(Type.Number({ description: `${metric} at the 50th percentile.` })),
|
||||
p75: Type.Optional(Type.Number({ description: `${metric} at the 75th percentile.` })),
|
||||
p90: Type.Optional(Type.Number({ description: `${metric} at the 90th percentile.` })),
|
||||
p99: Type.Optional(Type.Number({ description: `${metric} at the 99th percentile.` })),
|
||||
});
|
||||
}
|
||||
|
||||
export const OpenRouterRoutingSchema = Type.Object(
|
||||
{
|
||||
allow_fallbacks: Type.Optional(
|
||||
Type.Boolean({ description: "Whether to allow backup providers to serve requests.", default: true }),
|
||||
),
|
||||
require_parameters: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether to filter providers to only those that support all parameters in the request.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
data_collection: Type.Optional(
|
||||
Type.Union([Type.Literal("deny"), Type.Literal("allow")], {
|
||||
description:
|
||||
'Data collection setting. "allow": allow providers that may store or train on data. "deny": only use providers that do not collect user data.',
|
||||
default: "allow",
|
||||
}),
|
||||
),
|
||||
zdr: Type.Optional(
|
||||
Type.Boolean({ description: "Whether to restrict routing to only ZDR (Zero Data Retention) endpoints." }),
|
||||
),
|
||||
enforce_distillable_text: Type.Optional(
|
||||
Type.Boolean({ description: "Whether to restrict routing to only models that allow text distillation." }),
|
||||
),
|
||||
order: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description:
|
||||
"An ordered list of provider names or slugs to try in sequence, falling back to the next if unavailable.",
|
||||
}),
|
||||
),
|
||||
only: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description: "List of provider names or slugs to exclusively allow for this request.",
|
||||
}),
|
||||
),
|
||||
ignore: Type.Optional(
|
||||
Type.Array(Type.String(), { description: "List of provider names or slugs to skip for this request." }),
|
||||
),
|
||||
quantizations: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description:
|
||||
'A list of quantization levels to filter providers by, for example ["fp16", "bf16", "fp8", "fp6", "int8", "int4", "fp4", "fp32"].',
|
||||
}),
|
||||
),
|
||||
sort: Type.Optional(
|
||||
Type.Union(
|
||||
[
|
||||
Type.String(),
|
||||
Type.Object({
|
||||
by: Type.Optional(
|
||||
Type.String({ description: 'The sorting metric, such as "price", "throughput", or "latency".' }),
|
||||
),
|
||||
partition: Type.Optional(
|
||||
Type.Union([Type.String(), Type.Null()], {
|
||||
description: 'Partitioning strategy: "model" or "none".',
|
||||
default: "model",
|
||||
}),
|
||||
),
|
||||
}),
|
||||
],
|
||||
{
|
||||
description:
|
||||
'Sorting strategy. Can be a string such as "price", "throughput", or "latency", or an object.',
|
||||
},
|
||||
),
|
||||
),
|
||||
max_price: Type.Optional(
|
||||
Type.Object(
|
||||
{
|
||||
prompt: Type.Optional(
|
||||
Type.Union([Type.Number(), Type.String()], { description: "Price per million prompt tokens." }),
|
||||
),
|
||||
completion: Type.Optional(
|
||||
Type.Union([Type.Number(), Type.String()], { description: "Price per million completion tokens." }),
|
||||
),
|
||||
image: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: "Price per image." })),
|
||||
audio: Type.Optional(
|
||||
Type.Union([Type.Number(), Type.String()], { description: "Price per audio unit." }),
|
||||
),
|
||||
request: Type.Optional(
|
||||
Type.Union([Type.Number(), Type.String()], { description: "Price per request." }),
|
||||
),
|
||||
},
|
||||
{ description: "Maximum price per million tokens in USD." },
|
||||
),
|
||||
),
|
||||
preferred_min_throughput: Type.Optional(
|
||||
Type.Union([Type.Number(), percentileCutoffs("Minimum tokens per second")], {
|
||||
description: "Preferred minimum throughput in tokens per second. A number applies to p50.",
|
||||
}),
|
||||
),
|
||||
preferred_max_latency: Type.Optional(
|
||||
Type.Union([Type.Number(), percentileCutoffs("Maximum latency in seconds")], {
|
||||
description: "Preferred maximum latency in seconds. A number applies to p50.",
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
description:
|
||||
"OpenRouter provider routing preferences. Controls which upstream providers OpenRouter routes requests to. Sent as the provider field in the OpenRouter API request body. See https://openrouter.ai/docs/guides/routing/provider-selection.",
|
||||
},
|
||||
);
|
||||
|
||||
export const VercelGatewayRoutingSchema = Type.Object(
|
||||
{
|
||||
only: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description:
|
||||
'List of provider slugs to exclusively use for this request, for example ["bedrock", "anthropic"].',
|
||||
}),
|
||||
),
|
||||
order: Type.Optional(
|
||||
Type.Array(Type.String(), {
|
||||
description: 'List of provider slugs to try in order, for example ["anthropic", "openai"].',
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
description:
|
||||
"Vercel AI Gateway routing preferences. Controls which upstream providers the gateway routes requests to. See https://vercel.com/docs/ai-gateway/models-and-providers/provider-options.",
|
||||
},
|
||||
);
|
||||
|
||||
export const AnthropicAllowedFallbackModelSchema = Type.Object(
|
||||
{
|
||||
provider: Type.String({ minLength: 1 }),
|
||||
model: Type.String({ minLength: 1 }),
|
||||
cost: ModelCostSchema,
|
||||
},
|
||||
{ description: "An Anthropic server-side refusal fallback model with local pricing metadata." },
|
||||
);
|
||||
|
||||
function optionalCompatBoolean(options?: TSchemaOptions) {
|
||||
return Type.Optional(Type.Boolean(options));
|
||||
}
|
||||
|
||||
function optionalSessionAffinityFormat(options?: TSchemaOptions) {
|
||||
return Type.Optional(sessionAffinityFormat(options));
|
||||
}
|
||||
|
||||
export const OpenAICompletionsCompatSchema = Type.Object(
|
||||
{
|
||||
supportsStore: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether the provider supports the store field. Default: auto-detected from URL.",
|
||||
}),
|
||||
),
|
||||
supportsDeveloperRole: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the provider supports the developer role instead of system. Default: auto-detected from URL.",
|
||||
}),
|
||||
supportsReasoningEffort: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether the provider supports reasoning_effort. Default: auto-detected from URL.",
|
||||
}),
|
||||
),
|
||||
supportsUsageInStreaming: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether the provider supports stream_options.include_usage for token usage in streaming responses.",
|
||||
default: true,
|
||||
}),
|
||||
),
|
||||
supportsFinishReason: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether streamed responses include finish_reason. When false, pi infers stop or toolUse when the stream ends.",
|
||||
default: true,
|
||||
}),
|
||||
),
|
||||
maxTokensField: Type.Optional(
|
||||
Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")], {
|
||||
description: "Which field to use for max tokens. Default: auto-detected from URL.",
|
||||
}),
|
||||
),
|
||||
requiresToolResultName: Type.Optional(
|
||||
Type.Boolean({ description: "Whether tool results require the name field. Default: auto-detected from URL." }),
|
||||
),
|
||||
requiresAssistantAfterToolResult: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL.",
|
||||
}),
|
||||
),
|
||||
requiresThinkingAsText: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL.",
|
||||
}),
|
||||
),
|
||||
requiresReasoningContentOnAssistantMessages: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL.",
|
||||
}),
|
||||
),
|
||||
thinkingFormat: Type.Optional(
|
||||
Type.Union(
|
||||
[
|
||||
Type.Literal("openai"),
|
||||
Type.Literal("openrouter"),
|
||||
Type.Literal("deepseek"),
|
||||
Type.Literal("together"),
|
||||
Type.Literal("baseten"),
|
||||
Type.Literal("zai"),
|
||||
Type.Literal("qwen"),
|
||||
Type.Literal("chat-template"),
|
||||
Type.Literal("qwen-chat-template"),
|
||||
Type.Literal("string-thinking"),
|
||||
Type.Literal("ant-ling"),
|
||||
],
|
||||
{
|
||||
description:
|
||||
'Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. "openai" uses reasoning_effort, "openrouter" uses reasoning.effort, "deepseek" uses thinking.type plus reasoning_effort when supported, "together" uses reasoning.enabled plus reasoning_effort when supported, "baseten" uses configurable chat_template_args plus reasoning_effort when supported, "zai" uses thinking.type, "qwen" uses top-level enable_thinking, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, "string-thinking" uses top-level thinking, and "ant-ling" uses reasoning.effort only when the mapped effort is non-null.',
|
||||
},
|
||||
),
|
||||
),
|
||||
chatTemplateKwargs: Type.Optional(
|
||||
Type.Record(Type.String(), ChatTemplateKwargValueSchema, {
|
||||
description:
|
||||
'Kwargs sent as chat_template_kwargs when thinkingFormat is "chat-template". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values.',
|
||||
}),
|
||||
),
|
||||
chatTemplateArgs: Type.Optional(
|
||||
Type.Record(Type.String(), ChatTemplateKwargValueSchema, {
|
||||
description:
|
||||
'Arguments sent as chat_template_args when thinkingFormat is "baseten". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values.',
|
||||
}),
|
||||
),
|
||||
openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
|
||||
vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
|
||||
zaiToolStream: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether z.ai supports top-level tool_stream for streaming tool call deltas.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
thinkingTokenBudgetField: Type.Optional(
|
||||
thinkingTokenBudgetField({
|
||||
description:
|
||||
'Top-level request field used to cap reasoning tokens from thinkingBudgets. Reasoning and the answer share max_tokens on these endpoints. "thinking_token_budget" is vLLM, "thinking_budget" is Qwen, DashScope, or SGLang, and "thinking_budget_tokens" is llama.cpp. Off by default and not set on the generated catalog.',
|
||||
}),
|
||||
),
|
||||
supportsThinkingTokenBudget: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
'Alias for thinkingTokenBudgetField: "thinking_token_budget" (vLLM). Prefer thinkingTokenBudgetField.',
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsOpenAIGrammarTools: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the provider supports OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools. The generated catalog enables this for capable models.",
|
||||
default: false,
|
||||
}),
|
||||
supportsMidConvoSystemMessages: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the exact model accepts system or developer messages after the conversation has started. When false, later system messages are folded into the leading system message. The generated catalog enables this for verified models.",
|
||||
default: false,
|
||||
}),
|
||||
supportsMidConvoToolAdditions: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether system messages can introduce additional tools mid-conversation. Requires supportsMidConvoSystemMessages. The generated catalog enables this for capable models.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsStrictMode: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the provider supports the strict field in tool definitions. Generated capable models enable it explicitly.",
|
||||
default: false,
|
||||
}),
|
||||
cacheControlFormat: Type.Optional(
|
||||
Type.Literal("anthropic", {
|
||||
description:
|
||||
"Cache control convention for prompt caching. Anthropic applies cache_control markers to the system prompt, last tool definition, and last user, assistant, or tool-result text content.",
|
||||
}),
|
||||
),
|
||||
sendSessionAffinityHeaders: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether to send session-affinity data from options.sessionId. Default: true for OpenRouter endpoints, false otherwise.",
|
||||
}),
|
||||
sessionAffinityFormat: optionalSessionAffinityFormat({
|
||||
description:
|
||||
"Session-affinity header format. openai sends session_id, x-client-request-id, and x-session-affinity; openai-nosession sends x-client-request-id and x-session-affinity; openrouter sends x-session-id. Does not affect prompt_cache_key. Default: auto-detected.",
|
||||
}),
|
||||
supportsLongCacheRetention: optionalCompatBoolean({
|
||||
description:
|
||||
'Whether the provider supports long prompt cache retention (prompt_cache_retention: "24h" or Anthropic-style cache_control.ttl: "1h", depending on format). Default: auto-detected from provider and URL.',
|
||||
}),
|
||||
vllmPriority: Type.Optional(
|
||||
Type.Number({
|
||||
description:
|
||||
"vLLM scheduler priority sent as the top-level priority request field. Lower values are handled earlier and the server default is 0. Only meaningful with --scheduling-policy priority. Off by default and not set on the generated catalog.",
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
description:
|
||||
"Compatibility settings for OpenAI-compatible completions APIs. Use this to override URL-based auto-detection for custom providers.",
|
||||
additionalProperties: true,
|
||||
},
|
||||
);
|
||||
|
||||
export const OpenAIResponsesCompatSchema = Type.Object(
|
||||
{
|
||||
supportsDeveloperRole: optionalCompatBoolean({
|
||||
description: "Whether the provider supports the developer role instead of system.",
|
||||
default: true,
|
||||
}),
|
||||
supportsMidConvoSystemMessages: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the exact model accepts developer or system messages after the conversation has started. When false, later system messages are folded into the leading system message. The generated catalog enables this for verified models.",
|
||||
default: false,
|
||||
}),
|
||||
sessionAffinityFormat: optionalSessionAffinityFormat({
|
||||
description:
|
||||
"Session-affinity header format. openai sends session_id and x-client-request-id; openai-nosession sends x-client-request-id; openrouter sends x-session-id. Does not affect prompt_cache_key. Default: auto-detected.",
|
||||
}),
|
||||
supportsLongCacheRetention: optionalCompatBoolean({
|
||||
description:
|
||||
'Whether the provider supports long prompt cache retention. This uses prompt_cache_options.ttl: "30m" on GPT-5.6+ and prompt_cache_retention: "24h" on earlier models.',
|
||||
default: true,
|
||||
}),
|
||||
supportsStrictMode: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the provider supports strict JSON-schema function tools. Defaults are API-specific; generated OpenAI models enable it explicitly.",
|
||||
}),
|
||||
supportsOpenAIGrammarTools: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether to emit OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools. The generated catalog enables this for capable models.",
|
||||
default: false,
|
||||
}),
|
||||
supportsAdditionalTools: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether the model supports message-anchored additional_tools input items.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsToolSearch: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether the model supports client-executed tool search for transcript-anchored additions.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsExplicitPromptCacheMode: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether the model accepts prompt_cache_options. Older OpenAI models reject the parameter.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsMidConvoEffort: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether thinking level changes are sent as configuration_update input items instead of changing reasoning.effort, so a change keeps the prompt cache. Only used by the openai-responses API, and ignored with Sign in with ChatGPT on the openai provider.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsMaxOutputTokens: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether the provider accepts max_output_tokens. Some Codex-protocol gateways reject it.",
|
||||
default: true,
|
||||
}),
|
||||
),
|
||||
},
|
||||
{ description: "Compatibility settings for OpenAI Responses APIs.", additionalProperties: true },
|
||||
);
|
||||
|
||||
export const AnthropicMessagesCompatSchema = Type.Object(
|
||||
{
|
||||
supportsEagerToolInputStreaming: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether the provider accepts per-tool eager_input_streaming. When false, the Anthropic provider omits tools[].eager_input_streaming and sends the legacy fine-grained-tool-streaming-2025-05-14 beta header for tool-enabled requests.",
|
||||
default: true,
|
||||
}),
|
||||
),
|
||||
supportsLongCacheRetention: optionalCompatBoolean({
|
||||
description: "Whether the provider supports Anthropic long cache retention through cache_control.ttl.",
|
||||
default: true,
|
||||
}),
|
||||
sendSessionAffinityHeaders: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether to send x-session-affinity from options.sessionId when caching is enabled. Required for providers like Fireworks that use session affinity for prompt cache routing; requests to the same replica maximize cache hits. Default: true for OpenRouter endpoints, false otherwise.",
|
||||
}),
|
||||
sessionAffinityFormat: Type.Optional(
|
||||
Type.Literal("openrouter", {
|
||||
description:
|
||||
"Session-affinity format. openrouter sends x-session-id; when unset, sends x-session-affinity.",
|
||||
}),
|
||||
),
|
||||
supportsCacheControlOnTools: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether the provider supports Anthropic-style cache_control markers on tool definitions. When false, cache_control is omitted from tool parameters. Some Anthropic-compatible providers, such as Fireworks, do not support this field on tools and may reject or ignore it.",
|
||||
default: true,
|
||||
}),
|
||||
),
|
||||
supportsTemperature: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether the model accepts the Anthropic temperature request field. Claude Opus 4.7+ rejects non-default values.",
|
||||
default: true,
|
||||
}),
|
||||
),
|
||||
forceAdaptiveThinking: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether to force adaptive thinking (thinking.type: adaptive plus output_config.effort) regardless of model ID. Built-in models that require adaptive thinking set this in generated metadata. Custom Anthropic-compatible providers can set this to true for any model whose upstream requires the adaptive format. Set false to opt out on overridden built-in models.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
allowEmptySignature: Type.Optional(
|
||||
Type.Boolean({
|
||||
description: "Whether to replay empty thinking signatures instead of converting thinking to text.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsStrictTools: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether the provider supports Anthropic strict tool schemas. Generated Anthropic models enable it explicitly.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsMidConvoEffort: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether the exact model transport supports effort-only system messages and thinking binding controls.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
supportsMidConvoSystemMessages: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the exact model accepts system-role messages inside the conversation. When false, later system messages are folded into the top-level system prompt.",
|
||||
default: false,
|
||||
}),
|
||||
supportsMidConvoToolChanges: Type.Optional(
|
||||
Type.Boolean({
|
||||
description:
|
||||
"Whether the exact model accepts mid-conversation tool_addition and tool_removal blocks. Requires supportsMidConvoSystemMessages.",
|
||||
default: false,
|
||||
}),
|
||||
),
|
||||
allowedFallbackModels: Type.Optional(
|
||||
Type.Array(AnthropicAllowedFallbackModelSchema, {
|
||||
maxItems: 3,
|
||||
description:
|
||||
"Models Anthropic accepts for server-side refusal fallback, with local pricing metadata for returned fallback responses. When absent or empty, callers must omit fallbacks; Anthropic rejects the field for models with no permitted fallback targets.",
|
||||
}),
|
||||
),
|
||||
},
|
||||
{ description: "Compatibility settings for Anthropic Messages-compatible APIs.", additionalProperties: true },
|
||||
);
|
||||
|
||||
export const BedrockCompatSchema = Type.Object(
|
||||
{
|
||||
supportsStrictMode: optionalCompatBoolean({
|
||||
description: "Whether the model supports Bedrock strict tool schemas.",
|
||||
default: false,
|
||||
}),
|
||||
},
|
||||
{ description: "Compatibility settings for Amazon Bedrock models.", additionalProperties: true },
|
||||
);
|
||||
|
||||
export const MistralConversationsCompatSchema = Type.Object(
|
||||
{
|
||||
supportsMidConvoSystemMessages: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the exact model accepts system messages after the conversation has started. When false, later system messages are folded into the leading system message.",
|
||||
default: false,
|
||||
}),
|
||||
},
|
||||
{ description: "Compatibility settings for the Mistral chat API.", additionalProperties: true },
|
||||
);
|
||||
|
||||
const ProviderCompatPropertyOverrides = {
|
||||
supportsDeveloperRole: optionalCompatBoolean({
|
||||
description: "Whether the provider supports the developer role instead of system. Defaults are API-specific.",
|
||||
}),
|
||||
supportsMidConvoSystemMessages: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the exact model accepts system or developer messages after the conversation has started. When false, later system messages are folded into the leading system message.",
|
||||
default: false,
|
||||
}),
|
||||
sessionAffinityFormat: optionalSessionAffinityFormat({
|
||||
description: "Session-affinity header format. Defaults are API-specific or auto-detected.",
|
||||
}),
|
||||
supportsMidConvoEffort: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether thinking level changes are sent inside the conversation instead of changing the request's effort, so a change keeps the prompt cache. Used by the anthropic-messages and openai-responses APIs.",
|
||||
default: false,
|
||||
}),
|
||||
supportsLongCacheRetention: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the provider supports long prompt cache retention. Defaults are API-specific or auto-detected.",
|
||||
}),
|
||||
supportsStrictMode: optionalCompatBoolean({
|
||||
description: "Whether the provider supports strict tool schemas. Defaults are API-specific.",
|
||||
}),
|
||||
supportsOpenAIGrammarTools: optionalCompatBoolean({
|
||||
description:
|
||||
"Whether the provider supports OpenAI custom tools with Lark or regex grammar formats. When false, grammar-constrained tools fall back to normal function tools.",
|
||||
default: false,
|
||||
}),
|
||||
sendSessionAffinityHeaders: optionalCompatBoolean({
|
||||
description: "Whether to send session-affinity data from options.sessionId. Defaults are API-specific.",
|
||||
}),
|
||||
} satisfies TProperties;
|
||||
|
||||
type UnionToIntersection<Union> = (Union extends unknown ? (value: Union) => void : never) extends (
|
||||
value: infer Intersection,
|
||||
) => void
|
||||
? Intersection
|
||||
: never;
|
||||
|
||||
type MergedCompatProperties<PropertyGroups extends readonly TProperties[], Overrides extends TProperties> = Omit<
|
||||
UnionToIntersection<PropertyGroups[number]>,
|
||||
keyof Overrides
|
||||
> &
|
||||
Overrides;
|
||||
|
||||
/**
|
||||
* Provider-level models.json compatibility is API-agnostic, so it needs one superset. Every
|
||||
* duplicate property requires explicit generic metadata, while API-specific schemas retain their
|
||||
* own defaults and descriptions.
|
||||
*/
|
||||
function mergeCompatProperties<
|
||||
const PropertyGroups extends readonly TProperties[],
|
||||
const Overrides extends TProperties,
|
||||
>(propertyGroups: PropertyGroups, overrides: Overrides): MergedCompatProperties<PropertyGroups, Overrides> {
|
||||
const merged: TProperties = {};
|
||||
const duplicateNames = new Set<string>();
|
||||
|
||||
for (const properties of propertyGroups) {
|
||||
for (const [name, schema] of Object.entries(properties)) {
|
||||
if (merged[name] !== undefined) {
|
||||
duplicateNames.add(name);
|
||||
if (!(name in overrides)) {
|
||||
throw new Error(`Duplicate compatibility schema property requires an override: ${name}`);
|
||||
}
|
||||
}
|
||||
merged[name] = schema;
|
||||
}
|
||||
}
|
||||
|
||||
for (const name of Object.keys(overrides)) {
|
||||
if (!duplicateNames.has(name)) {
|
||||
throw new Error(`Compatibility schema override does not resolve a duplicate property: ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
return { ...merged, ...overrides } as MergedCompatProperties<PropertyGroups, Overrides>;
|
||||
}
|
||||
|
||||
const CompatSchemasByApi = {
|
||||
"openai-completions": OpenAICompletionsCompatSchema,
|
||||
"openai-responses": OpenAIResponsesCompatSchema,
|
||||
"anthropic-messages": AnthropicMessagesCompatSchema,
|
||||
"bedrock-converse-stream": BedrockCompatSchema,
|
||||
"mistral-conversations": MistralConversationsCompatSchema,
|
||||
} as const;
|
||||
|
||||
const ProviderCompatProperties = mergeCompatProperties(
|
||||
Object.values(CompatSchemasByApi).map((schema) => schema.properties),
|
||||
ProviderCompatPropertyOverrides,
|
||||
);
|
||||
|
||||
export const ProviderCompatSchema = Type.Object(ProviderCompatProperties, {
|
||||
description: "Provider and model compatibility overrides.",
|
||||
additionalProperties: true,
|
||||
});
|
||||
|
||||
export type ChatTemplateKwargValue = Static<typeof ChatTemplateKwargValueSchema>;
|
||||
/** Top-level request field used to cap reasoning tokens on OpenAI-compatible servers. */
|
||||
export type ThinkingTokenBudgetField = Static<typeof ThinkingTokenBudgetFieldSchema>;
|
||||
export type SessionAffinityFormat = Static<typeof SessionAffinityFormatSchema>;
|
||||
/** OpenRouter provider routing preferences. */
|
||||
export interface OpenRouterRouting extends Static<typeof OpenRouterRoutingSchema> {}
|
||||
/** Vercel AI Gateway routing preferences. */
|
||||
export interface VercelGatewayRouting extends Static<typeof VercelGatewayRoutingSchema> {}
|
||||
/** An Anthropic server-side refusal fallback model with local pricing metadata. */
|
||||
export interface AnthropicAllowedFallbackModel extends Static<typeof AnthropicAllowedFallbackModelSchema> {}
|
||||
|
||||
/** Compatibility settings for OpenAI-compatible completions APIs. */
|
||||
export interface OpenAICompletionsCompat extends Static<typeof OpenAICompletionsCompatSchema> {}
|
||||
/** Compatibility settings for OpenAI Responses APIs. */
|
||||
export interface OpenAIResponsesCompat extends Static<typeof OpenAIResponsesCompatSchema> {}
|
||||
/** Compatibility settings for Anthropic Messages-compatible APIs. */
|
||||
export interface AnthropicMessagesCompat extends Static<typeof AnthropicMessagesCompatSchema> {}
|
||||
/** Compatibility settings for Amazon Bedrock models. */
|
||||
export interface BedrockCompat extends Static<typeof BedrockCompatSchema> {}
|
||||
/** Compatibility settings for the Mistral chat API. */
|
||||
export interface MistralConversationsCompat extends Static<typeof MistralConversationsCompatSchema> {}
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/deepseek.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const DEEPSEEK_MODELS: ModelCatalog<typeof values, "deepseek"> =
|
||||
flattenModelCatalog("deepseek", values);
|
||||
export const DEEPSEEK_MODELS: ChatModelCatalog<typeof values, "deepseek"> =
|
||||
flattenChatModelCatalog("deepseek", values);
|
||||
|
||||
export const DEEPSEEK_IMAGE_MODELS: ImageModelCatalog<typeof values, "deepseek"> =
|
||||
flattenImageModelCatalog("deepseek", values);
|
||||
|
||||
export const DEEPSEEK_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "deepseek"> =
|
||||
flattenClassifierModelCatalog("deepseek", values);
|
||||
|
||||
69
third_party/pi/packages/ai/src/providers/faux.ts
vendored
69
third_party/pi/packages/ai/src/providers/faux.ts
vendored
@@ -2,7 +2,6 @@ import { createProvider, type Provider } from "../models.ts";
|
||||
import type {
|
||||
AssistantMessage,
|
||||
AssistantMessageEventStream,
|
||||
Context,
|
||||
DeferredCancelOptions,
|
||||
DeferredFetchOptions,
|
||||
DeferredHandle,
|
||||
@@ -16,9 +15,11 @@ import type {
|
||||
ThinkingContent,
|
||||
ToolCall,
|
||||
ToolResultMessage,
|
||||
TranscriptContext,
|
||||
Usage,
|
||||
} from "../types.ts";
|
||||
import { createAssistantMessageEventStream } from "../utils/event-stream.ts";
|
||||
import { getSystemMessageText } from "../utils/text.ts";
|
||||
|
||||
const DEFAULT_API = "faux";
|
||||
const DEFAULT_PROVIDER = "faux";
|
||||
@@ -42,6 +43,7 @@ export interface FauxModelDefinition {
|
||||
name?: string;
|
||||
reasoning?: boolean;
|
||||
input?: ("text" | "image")[];
|
||||
inputLimits?: Model<string>["inputLimits"];
|
||||
cost?: { input: number; output: number; cacheRead: number; cacheWrite: number };
|
||||
contextWindow?: number;
|
||||
maxTokens?: number;
|
||||
@@ -105,7 +107,7 @@ export interface FauxProviderState {
|
||||
}
|
||||
|
||||
export type FauxResponseFactory = (
|
||||
context: Context,
|
||||
context: TranscriptContext,
|
||||
options: SimpleStreamOptions | undefined,
|
||||
state: FauxProviderState,
|
||||
model: Model<string>,
|
||||
@@ -194,6 +196,15 @@ function toolResultToText(message: ToolResultMessage): string {
|
||||
}
|
||||
|
||||
function messageToText(message: Message): string {
|
||||
if (message.role === "system") {
|
||||
return [
|
||||
getSystemMessageText(message),
|
||||
...(message.toolsRemoved?.map((tool) => `tool-:${JSON.stringify(tool)}`) ?? []),
|
||||
...(message.toolsAdded?.map((tool) => `tool+:${JSON.stringify(tool)}`) ?? []),
|
||||
]
|
||||
.filter((part) => part.length > 0)
|
||||
.join("\n");
|
||||
}
|
||||
if (message.role === "user") {
|
||||
return contentToText(message.content);
|
||||
}
|
||||
@@ -203,18 +214,23 @@ function messageToText(message: Message): string {
|
||||
return toolResultToText(message);
|
||||
}
|
||||
|
||||
function serializeContext(context: Context): string {
|
||||
const parts: string[] = [];
|
||||
if (context.systemPrompt) {
|
||||
parts.push(`system:${context.systemPrompt}`);
|
||||
}
|
||||
for (const message of context.messages) {
|
||||
parts.push(`${message.role}:${messageToText(message)}`);
|
||||
}
|
||||
if (context.tools?.length) {
|
||||
parts.push(`tools:${JSON.stringify(context.tools)}`);
|
||||
}
|
||||
return parts.join("\n\n");
|
||||
/** Length of the prompt text that joins `messages` with blank lines. */
|
||||
function joinedLength(messages: readonly string[], count = messages.length): number {
|
||||
let length = count > 0 ? (count - 1) * 2 : 0;
|
||||
for (let index = 0; index < count; index++) length += messages[index]!.length;
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of the common prefix of the two joined prompts. Equal messages are compared whole; characters are compared
|
||||
* only from the first message that differs.
|
||||
*/
|
||||
function commonPromptPrefixLength(previous: readonly string[], current: readonly string[]): number {
|
||||
let index = 0;
|
||||
while (index < previous.length && index < current.length && previous[index] === current[index]) index++;
|
||||
const rest = (messages: readonly string[]) =>
|
||||
index === messages.length ? "" : (index > 0 ? "\n\n" : "") + messages.slice(index).join("\n\n");
|
||||
return joinedLength(previous, index) + commonPrefixLength(rest(previous), rest(current));
|
||||
}
|
||||
|
||||
function commonPrefixLength(a: string, b: string): number {
|
||||
@@ -228,12 +244,14 @@ function commonPrefixLength(a: string, b: string): number {
|
||||
|
||||
function withUsageEstimate(
|
||||
message: AssistantMessage,
|
||||
context: Context,
|
||||
context: TranscriptContext,
|
||||
options: StreamOptions | undefined,
|
||||
promptCache: Map<string, string>,
|
||||
promptCache: Map<string, readonly string[]>,
|
||||
): AssistantMessage {
|
||||
const promptText = serializeContext(context);
|
||||
const promptTokens = estimateTokens(promptText);
|
||||
// One text per message; the whole prompt joins them with blank lines.
|
||||
const prompt = context.messages.map((message) => `${message.role}:${messageToText(message)}`);
|
||||
const promptLength = joinedLength(prompt);
|
||||
const promptTokens = Math.ceil(promptLength / 4);
|
||||
const outputTokens = estimateTokens(assistantContentToText(message.content));
|
||||
let input = promptTokens;
|
||||
let cacheRead = 0;
|
||||
@@ -243,14 +261,14 @@ function withUsageEstimate(
|
||||
if (sessionId && options?.cacheRetention !== "none") {
|
||||
const previousPrompt = promptCache.get(sessionId);
|
||||
if (previousPrompt) {
|
||||
const cachedChars = commonPrefixLength(previousPrompt, promptText);
|
||||
cacheRead = estimateTokens(previousPrompt.slice(0, cachedChars));
|
||||
cacheWrite = estimateTokens(promptText.slice(cachedChars));
|
||||
const cachedChars = commonPromptPrefixLength(previousPrompt, prompt);
|
||||
cacheRead = Math.ceil(cachedChars / 4);
|
||||
cacheWrite = Math.ceil((promptLength - cachedChars) / 4);
|
||||
input = Math.max(0, promptTokens - cacheRead);
|
||||
} else {
|
||||
cacheWrite = promptTokens;
|
||||
}
|
||||
promptCache.set(sessionId, promptText);
|
||||
promptCache.set(sessionId, prompt);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -444,13 +462,13 @@ export function createFauxCore(options: RegisterFauxProviderOptions) {
|
||||
let pendingResponses: FauxResponseStep[] = [];
|
||||
const tokensPerSecond = options.tokensPerSecond;
|
||||
const state: FauxProviderState = { callCount: 0, deferredFetchCount: 0, cancelledDeferred: [] };
|
||||
const promptCache = new Map<string, string>();
|
||||
const promptCache = new Map<string, readonly string[]>();
|
||||
const deferredResponses = new Map<
|
||||
string,
|
||||
{
|
||||
handle: DeferredHandle;
|
||||
step: FauxResponseStep;
|
||||
context: Context;
|
||||
context: TranscriptContext;
|
||||
options: SimpleStreamOptions | undefined;
|
||||
model: Model<string>;
|
||||
pendingFetches: number;
|
||||
@@ -480,6 +498,7 @@ export function createFauxCore(options: RegisterFauxProviderOptions) {
|
||||
baseUrl: DEFAULT_BASE_URL,
|
||||
reasoning: definition.reasoning ?? false,
|
||||
input: definition.input ?? ["text", "image"],
|
||||
inputLimits: definition.inputLimits,
|
||||
cost: definition.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: definition.contextWindow ?? 128000,
|
||||
maxTokens: definition.maxTokens ?? 16384,
|
||||
@@ -487,7 +506,7 @@ export function createFauxCore(options: RegisterFauxProviderOptions) {
|
||||
|
||||
const resolveResponse = async (
|
||||
step: FauxResponseStep,
|
||||
context: Context,
|
||||
context: TranscriptContext,
|
||||
streamOptions: SimpleStreamOptions | undefined,
|
||||
requestModel: Model<string>,
|
||||
): Promise<AssistantMessage> => {
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/fireworks.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const FIREWORKS_MODELS: ModelCatalog<typeof values, "fireworks"> =
|
||||
flattenModelCatalog("fireworks", values);
|
||||
export const FIREWORKS_MODELS: ChatModelCatalog<typeof values, "fireworks"> =
|
||||
flattenChatModelCatalog("fireworks", values);
|
||||
|
||||
export const FIREWORKS_IMAGE_MODELS: ImageModelCatalog<typeof values, "fireworks"> =
|
||||
flattenImageModelCatalog("fireworks", values);
|
||||
|
||||
export const FIREWORKS_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "fireworks"> =
|
||||
flattenClassifierModelCatalog("fireworks", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/github-copilot.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const GITHUB_COPILOT_MODELS: ModelCatalog<typeof values, "github-copilot"> =
|
||||
flattenModelCatalog("github-copilot", values);
|
||||
export const GITHUB_COPILOT_MODELS: ChatModelCatalog<typeof values, "github-copilot"> =
|
||||
flattenChatModelCatalog("github-copilot", values);
|
||||
|
||||
export const GITHUB_COPILOT_IMAGE_MODELS: ImageModelCatalog<typeof values, "github-copilot"> =
|
||||
flattenImageModelCatalog("github-copilot", values);
|
||||
|
||||
export const GITHUB_COPILOT_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "github-copilot"> =
|
||||
flattenClassifierModelCatalog("github-copilot", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/google-vertex.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const GOOGLE_VERTEX_MODELS: ModelCatalog<typeof values, "google-vertex"> =
|
||||
flattenModelCatalog("google-vertex", values);
|
||||
export const GOOGLE_VERTEX_MODELS: ChatModelCatalog<typeof values, "google-vertex"> =
|
||||
flattenChatModelCatalog("google-vertex", values);
|
||||
|
||||
export const GOOGLE_VERTEX_IMAGE_MODELS: ImageModelCatalog<typeof values, "google-vertex"> =
|
||||
flattenImageModelCatalog("google-vertex", values);
|
||||
|
||||
export const GOOGLE_VERTEX_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "google-vertex"> =
|
||||
flattenClassifierModelCatalog("google-vertex", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/google.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const GOOGLE_MODELS: ModelCatalog<typeof values, "google"> =
|
||||
flattenModelCatalog("google", values);
|
||||
export const GOOGLE_MODELS: ChatModelCatalog<typeof values, "google"> =
|
||||
flattenChatModelCatalog("google", values);
|
||||
|
||||
export const GOOGLE_IMAGE_MODELS: ImageModelCatalog<typeof values, "google"> =
|
||||
flattenImageModelCatalog("google", values);
|
||||
|
||||
export const GOOGLE_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "google"> =
|
||||
flattenClassifierModelCatalog("google", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/groq.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const GROQ_MODELS: ModelCatalog<typeof values, "groq"> =
|
||||
flattenModelCatalog("groq", values);
|
||||
export const GROQ_MODELS: ChatModelCatalog<typeof values, "groq"> =
|
||||
flattenChatModelCatalog("groq", values);
|
||||
|
||||
export const GROQ_IMAGE_MODELS: ImageModelCatalog<typeof values, "groq"> =
|
||||
flattenImageModelCatalog("groq", values);
|
||||
|
||||
export const GROQ_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "groq"> =
|
||||
flattenClassifierModelCatalog("groq", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/huggingface.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const HUGGINGFACE_MODELS: ModelCatalog<typeof values, "huggingface"> =
|
||||
flattenModelCatalog("huggingface", values);
|
||||
export const HUGGINGFACE_MODELS: ChatModelCatalog<typeof values, "huggingface"> =
|
||||
flattenChatModelCatalog("huggingface", values);
|
||||
|
||||
export const HUGGINGFACE_IMAGE_MODELS: ImageModelCatalog<typeof values, "huggingface"> =
|
||||
flattenImageModelCatalog("huggingface", values);
|
||||
|
||||
export const HUGGINGFACE_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "huggingface"> =
|
||||
flattenClassifierModelCatalog("huggingface", values);
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import type { generateImages as generateImagesOpenRouterFunction } from "../../api/openrouter-images.ts";
|
||||
import { registerImagesApiProvider } from "../../images-api-registry.ts";
|
||||
import type { AssistantImages, ImagesContext, ImagesFunction, ImagesModel, ImagesOptions } from "../../types.ts";
|
||||
import type {
|
||||
AssistantImages,
|
||||
ImageApi,
|
||||
ImageModel,
|
||||
ImagesContext,
|
||||
ImagesFunction,
|
||||
ImagesOptions,
|
||||
} from "../../types.ts";
|
||||
|
||||
interface OpenRouterImagesProviderModule {
|
||||
generateImages: typeof generateImagesOpenRouterFunction;
|
||||
@@ -8,7 +15,7 @@ interface OpenRouterImagesProviderModule {
|
||||
|
||||
let openRouterImagesProviderModulePromise: Promise<OpenRouterImagesProviderModule> | undefined;
|
||||
|
||||
function createLazyLoadErrorImages(model: ImagesModel<"openrouter-images">, error: unknown): AssistantImages {
|
||||
function createLazyLoadErrorImages(model: ImageModel<ImageApi>, error: unknown): AssistantImages {
|
||||
return {
|
||||
api: model.api,
|
||||
provider: model.provider,
|
||||
@@ -27,8 +34,8 @@ function loadOpenRouterImagesProviderModule(): Promise<OpenRouterImagesProviderM
|
||||
return openRouterImagesProviderModulePromise;
|
||||
}
|
||||
|
||||
export const generateImagesOpenRouter: ImagesFunction<"openrouter-images", ImagesOptions> = async (
|
||||
model: ImagesModel<"openrouter-images">,
|
||||
export const generateImagesOpenRouter: ImagesFunction<ImagesOptions> = async (
|
||||
model: ImageModel<ImageApi>,
|
||||
context: ImagesContext,
|
||||
options?: ImagesOptions,
|
||||
) => {
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/kimi-coding.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const KIMI_CODING_MODELS: ModelCatalog<typeof values, "kimi-coding"> =
|
||||
flattenModelCatalog("kimi-coding", values);
|
||||
export const KIMI_CODING_MODELS: ChatModelCatalog<typeof values, "kimi-coding"> =
|
||||
flattenChatModelCatalog("kimi-coding", values);
|
||||
|
||||
export const KIMI_CODING_IMAGE_MODELS: ImageModelCatalog<typeof values, "kimi-coding"> =
|
||||
flattenImageModelCatalog("kimi-coding", values);
|
||||
|
||||
export const KIMI_CODING_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "kimi-coding"> =
|
||||
flattenClassifierModelCatalog("kimi-coding", values);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadKimiCodingOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { KIMI_CODING_MODELS } from "./kimi-coding.models.ts";
|
||||
|
||||
export function kimiCodingProvider(): Provider<"anthropic-messages"> {
|
||||
export function kimiCodingProvider(): Provider<"openai-completions"> {
|
||||
return createProvider({
|
||||
id: "kimi-coding",
|
||||
name: "Kimi For Coding",
|
||||
baseUrl: "https://api.kimi.com/coding",
|
||||
baseUrl: "https://api.kimi.com/coding/v1",
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("Kimi API key", ["KIMI_API_KEY"]),
|
||||
oauth: lazyOAuth({
|
||||
@@ -19,6 +19,6 @@ export function kimiCodingProvider(): Provider<"anthropic-messages"> {
|
||||
}),
|
||||
},
|
||||
models: Object.values(KIMI_CODING_MODELS),
|
||||
api: anthropicMessagesApi(),
|
||||
api: openAICompletionsApi(),
|
||||
});
|
||||
}
|
||||
|
||||
14
third_party/pi/packages/ai/src/providers/meta.models.ts
vendored
Normal file
14
third_party/pi/packages/ai/src/providers/meta.models.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is auto-generated by scripts/generate-models.ts
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/meta.json" with { type: "json" };
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const META_MODELS: ChatModelCatalog<typeof values, "meta"> =
|
||||
flattenChatModelCatalog("meta", values);
|
||||
|
||||
export const META_IMAGE_MODELS: ImageModelCatalog<typeof values, "meta"> =
|
||||
flattenImageModelCatalog("meta", values);
|
||||
|
||||
export const META_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "meta"> =
|
||||
flattenClassifierModelCatalog("meta", values);
|
||||
24
third_party/pi/packages/ai/src/providers/meta.ts
vendored
Normal file
24
third_party/pi/packages/ai/src/providers/meta.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadMetaOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { META_MODELS } from "./meta.models.ts";
|
||||
|
||||
export function metaProvider(): Provider<"openai-responses"> {
|
||||
return createProvider({
|
||||
id: "meta",
|
||||
name: "Meta",
|
||||
baseUrl: "https://api.meta.ai/v1",
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("Meta Model API key", ["META_API_KEY"]),
|
||||
oauth: lazyOAuth({
|
||||
name: "Meta (Muse subscription)",
|
||||
isSubscription: true,
|
||||
loginLabel: "Sign in with Meta",
|
||||
load: loadMetaOAuth,
|
||||
}),
|
||||
},
|
||||
models: Object.values(META_MODELS),
|
||||
api: openAIResponsesApi(),
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/minimax-cn.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const MINIMAX_CN_MODELS: ModelCatalog<typeof values, "minimax-cn"> =
|
||||
flattenModelCatalog("minimax-cn", values);
|
||||
export const MINIMAX_CN_MODELS: ChatModelCatalog<typeof values, "minimax-cn"> =
|
||||
flattenChatModelCatalog("minimax-cn", values);
|
||||
|
||||
export const MINIMAX_CN_IMAGE_MODELS: ImageModelCatalog<typeof values, "minimax-cn"> =
|
||||
flattenImageModelCatalog("minimax-cn", values);
|
||||
|
||||
export const MINIMAX_CN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "minimax-cn"> =
|
||||
flattenClassifierModelCatalog("minimax-cn", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/minimax.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const MINIMAX_MODELS: ModelCatalog<typeof values, "minimax"> =
|
||||
flattenModelCatalog("minimax", values);
|
||||
export const MINIMAX_MODELS: ChatModelCatalog<typeof values, "minimax"> =
|
||||
flattenChatModelCatalog("minimax", values);
|
||||
|
||||
export const MINIMAX_IMAGE_MODELS: ImageModelCatalog<typeof values, "minimax"> =
|
||||
flattenImageModelCatalog("minimax", values);
|
||||
|
||||
export const MINIMAX_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "minimax"> =
|
||||
flattenClassifierModelCatalog("minimax", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/mistral.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const MISTRAL_MODELS: ModelCatalog<typeof values, "mistral"> =
|
||||
flattenModelCatalog("mistral", values);
|
||||
export const MISTRAL_MODELS: ChatModelCatalog<typeof values, "mistral"> =
|
||||
flattenChatModelCatalog("mistral", values);
|
||||
|
||||
export const MISTRAL_IMAGE_MODELS: ImageModelCatalog<typeof values, "mistral"> =
|
||||
flattenImageModelCatalog("mistral", values);
|
||||
|
||||
export const MISTRAL_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "mistral"> =
|
||||
flattenClassifierModelCatalog("mistral", values);
|
||||
|
||||
96
third_party/pi/packages/ai/src/providers/model-schema.ts
vendored
Normal file
96
third_party/pi/packages/ai/src/providers/model-schema.ts
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
import { type Static, type TSchemaOptions, Type } from "typebox";
|
||||
|
||||
export const THINKING_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max"] as const;
|
||||
export const MODEL_THINKING_LEVELS = ["off", ...THINKING_LEVELS] as const;
|
||||
export const MODEL_INPUT_MODALITIES = ["text", "image"] as const;
|
||||
export const CACHE_RETENTIONS = ["none", "short", "long"] as const;
|
||||
export const MODEL_PROMPT_CACHE_RETENTIONS = ["short", "long"] as const;
|
||||
|
||||
export const ThinkingLevelSchema = Type.Enum(THINKING_LEVELS);
|
||||
export const ModelThinkingLevelSchema = Type.Enum(MODEL_THINKING_LEVELS);
|
||||
export const ModelInputModalitySchema = Type.Enum(MODEL_INPUT_MODALITIES);
|
||||
export const CacheRetentionSchema = Type.Enum(CACHE_RETENTIONS);
|
||||
|
||||
const ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);
|
||||
export const ThinkingLevelMapSchema = Type.Partial(Type.Record(ModelThinkingLevelSchema, ThinkingLevelMapValueSchema));
|
||||
|
||||
export const ModelPromptCacheSchema = Type.Partial(
|
||||
Type.Record(Type.Enum(MODEL_PROMPT_CACHE_RETENTIONS), Type.Number({ exclusiveMinimum: 0 })),
|
||||
{
|
||||
description:
|
||||
"Best-effort prompt cache lifetime in seconds for each retention tier. A missing tier means the lifetime is unknown, so Pi does not warm it.",
|
||||
},
|
||||
);
|
||||
|
||||
const ModelCostRatesProperties = {
|
||||
input: Type.Number({ description: "Input cost in USD per million tokens." }),
|
||||
output: Type.Number({ description: "Output cost in USD per million tokens." }),
|
||||
cacheRead: Type.Number({ description: "Cache-read cost in USD per million tokens." }),
|
||||
cacheWrite: Type.Number({ description: "Cache-write cost in USD per million tokens." }),
|
||||
};
|
||||
|
||||
export const ModelCostRatesSchema = Type.Object(ModelCostRatesProperties);
|
||||
export const ModelCostTierSchema = Type.Object({
|
||||
inputTokensAbove: Type.Number({
|
||||
description: "Use this tier when total request input exceeds this token count.",
|
||||
}),
|
||||
...ModelCostRatesProperties,
|
||||
});
|
||||
export const ModelCostSchema = Type.Object({
|
||||
...ModelCostRatesProperties,
|
||||
tiers: Type.Optional(
|
||||
Type.Array(ModelCostTierSchema, {
|
||||
description: "Request-wide pricing tiers. The highest matching input threshold applies to the full request.",
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
function modelImageResizeOptions(options?: TSchemaOptions) {
|
||||
return Type.Object(
|
||||
{
|
||||
maxWidth: Type.Optional(Type.Integer({ minimum: 1 })),
|
||||
maxHeight: Type.Optional(Type.Integer({ minimum: 1 })),
|
||||
maxBytes: Type.Optional(
|
||||
Type.Integer({ minimum: 1, description: "Maximum base64-encoded payload size in bytes." }),
|
||||
),
|
||||
jpegQuality: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 })),
|
||||
},
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
export const ModelImageResizeOptionsSchema = modelImageResizeOptions();
|
||||
|
||||
export const ModelImageInputLimitsSchema = Type.Object({
|
||||
resize: Type.Optional(
|
||||
modelImageResizeOptions({
|
||||
description: "Cache-safe resize profile applied before a new image enters conversation history.",
|
||||
}),
|
||||
),
|
||||
maxPerMessage: Type.Optional(
|
||||
Type.Integer({ minimum: 1, description: "Maximum images accepted in one provider message." }),
|
||||
),
|
||||
maxPerRequest: Type.Optional(
|
||||
Type.Integer({ minimum: 1, description: "Maximum images accepted across one provider request." }),
|
||||
),
|
||||
});
|
||||
|
||||
export const ModelInputLimitsSchema = Type.Object({
|
||||
maxRequestBytes: Type.Optional(
|
||||
Type.Integer({ minimum: 1, description: "Maximum serialized provider request size in bytes." }),
|
||||
),
|
||||
images: Type.Optional(ModelImageInputLimitsSchema),
|
||||
});
|
||||
|
||||
export type ThinkingLevel = Static<typeof ThinkingLevelSchema>;
|
||||
export type ModelThinkingLevel = Static<typeof ModelThinkingLevelSchema>;
|
||||
export type ThinkingLevelMap = Static<typeof ThinkingLevelMapSchema>;
|
||||
export type ModelInputModality = Static<typeof ModelInputModalitySchema>;
|
||||
export type CacheRetention = Static<typeof CacheRetentionSchema>;
|
||||
export type ModelPromptCache = Static<typeof ModelPromptCacheSchema>;
|
||||
export type ModelCostRates = Static<typeof ModelCostRatesSchema>;
|
||||
export type ModelCostTier = Static<typeof ModelCostTierSchema>;
|
||||
export type ModelCost = Static<typeof ModelCostSchema>;
|
||||
export type ModelImageResizeOptions = Static<typeof ModelImageResizeOptionsSchema>;
|
||||
export type ModelImageInputLimits = Static<typeof ModelImageInputLimitsSchema>;
|
||||
export type ModelInputLimits = Static<typeof ModelInputLimitsSchema>;
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/moonshotai-cn.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const MOONSHOTAI_CN_MODELS: ModelCatalog<typeof values, "moonshotai-cn"> =
|
||||
flattenModelCatalog("moonshotai-cn", values);
|
||||
export const MOONSHOTAI_CN_MODELS: ChatModelCatalog<typeof values, "moonshotai-cn"> =
|
||||
flattenChatModelCatalog("moonshotai-cn", values);
|
||||
|
||||
export const MOONSHOTAI_CN_IMAGE_MODELS: ImageModelCatalog<typeof values, "moonshotai-cn"> =
|
||||
flattenImageModelCatalog("moonshotai-cn", values);
|
||||
|
||||
export const MOONSHOTAI_CN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "moonshotai-cn"> =
|
||||
flattenClassifierModelCatalog("moonshotai-cn", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/moonshotai.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const MOONSHOTAI_MODELS: ModelCatalog<typeof values, "moonshotai"> =
|
||||
flattenModelCatalog("moonshotai", values);
|
||||
export const MOONSHOTAI_MODELS: ChatModelCatalog<typeof values, "moonshotai"> =
|
||||
flattenChatModelCatalog("moonshotai", values);
|
||||
|
||||
export const MOONSHOTAI_IMAGE_MODELS: ImageModelCatalog<typeof values, "moonshotai"> =
|
||||
flattenImageModelCatalog("moonshotai", values);
|
||||
|
||||
export const MOONSHOTAI_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "moonshotai"> =
|
||||
flattenClassifierModelCatalog("moonshotai", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/nvidia.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const NVIDIA_MODELS: ModelCatalog<typeof values, "nvidia"> =
|
||||
flattenModelCatalog("nvidia", values);
|
||||
export const NVIDIA_MODELS: ChatModelCatalog<typeof values, "nvidia"> =
|
||||
flattenChatModelCatalog("nvidia", values);
|
||||
|
||||
export const NVIDIA_IMAGE_MODELS: ImageModelCatalog<typeof values, "nvidia"> =
|
||||
flattenImageModelCatalog("nvidia", values);
|
||||
|
||||
export const NVIDIA_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "nvidia"> =
|
||||
flattenClassifierModelCatalog("nvidia", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/openai-codex.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const OPENAI_CODEX_MODELS: ModelCatalog<typeof values, "openai-codex"> =
|
||||
flattenModelCatalog("openai-codex", values);
|
||||
export const OPENAI_CODEX_MODELS: ChatModelCatalog<typeof values, "openai-codex"> =
|
||||
flattenChatModelCatalog("openai-codex", values);
|
||||
|
||||
export const OPENAI_CODEX_IMAGE_MODELS: ImageModelCatalog<typeof values, "openai-codex"> =
|
||||
flattenImageModelCatalog("openai-codex", values);
|
||||
|
||||
export const OPENAI_CODEX_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "openai-codex"> =
|
||||
flattenClassifierModelCatalog("openai-codex", values);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { OPENAI_CODEX_MODELS } from "./openai-codex.models.ts";
|
||||
export function openaiCodexProvider(): Provider<"openai-codex-responses"> {
|
||||
return createProvider({
|
||||
id: "openai-codex",
|
||||
name: "OpenAI Codex",
|
||||
name: "OpenAI Codex (legacy)",
|
||||
baseUrl: "https://chatgpt.com/backend-api",
|
||||
auth: {
|
||||
oauth: lazyOAuth({
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/openai.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const OPENAI_MODELS: ModelCatalog<typeof values, "openai"> =
|
||||
flattenModelCatalog("openai", values);
|
||||
export const OPENAI_MODELS: ChatModelCatalog<typeof values, "openai"> =
|
||||
flattenChatModelCatalog("openai", values);
|
||||
|
||||
export const OPENAI_IMAGE_MODELS: ImageModelCatalog<typeof values, "openai"> =
|
||||
flattenImageModelCatalog("openai", values);
|
||||
|
||||
export const OPENAI_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "openai"> =
|
||||
flattenClassifierModelCatalog("openai", values);
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
import { openAIDecisionsApi } from "../api/openai-decisions.lazy.ts";
|
||||
import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { OPENAI_MODELS } from "./openai.models.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadOpenAIChatGPTOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, isModelType, type Provider } from "../models.ts";
|
||||
import type { ClassifierModel } from "../types.ts";
|
||||
import { OPENAI_CLASSIFIER_MODELS, OPENAI_MODELS } from "./openai.models.ts";
|
||||
|
||||
export function openaiProvider(): Provider<"openai-responses"> {
|
||||
return createProvider({
|
||||
return createProvider<"openai-responses">({
|
||||
id: "openai",
|
||||
name: "OpenAI",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
auth: { apiKey: envApiKeyAuth("OpenAI API key", ["OPENAI_API_KEY"]) },
|
||||
models: Object.values(OPENAI_MODELS),
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("OpenAI API key", ["OPENAI_API_KEY"]),
|
||||
oauth: lazyOAuth({
|
||||
name: "OpenAI (ChatGPT subscription)",
|
||||
isSubscription: true,
|
||||
loginLabel: "Sign in with ChatGPT",
|
||||
load: loadOpenAIChatGPTOAuth,
|
||||
}),
|
||||
},
|
||||
models: [
|
||||
...Object.values(OPENAI_MODELS),
|
||||
...Object.values<ClassifierModel<"openai-decisions">>(OPENAI_CLASSIFIER_MODELS),
|
||||
],
|
||||
// Sign in with ChatGPT tokens only reach the Responses API; the Decisions API rejects them.
|
||||
filterAllModels: (models, credential) =>
|
||||
credential?.type === "oauth" ? models.filter((model) => !isModelType(model, "classifier")) : models,
|
||||
api: openAIResponsesApi(),
|
||||
classifiers: {
|
||||
"openai-decisions": openAIDecisionsApi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/opencode-go.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const OPENCODE_GO_MODELS: ModelCatalog<typeof values, "opencode-go"> =
|
||||
flattenModelCatalog("opencode-go", values);
|
||||
export const OPENCODE_GO_MODELS: ChatModelCatalog<typeof values, "opencode-go"> =
|
||||
flattenChatModelCatalog("opencode-go", values);
|
||||
|
||||
export const OPENCODE_GO_IMAGE_MODELS: ImageModelCatalog<typeof values, "opencode-go"> =
|
||||
flattenImageModelCatalog("opencode-go", values);
|
||||
|
||||
export const OPENCODE_GO_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "opencode-go"> =
|
||||
flattenClassifierModelCatalog("opencode-go", values);
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { googleGenerativeAIApi } from "../api/google-generative-ai.lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { OPENCODE_GO_MODELS } from "./opencode-go.models.ts";
|
||||
import { withOpenCodeSessionHeader } from "./opencode-headers.ts";
|
||||
|
||||
export function opencodeGoProvider(): Provider<"anthropic-messages" | "openai-completions" | "openai-responses"> {
|
||||
return createProvider<"anthropic-messages" | "openai-completions" | "openai-responses">({
|
||||
type OpenCodeGoApi = "anthropic-messages" | "google-generative-ai" | "openai-completions" | "openai-responses";
|
||||
|
||||
export function opencodeGoProvider(): Provider<OpenCodeGoApi> {
|
||||
return createProvider<OpenCodeGoApi>({
|
||||
id: "opencode-go",
|
||||
name: "OpenCode Go",
|
||||
auth: { apiKey: envApiKeyAuth("OpenCode API key", ["OPENCODE_API_KEY"]) },
|
||||
models: Object.values(OPENCODE_GO_MODELS),
|
||||
api: {
|
||||
"anthropic-messages": anthropicMessagesApi(),
|
||||
"openai-completions": openAICompletionsApi(),
|
||||
"openai-responses": openAIResponsesApi(),
|
||||
"anthropic-messages": withOpenCodeSessionHeader(anthropicMessagesApi()),
|
||||
"google-generative-ai": withOpenCodeSessionHeader(googleGenerativeAIApi()),
|
||||
"openai-completions": withOpenCodeSessionHeader(openAICompletionsApi()),
|
||||
"openai-responses": withOpenCodeSessionHeader(openAIResponsesApi()),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
25
third_party/pi/packages/ai/src/providers/opencode-headers.ts
vendored
Normal file
25
third_party/pi/packages/ai/src/providers/opencode-headers.ts
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { ProviderHeaders, ProviderStreams, StreamOptions } from "../types.ts";
|
||||
|
||||
const OPENCODE_SESSION_HEADER = "x-opencode-session";
|
||||
|
||||
function hasHeader(headers: ProviderHeaders | undefined, name: string): boolean {
|
||||
const expected = name.toLowerCase();
|
||||
return Object.keys(headers ?? {}).some((key) => key.toLowerCase() === expected);
|
||||
}
|
||||
|
||||
function withSessionHeader<TOptions extends StreamOptions>(options: TOptions | undefined): TOptions | undefined {
|
||||
if (!options?.sessionId || hasHeader(options.headers, OPENCODE_SESSION_HEADER)) return options;
|
||||
return {
|
||||
...options,
|
||||
headers: { ...options.headers, [OPENCODE_SESSION_HEADER]: options.sessionId },
|
||||
};
|
||||
}
|
||||
|
||||
/** Adds OpenCode's required per-conversation routing header before API dispatch. */
|
||||
export function withOpenCodeSessionHeader(streams: ProviderStreams): ProviderStreams {
|
||||
return {
|
||||
...streams,
|
||||
stream: (model, context, options) => streams.stream(model, context, withSessionHeader(options)),
|
||||
streamSimple: (model, context, options) => streams.streamSimple(model, context, withSessionHeader(options)),
|
||||
};
|
||||
}
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/opencode.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const OPENCODE_MODELS: ModelCatalog<typeof values, "opencode"> =
|
||||
flattenModelCatalog("opencode", values);
|
||||
export const OPENCODE_MODELS: ChatModelCatalog<typeof values, "opencode"> =
|
||||
flattenChatModelCatalog("opencode", values);
|
||||
|
||||
export const OPENCODE_IMAGE_MODELS: ImageModelCatalog<typeof values, "opencode"> =
|
||||
flattenImageModelCatalog("opencode", values);
|
||||
|
||||
export const OPENCODE_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "opencode"> =
|
||||
flattenClassifierModelCatalog("opencode", values);
|
||||
|
||||
@@ -2,23 +2,27 @@ import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { googleGenerativeAIApi } from "../api/google-generative-ai.lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { openAIResponsesApi } from "../api/openai-responses.lazy.ts";
|
||||
import { typesafeSystemOneApi } from "../api/typesafe-system-one.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { OPENCODE_MODELS } from "./opencode.models.ts";
|
||||
import { OPENCODE_CLASSIFIER_MODELS, OPENCODE_MODELS } from "./opencode.models.ts";
|
||||
import { withOpenCodeSessionHeader } from "./opencode-headers.ts";
|
||||
|
||||
export function opencodeProvider(): Provider<
|
||||
"anthropic-messages" | "google-generative-ai" | "openai-completions" | "openai-responses"
|
||||
> {
|
||||
return createProvider({
|
||||
type OpenCodeApi = "anthropic-messages" | "google-generative-ai" | "openai-completions" | "openai-responses";
|
||||
|
||||
export function opencodeProvider(): Provider<OpenCodeApi> {
|
||||
return createProvider<OpenCodeApi>({
|
||||
id: "opencode",
|
||||
name: "OpenCode Zen",
|
||||
auth: { apiKey: envApiKeyAuth("OpenCode API key", ["OPENCODE_API_KEY"]) },
|
||||
models: Object.values(OPENCODE_MODELS),
|
||||
models: [...Object.values(OPENCODE_MODELS), ...Object.values(OPENCODE_CLASSIFIER_MODELS)],
|
||||
api: {
|
||||
"anthropic-messages": anthropicMessagesApi(),
|
||||
"google-generative-ai": googleGenerativeAIApi(),
|
||||
"openai-completions": openAICompletionsApi(),
|
||||
"openai-responses": openAIResponsesApi(),
|
||||
"anthropic-messages": withOpenCodeSessionHeader(anthropicMessagesApi()),
|
||||
"google-generative-ai": withOpenCodeSessionHeader(googleGenerativeAIApi()),
|
||||
"openai-completions": withOpenCodeSessionHeader(openAICompletionsApi()),
|
||||
"openai-responses": withOpenCodeSessionHeader(openAIResponsesApi()),
|
||||
},
|
||||
// OpenCode Zen serves TypeSafe's System One protocol at /zen/v1/systemone.
|
||||
classifiers: { "typesafe-system-one": typesafeSystemOneApi() },
|
||||
});
|
||||
}
|
||||
|
||||
77
third_party/pi/packages/ai/src/providers/openrouter-api.ts
vendored
Normal file
77
third_party/pi/packages/ai/src/providers/openrouter-api.ts
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { ModelCost, ModelCostTier } from "../types.ts";
|
||||
|
||||
/** OpenRouter's per-token prices, as decimal strings. */
|
||||
export interface OpenRouterPricing {
|
||||
prompt?: string;
|
||||
completion?: string;
|
||||
input_cache_read?: string;
|
||||
input_cache_write?: string;
|
||||
overrides?: OpenRouterPricingOverride[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A conditional price. `min_prompt_tokens` selects prompt-length pricing; `utc_*` fields select
|
||||
* time-of-day or weekday pricing. Missing rates keep the base price.
|
||||
*/
|
||||
export interface OpenRouterPricingOverride {
|
||||
min_prompt_tokens?: number;
|
||||
utc_start?: number;
|
||||
utc_end?: number;
|
||||
utc_days?: string[];
|
||||
prompt?: string;
|
||||
completion?: string;
|
||||
input_cache_read?: string;
|
||||
input_cache_write?: string;
|
||||
}
|
||||
|
||||
/** The fields pi reads from a model in OpenRouter's `GET /models` and `GET /models/user`. */
|
||||
export interface OpenRouterModel {
|
||||
id: string;
|
||||
context_length?: number | null;
|
||||
top_provider?: { context_length?: number | null; max_completion_tokens?: number | null };
|
||||
pricing?: OpenRouterPricing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert one $/token price to $/1M tokens. 0 means free. Missing, invalid and negative prices use
|
||||
* the fallback: OpenRouter reports -1 for router models such as `openrouter/auto`, whose price
|
||||
* depends on the model they pick.
|
||||
*/
|
||||
function perMillion(value: string | undefined, fallback: number): number {
|
||||
const perToken = Number.parseFloat(value ?? "");
|
||||
return perToken >= 0 ? Number((perToken * 1_000_000).toFixed(6)) : fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert OpenRouter's $/token prices to pi's $/1M tokens. Missing, invalid and negative base
|
||||
* prices are 0. Prompt-length overrides become request-wide tiers; a rate a tier does not list
|
||||
* keeps the base price. Time-of-day overrides are skipped because ModelCost cannot express them.
|
||||
*/
|
||||
export function openRouterCost(pricing: OpenRouterPricing | undefined): ModelCost {
|
||||
const base = {
|
||||
input: perMillion(pricing?.prompt, 0),
|
||||
output: perMillion(pricing?.completion, 0),
|
||||
cacheRead: perMillion(pricing?.input_cache_read, 0),
|
||||
cacheWrite: perMillion(pricing?.input_cache_write, 0),
|
||||
};
|
||||
const tiers = (pricing?.overrides ?? []).flatMap((override): ModelCostTier[] => {
|
||||
if (
|
||||
override.min_prompt_tokens === undefined ||
|
||||
override.utc_start !== undefined ||
|
||||
override.utc_end !== undefined ||
|
||||
override.utc_days !== undefined
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
inputTokensAbove: override.min_prompt_tokens,
|
||||
input: perMillion(override.prompt, base.input),
|
||||
output: perMillion(override.completion, base.output),
|
||||
cacheRead: perMillion(override.input_cache_read, base.cacheRead),
|
||||
cacheWrite: perMillion(override.input_cache_write, base.cacheWrite),
|
||||
},
|
||||
];
|
||||
});
|
||||
return tiers.length > 0 ? { ...base, tiers } : base;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { openrouterImagesApi } from "../api/openrouter-images.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadOpenRouterOAuth } from "../auth/oauth/load.ts";
|
||||
import { IMAGE_MODELS } from "../image-models.generated.ts";
|
||||
import { createImagesProvider, type ImagesProvider } from "../images-models.ts";
|
||||
|
||||
export function openrouterImagesProvider(): ImagesProvider {
|
||||
return createImagesProvider({
|
||||
id: "openrouter",
|
||||
name: "OpenRouter",
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("OpenRouter API key", ["OPENROUTER_API_KEY"]),
|
||||
oauth: lazyOAuth({
|
||||
name: "OpenRouter OAuth",
|
||||
loginLabel: "Sign in with OpenRouter",
|
||||
load: loadOpenRouterOAuth,
|
||||
}),
|
||||
},
|
||||
models: Object.values(IMAGE_MODELS.openrouter),
|
||||
api: openrouterImagesApi(),
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/openrouter.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const OPENROUTER_MODELS: ModelCatalog<typeof values, "openrouter"> =
|
||||
flattenModelCatalog("openrouter", values);
|
||||
export const OPENROUTER_MODELS: ChatModelCatalog<typeof values, "openrouter"> =
|
||||
flattenChatModelCatalog("openrouter", values);
|
||||
|
||||
export const OPENROUTER_IMAGE_MODELS: ImageModelCatalog<typeof values, "openrouter"> =
|
||||
flattenImageModelCatalog("openrouter", values);
|
||||
|
||||
export const OPENROUTER_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "openrouter"> =
|
||||
flattenClassifierModelCatalog("openrouter", values);
|
||||
|
||||
@@ -1,15 +1,69 @@
|
||||
import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { openAICompletionsApi } from "../api/openai-completions.lazy.ts";
|
||||
import { openrouterImagesApi } from "../api/openrouter-images.lazy.ts";
|
||||
import { typesafeSystemOneApi } from "../api/typesafe-system-one.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadOpenRouterOAuth } from "../auth/oauth/load.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { OPENROUTER_MODELS } from "./openrouter.models.ts";
|
||||
import { createProvider, type Provider, type RefreshModelsContext } from "../models.ts";
|
||||
import type { AnyModel } from "../types.ts";
|
||||
import { isModelType } from "../utils/model-operations.ts";
|
||||
import { OPENROUTER_CLASSIFIER_MODELS, OPENROUTER_IMAGE_MODELS, OPENROUTER_MODELS } from "./openrouter.models.ts";
|
||||
import { type OpenRouterModel, openRouterCost } from "./openrouter-api.ts";
|
||||
|
||||
const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
||||
const OPENROUTER_USER_MODELS_TIMEOUT_MS = 15_000;
|
||||
|
||||
/**
|
||||
* Restrict an OpenRouter catalog to the chat models the key may use, with the key's limits and
|
||||
* prices from `GET /models/user`. Image and classifier models are returned unchanged. A missing
|
||||
* limit keeps the catalog value. The request uses the provider's configured base URL, so regional
|
||||
* endpoints such as `https://us.openrouter.ai/api/v1` apply their region's filtering. When the
|
||||
* endpoint rejects the key (401/403) or does not exist (404), for example with a proxy configured
|
||||
* in models.json, the catalog is returned unchanged.
|
||||
*/
|
||||
export async function personalizeOpenRouterCatalog(
|
||||
catalog: readonly AnyModel[],
|
||||
context: RefreshModelsContext,
|
||||
): Promise<readonly AnyModel[]> {
|
||||
const key = context.credential?.type === "oauth" ? context.credential.access : context.credential?.key;
|
||||
if (!key) return catalog;
|
||||
const response = await fetch(`${(context.baseUrl ?? OPENROUTER_BASE_URL).replace(/\/+$/, "")}/models/user`, {
|
||||
headers: { accept: "application/json", authorization: `Bearer ${key}` },
|
||||
signal: AbortSignal.any([context.signal, AbortSignal.timeout(OPENROUTER_USER_MODELS_TIMEOUT_MS)]),
|
||||
});
|
||||
if (response.status === 401 || response.status === 403 || response.status === 404) return catalog;
|
||||
if (!response.ok) throw new Error(`OpenRouter model list request failed: ${response.status}`);
|
||||
const body: unknown = await response.json();
|
||||
if (typeof body !== "object" || body === null || !("data" in body) || !Array.isArray(body.data)) {
|
||||
throw new Error("Invalid OpenRouter model list response");
|
||||
}
|
||||
const allowed = new Map<string, OpenRouterModel>();
|
||||
for (const entry of body.data as unknown[]) {
|
||||
if (typeof entry === "object" && entry !== null && "id" in entry && typeof entry.id === "string") {
|
||||
allowed.set(entry.id, entry as OpenRouterModel);
|
||||
}
|
||||
}
|
||||
return catalog.flatMap((model): AnyModel[] => {
|
||||
if (!isModelType(model, "chat")) return [model];
|
||||
const entry = allowed.get(model.id);
|
||||
if (!entry) return [];
|
||||
return [
|
||||
{
|
||||
...model,
|
||||
// `||`: OpenRouter reports a missing limit as absent, null or 0, like the generator's fallback.
|
||||
contextWindow: entry.top_provider?.context_length || entry.context_length || model.contextWindow,
|
||||
maxTokens: entry.top_provider?.max_completion_tokens || model.maxTokens,
|
||||
cost: entry.pricing ? openRouterCost(entry.pricing) : model.cost,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
export function openrouterProvider(): Provider<"anthropic-messages" | "openai-completions"> {
|
||||
return createProvider({
|
||||
return createProvider<"anthropic-messages" | "openai-completions">({
|
||||
id: "openrouter",
|
||||
name: "OpenRouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
baseUrl: OPENROUTER_BASE_URL,
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("OpenRouter API key", ["OPENROUTER_API_KEY"]),
|
||||
oauth: lazyOAuth({
|
||||
@@ -18,10 +72,17 @@ export function openrouterProvider(): Provider<"anthropic-messages" | "openai-co
|
||||
load: loadOpenRouterOAuth,
|
||||
}),
|
||||
},
|
||||
models: Object.values(OPENROUTER_MODELS),
|
||||
models: [
|
||||
...Object.values(OPENROUTER_MODELS),
|
||||
...Object.values(OPENROUTER_IMAGE_MODELS),
|
||||
...Object.values(OPENROUTER_CLASSIFIER_MODELS),
|
||||
],
|
||||
api: {
|
||||
"anthropic-messages": anthropicMessagesApi(),
|
||||
"openai-completions": openAICompletionsApi(),
|
||||
},
|
||||
images: { "openrouter-images": openrouterImagesApi() },
|
||||
// OpenRouter serves TypeSafe's System One protocol at /api/v1/systemone.
|
||||
classifiers: { "typesafe-system-one": typesafeSystemOneApi() },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/qwen-token-plan-cn.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const QWEN_TOKEN_PLAN_CN_MODELS: ModelCatalog<typeof values, "qwen-token-plan-cn"> =
|
||||
flattenModelCatalog("qwen-token-plan-cn", values);
|
||||
export const QWEN_TOKEN_PLAN_CN_MODELS: ChatModelCatalog<typeof values, "qwen-token-plan-cn"> =
|
||||
flattenChatModelCatalog("qwen-token-plan-cn", values);
|
||||
|
||||
export const QWEN_TOKEN_PLAN_CN_IMAGE_MODELS: ImageModelCatalog<typeof values, "qwen-token-plan-cn"> =
|
||||
flattenImageModelCatalog("qwen-token-plan-cn", values);
|
||||
|
||||
export const QWEN_TOKEN_PLAN_CN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "qwen-token-plan-cn"> =
|
||||
flattenClassifierModelCatalog("qwen-token-plan-cn", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/qwen-token-plan-individual.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS: ModelCatalog<typeof values, "qwen-token-plan-individual"> =
|
||||
flattenModelCatalog("qwen-token-plan-individual", values);
|
||||
export const QWEN_TOKEN_PLAN_INDIVIDUAL_MODELS: ChatModelCatalog<typeof values, "qwen-token-plan-individual"> =
|
||||
flattenChatModelCatalog("qwen-token-plan-individual", values);
|
||||
|
||||
export const QWEN_TOKEN_PLAN_INDIVIDUAL_IMAGE_MODELS: ImageModelCatalog<typeof values, "qwen-token-plan-individual"> =
|
||||
flattenImageModelCatalog("qwen-token-plan-individual", values);
|
||||
|
||||
export const QWEN_TOKEN_PLAN_INDIVIDUAL_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "qwen-token-plan-individual"> =
|
||||
flattenClassifierModelCatalog("qwen-token-plan-individual", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/qwen-token-plan.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const QWEN_TOKEN_PLAN_MODELS: ModelCatalog<typeof values, "qwen-token-plan"> =
|
||||
flattenModelCatalog("qwen-token-plan", values);
|
||||
export const QWEN_TOKEN_PLAN_MODELS: ChatModelCatalog<typeof values, "qwen-token-plan"> =
|
||||
flattenChatModelCatalog("qwen-token-plan", values);
|
||||
|
||||
export const QWEN_TOKEN_PLAN_IMAGE_MODELS: ImageModelCatalog<typeof values, "qwen-token-plan"> =
|
||||
flattenImageModelCatalog("qwen-token-plan", values);
|
||||
|
||||
export const QWEN_TOKEN_PLAN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "qwen-token-plan"> =
|
||||
flattenClassifierModelCatalog("qwen-token-plan", values);
|
||||
|
||||
14
third_party/pi/packages/ai/src/providers/radius.models.ts
vendored
Normal file
14
third_party/pi/packages/ai/src/providers/radius.models.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is auto-generated by scripts/generate-models.ts
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/radius.json" with { type: "json" };
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const RADIUS_MODELS: ChatModelCatalog<typeof values, "radius"> =
|
||||
flattenChatModelCatalog("radius", values);
|
||||
|
||||
export const RADIUS_IMAGE_MODELS: ImageModelCatalog<typeof values, "radius"> =
|
||||
flattenImageModelCatalog("radius", values);
|
||||
|
||||
export const RADIUS_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "radius"> =
|
||||
flattenClassifierModelCatalog("radius", values);
|
||||
@@ -2,6 +2,8 @@ import { piMessagesApi } from "../api/pi-messages.lazy.ts";
|
||||
import { envApiKeyAuth, lazyOAuth } from "../auth/helpers.ts";
|
||||
import { loadRadiusOAuth } from "../auth/oauth/load.ts";
|
||||
import type { Provider } from "../models.ts";
|
||||
import type { Model } from "../types.ts";
|
||||
import { RADIUS_MODELS } from "./radius.models.ts";
|
||||
import {
|
||||
DEFAULT_RADIUS_GATEWAY,
|
||||
getRadiusModels,
|
||||
@@ -21,7 +23,13 @@ export function radiusProvider(options: RadiusProviderOptions = {}): Provider<"p
|
||||
const id = options.id ?? "radius";
|
||||
const name = options.name ?? "Radius";
|
||||
const gateway = normalizeRadiusGatewayUrl(options.gateway ?? DEFAULT_RADIUS_GATEWAY);
|
||||
let models = getRadiusModels(id, undefined);
|
||||
const baselineModels: Model<"pi-messages">[] =
|
||||
gateway === normalizeRadiusGatewayUrl(DEFAULT_RADIUS_GATEWAY)
|
||||
? Object.values(RADIUS_MODELS).map((model) => ({ ...model, provider: id }))
|
||||
: [];
|
||||
// Gateway catalog for this account. Radius org owners can disable models, so once known it replaces
|
||||
// the shipped baseline instead of overlaying it. The baseline only covers the time before any catalog exists.
|
||||
let dynamicModels: Model<"pi-messages">[] | undefined;
|
||||
const streams = piMessagesApi();
|
||||
|
||||
return {
|
||||
@@ -31,15 +39,15 @@ export function radiusProvider(options: RadiusProviderOptions = {}): Provider<"p
|
||||
apiKey: envApiKeyAuth("Radius API key", ["RADIUS_API_KEY"]),
|
||||
oauth: lazyOAuth({ name, load: () => loadRadiusOAuth({ name, gateway }) }),
|
||||
},
|
||||
getModels: () => models,
|
||||
getModels: () => dynamicModels ?? baselineModels,
|
||||
refreshModels: async (context) => {
|
||||
const stored = context.stored;
|
||||
if (stored) {
|
||||
const restored = stored.models.filter((model) => model.provider === id) as typeof models;
|
||||
const restored = stored.models.filter((model) => model.provider === id) as Model<"pi-messages">[];
|
||||
if (
|
||||
!(await context.publish({
|
||||
update: () => {
|
||||
models = restored;
|
||||
dynamicModels = restored;
|
||||
},
|
||||
}))
|
||||
) {
|
||||
@@ -55,7 +63,7 @@ export function radiusProvider(options: RadiusProviderOptions = {}): Provider<"p
|
||||
!(await context.publish({
|
||||
persist: { models: legacy, checkedAt: Date.now() },
|
||||
update: () => {
|
||||
models = legacy;
|
||||
dynamicModels = legacy;
|
||||
},
|
||||
}))
|
||||
) {
|
||||
@@ -72,7 +80,7 @@ export function radiusProvider(options: RadiusProviderOptions = {}): Provider<"p
|
||||
await context.publish({
|
||||
persist: { models: refreshed, checkedAt: Date.now() },
|
||||
update: () => {
|
||||
models = refreshed;
|
||||
dynamicModels = refreshed;
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/together.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const TOGETHER_MODELS: ModelCatalog<typeof values, "together"> =
|
||||
flattenModelCatalog("together", values);
|
||||
export const TOGETHER_MODELS: ChatModelCatalog<typeof values, "together"> =
|
||||
flattenChatModelCatalog("together", values);
|
||||
|
||||
export const TOGETHER_IMAGE_MODELS: ImageModelCatalog<typeof values, "together"> =
|
||||
flattenImageModelCatalog("together", values);
|
||||
|
||||
export const TOGETHER_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "together"> =
|
||||
flattenClassifierModelCatalog("together", values);
|
||||
|
||||
14
third_party/pi/packages/ai/src/providers/typesafe.models.ts
vendored
Normal file
14
third_party/pi/packages/ai/src/providers/typesafe.models.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is auto-generated by scripts/generate-models.ts
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/typesafe.json" with { type: "json" };
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const TYPESAFE_MODELS: ChatModelCatalog<typeof values, "typesafe"> =
|
||||
flattenChatModelCatalog("typesafe", values);
|
||||
|
||||
export const TYPESAFE_IMAGE_MODELS: ImageModelCatalog<typeof values, "typesafe"> =
|
||||
flattenImageModelCatalog("typesafe", values);
|
||||
|
||||
export const TYPESAFE_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "typesafe"> =
|
||||
flattenClassifierModelCatalog("typesafe", values);
|
||||
18
third_party/pi/packages/ai/src/providers/typesafe.ts
vendored
Normal file
18
third_party/pi/packages/ai/src/providers/typesafe.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { typesafeSystemOneApi } from "../api/typesafe-system-one.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { TYPESAFE_CLASSIFIER_MODELS } from "./typesafe.models.ts";
|
||||
|
||||
export function typesafeProvider(): Provider {
|
||||
return createProvider({
|
||||
id: "typesafe",
|
||||
name: "TypeSafe",
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("TypeSafe API key", ["TYPESAFE_API_KEY"]),
|
||||
},
|
||||
models: Object.values(TYPESAFE_CLASSIFIER_MODELS),
|
||||
classifiers: {
|
||||
"typesafe-system-one": typesafeSystemOneApi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/vercel-ai-gateway.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const VERCEL_AI_GATEWAY_MODELS: ModelCatalog<typeof values, "vercel-ai-gateway"> =
|
||||
flattenModelCatalog("vercel-ai-gateway", values);
|
||||
export const VERCEL_AI_GATEWAY_MODELS: ChatModelCatalog<typeof values, "vercel-ai-gateway"> =
|
||||
flattenChatModelCatalog("vercel-ai-gateway", values);
|
||||
|
||||
export const VERCEL_AI_GATEWAY_IMAGE_MODELS: ImageModelCatalog<typeof values, "vercel-ai-gateway"> =
|
||||
flattenImageModelCatalog("vercel-ai-gateway", values);
|
||||
|
||||
export const VERCEL_AI_GATEWAY_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "vercel-ai-gateway"> =
|
||||
flattenClassifierModelCatalog("vercel-ai-gateway", values);
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { anthropicMessagesApi } from "../api/anthropic-messages.lazy.ts";
|
||||
import { typesafeSystemOneApi } from "../api/typesafe-system-one.lazy.ts";
|
||||
import { envApiKeyAuth } from "../auth/helpers.ts";
|
||||
import { createProvider, type Provider } from "../models.ts";
|
||||
import { VERCEL_AI_GATEWAY_MODELS } from "./vercel-ai-gateway.models.ts";
|
||||
import { VERCEL_AI_GATEWAY_CLASSIFIER_MODELS, VERCEL_AI_GATEWAY_MODELS } from "./vercel-ai-gateway.models.ts";
|
||||
|
||||
export function vercelAIGatewayProvider(): Provider<"anthropic-messages"> {
|
||||
return createProvider({
|
||||
return createProvider<"anthropic-messages">({
|
||||
id: "vercel-ai-gateway",
|
||||
name: "Vercel AI Gateway",
|
||||
baseUrl: "https://ai-gateway.vercel.sh",
|
||||
auth: { apiKey: envApiKeyAuth("Vercel AI Gateway API key", ["AI_GATEWAY_API_KEY"]) },
|
||||
models: Object.values(VERCEL_AI_GATEWAY_MODELS),
|
||||
models: [...Object.values(VERCEL_AI_GATEWAY_MODELS), ...Object.values(VERCEL_AI_GATEWAY_CLASSIFIER_MODELS)],
|
||||
api: anthropicMessagesApi(),
|
||||
// AI Gateway serves TypeSafe's System One protocol at /typesafe/v1/systemone.
|
||||
classifiers: { "typesafe-system-one": typesafeSystemOneApi() },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/xai.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const XAI_MODELS: ModelCatalog<typeof values, "xai"> =
|
||||
flattenModelCatalog("xai", values);
|
||||
export const XAI_MODELS: ChatModelCatalog<typeof values, "xai"> =
|
||||
flattenChatModelCatalog("xai", values);
|
||||
|
||||
export const XAI_IMAGE_MODELS: ImageModelCatalog<typeof values, "xai"> =
|
||||
flattenImageModelCatalog("xai", values);
|
||||
|
||||
export const XAI_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "xai"> =
|
||||
flattenClassifierModelCatalog("xai", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/xiaomi-token-plan-ams.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_AMS_MODELS: ModelCatalog<typeof values, "xiaomi-token-plan-ams"> =
|
||||
flattenModelCatalog("xiaomi-token-plan-ams", values);
|
||||
export const XIAOMI_TOKEN_PLAN_AMS_MODELS: ChatModelCatalog<typeof values, "xiaomi-token-plan-ams"> =
|
||||
flattenChatModelCatalog("xiaomi-token-plan-ams", values);
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_AMS_IMAGE_MODELS: ImageModelCatalog<typeof values, "xiaomi-token-plan-ams"> =
|
||||
flattenImageModelCatalog("xiaomi-token-plan-ams", values);
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_AMS_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "xiaomi-token-plan-ams"> =
|
||||
flattenClassifierModelCatalog("xiaomi-token-plan-ams", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/xiaomi-token-plan-cn.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_CN_MODELS: ModelCatalog<typeof values, "xiaomi-token-plan-cn"> =
|
||||
flattenModelCatalog("xiaomi-token-plan-cn", values);
|
||||
export const XIAOMI_TOKEN_PLAN_CN_MODELS: ChatModelCatalog<typeof values, "xiaomi-token-plan-cn"> =
|
||||
flattenChatModelCatalog("xiaomi-token-plan-cn", values);
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_CN_IMAGE_MODELS: ImageModelCatalog<typeof values, "xiaomi-token-plan-cn"> =
|
||||
flattenImageModelCatalog("xiaomi-token-plan-cn", values);
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_CN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "xiaomi-token-plan-cn"> =
|
||||
flattenClassifierModelCatalog("xiaomi-token-plan-cn", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/xiaomi-token-plan-sgp.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_SGP_MODELS: ModelCatalog<typeof values, "xiaomi-token-plan-sgp"> =
|
||||
flattenModelCatalog("xiaomi-token-plan-sgp", values);
|
||||
export const XIAOMI_TOKEN_PLAN_SGP_MODELS: ChatModelCatalog<typeof values, "xiaomi-token-plan-sgp"> =
|
||||
flattenChatModelCatalog("xiaomi-token-plan-sgp", values);
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_SGP_IMAGE_MODELS: ImageModelCatalog<typeof values, "xiaomi-token-plan-sgp"> =
|
||||
flattenImageModelCatalog("xiaomi-token-plan-sgp", values);
|
||||
|
||||
export const XIAOMI_TOKEN_PLAN_SGP_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "xiaomi-token-plan-sgp"> =
|
||||
flattenClassifierModelCatalog("xiaomi-token-plan-sgp", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/xiaomi.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const XIAOMI_MODELS: ModelCatalog<typeof values, "xiaomi"> =
|
||||
flattenModelCatalog("xiaomi", values);
|
||||
export const XIAOMI_MODELS: ChatModelCatalog<typeof values, "xiaomi"> =
|
||||
flattenChatModelCatalog("xiaomi", values);
|
||||
|
||||
export const XIAOMI_IMAGE_MODELS: ImageModelCatalog<typeof values, "xiaomi"> =
|
||||
flattenImageModelCatalog("xiaomi", values);
|
||||
|
||||
export const XIAOMI_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "xiaomi"> =
|
||||
flattenClassifierModelCatalog("xiaomi", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/zai-coding-cn.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const ZAI_CODING_CN_MODELS: ModelCatalog<typeof values, "zai-coding-cn"> =
|
||||
flattenModelCatalog("zai-coding-cn", values);
|
||||
export const ZAI_CODING_CN_MODELS: ChatModelCatalog<typeof values, "zai-coding-cn"> =
|
||||
flattenChatModelCatalog("zai-coding-cn", values);
|
||||
|
||||
export const ZAI_CODING_CN_IMAGE_MODELS: ImageModelCatalog<typeof values, "zai-coding-cn"> =
|
||||
flattenImageModelCatalog("zai-coding-cn", values);
|
||||
|
||||
export const ZAI_CODING_CN_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "zai-coding-cn"> =
|
||||
flattenClassifierModelCatalog("zai-coding-cn", values);
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
// Do not edit manually - run 'npm run generate-models' to update
|
||||
|
||||
import values from "./data/zai.json" with { type: "json" };
|
||||
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
|
||||
import { flattenChatModelCatalog, flattenClassifierModelCatalog, flattenImageModelCatalog, type ChatModelCatalog, type ClassifierModelCatalog, type ImageModelCatalog } from "../model-catalog.ts";
|
||||
|
||||
export const ZAI_MODELS: ModelCatalog<typeof values, "zai"> =
|
||||
flattenModelCatalog("zai", values);
|
||||
export const ZAI_MODELS: ChatModelCatalog<typeof values, "zai"> =
|
||||
flattenChatModelCatalog("zai", values);
|
||||
|
||||
export const ZAI_IMAGE_MODELS: ImageModelCatalog<typeof values, "zai"> =
|
||||
flattenImageModelCatalog("zai", values);
|
||||
|
||||
export const ZAI_CLASSIFIER_MODELS: ClassifierModelCatalog<typeof values, "zai"> =
|
||||
flattenClassifierModelCatalog("zai", values);
|
||||
|
||||
Reference in New Issue
Block a user