@cherrystudio/ai-core
Version:
Cherry Studio AI Core - Unified AI Provider Interface Based on Vercel AI SDK
269 lines (268 loc) • 9.95 kB
text/typescript
import { AnthropicProviderOptions, AnthropicProviderSettings } from "@ai-sdk/anthropic";
import { AzureOpenAIProviderSettings } from "@ai-sdk/azure";
import { DeepSeekProviderSettings } from "@ai-sdk/deepseek";
import { GoogleGenerativeAIProviderOptions, GoogleGenerativeAIProviderSettings } from "@ai-sdk/google";
import { OpenAIProviderSettings, OpenAIResponsesProviderOptions } from "@ai-sdk/openai";
import { OpenAICompatibleProviderSettings } from "@ai-sdk/openai-compatible";
import { XaiProviderSettings } from "@ai-sdk/xai";
import * as ai0 from "ai";
import { LanguageModel, TextStreamPart, ToolSet, generateObject, generateText, streamObject, streamText } from "ai";
import { SharedV2ProviderMetadata } from "@ai-sdk/provider";
import * as z from "zod/v4";
//#region src/core/providers/types.d.ts
/**
* Provider 相关核心类型定义
* 只定义必要的接口,其他类型直接使用 AI SDK
*/
type ProviderId = keyof ProviderSettingsMap & string;
interface ProviderConfig {
id: string;
name: string;
creator?: (options: any) => any;
import?: () => Promise<any>;
creatorFunctionName?: string;
supportsImageGeneration?: boolean;
imageCreator?: (options: any) => any;
validateOptions?: (options: any) => boolean;
}
declare class ProviderError extends Error {
providerId: string;
code?: string | undefined;
cause?: Error | undefined;
constructor(message: string, providerId: string, code?: string | undefined, cause?: Error | undefined);
}
type ProviderSettingsMap = {
openai: OpenAIProviderSettings;
'openai-responses': OpenAIProviderSettings;
'openai-compatible': OpenAICompatibleProviderSettings;
anthropic: AnthropicProviderSettings;
google: GoogleGenerativeAIProviderSettings;
xai: XaiProviderSettings;
azure: AzureOpenAIProviderSettings;
deepseek: DeepSeekProviderSettings;
};
//#endregion
//#region src/core/plugins/types.d.ts
/**
* 递归调用函数类型
* 使用 any 是因为递归调用时参数和返回类型可能完全不同
*/
type RecursiveCallFn = (newParams: any) => Promise<any>;
/**
* AI 请求上下文
*/
interface AiRequestContext {
providerId: ProviderId;
modelId: string;
originalParams: any;
metadata: Record<string, any>;
startTime: number;
requestId: string;
recursiveCall: RecursiveCallFn;
isRecursiveCall?: boolean;
mcpTools?: ToolSet;
[key: string]: any;
}
/**
* 钩子分类
*/
interface AiPlugin {
name: string;
enforce?: 'pre' | 'post';
resolveModel?: (modelId: string, context: AiRequestContext) => Promise<LanguageModel | null> | LanguageModel | null;
loadTemplate?: (templateName: string, context: AiRequestContext) => any | null | Promise<any | null>;
configureContext?: (context: AiRequestContext) => void | Promise<void>;
transformParams?: (params: any, context: AiRequestContext) => any | Promise<any>;
transformResult?: (result: any, context: AiRequestContext) => any | Promise<any>;
onRequestStart?: (context: AiRequestContext) => void | Promise<void>;
onRequestEnd?: (context: AiRequestContext, result: any) => void | Promise<void>;
onError?: (error: Error, context: AiRequestContext) => void | Promise<void>;
transformStream?: (params: any, context: AiRequestContext) => <TOOLS extends ToolSet>(options?: {
tools: TOOLS;
stopStream: () => void;
}) => TransformStream<TextStreamPart<TOOLS>, TextStreamPart<TOOLS>>;
}
/**
* 插件管理器配置
*/
interface PluginManagerConfig {
plugins: AiPlugin[];
context: Partial<AiRequestContext>;
}
/**
* 钩子执行结果
*/
interface HookResult<T = any> {
value: T;
stop?: boolean;
}
//#endregion
//#region src/types.d.ts
type ProviderSettings = ProviderSettingsMap[keyof ProviderSettingsMap];
type StreamTextParams = Omit<Parameters<typeof streamText>[0], 'model'>;
type GenerateTextParams = Omit<Parameters<typeof generateText>[0], 'model'>;
type StreamObjectParams = Omit<Parameters<typeof streamObject>[0], 'model'>;
type GenerateObjectParams = Omit<Parameters<typeof generateObject>[0], 'model'>;
//#endregion
//#region src/core/plugins/manager.d.ts
/**
* 插件管理器
*/
declare class PluginManager {
private plugins;
constructor(plugins?: AiPlugin[]);
/**
* 添加插件
*/
use(plugin: AiPlugin): this;
/**
* 移除插件
*/
remove(pluginName: string): this;
/**
* 插件排序:pre -> normal -> post
*/
private sortPlugins;
/**
* 执行 First 钩子 - 返回第一个有效结果
*/
executeFirst<T>(hookName: 'resolveModel' | 'loadTemplate', arg: any, context: AiRequestContext): Promise<T | null>;
/**
* 执行 Sequential 钩子 - 链式数据转换
*/
executeSequential<T>(hookName: 'transformParams' | 'transformResult', initialValue: T, context: AiRequestContext): Promise<T>;
/**
* 执行 ConfigureContext 钩子 - 串行配置上下文
*/
executeConfigureContext(context: AiRequestContext): Promise<void>;
/**
* 执行 Parallel 钩子 - 并行副作用
*/
executeParallel(hookName: 'onRequestStart' | 'onRequestEnd' | 'onError', context: AiRequestContext, result?: any, error?: Error): Promise<void>;
/**
* 收集所有流转换器(返回数组,AI SDK 原生支持)
*/
collectStreamTransforms(params: any, context: AiRequestContext): ((<TOOLS extends ai0.ToolSet>(options?: {
tools: TOOLS;
stopStream: () => void;
}) => TransformStream<ai0.TextStreamPart<TOOLS>, ai0.TextStreamPart<TOOLS>>) | undefined)[];
/**
* 获取所有插件信息
*/
getPlugins(): AiPlugin[];
/**
* 获取插件统计信息
*/
getStats(): {
total: number;
pre: number;
normal: number;
post: number;
hooks: {
resolveModel: number;
loadTemplate: number;
transformParams: number;
transformResult: number;
onRequestStart: number;
onRequestEnd: number;
onError: number;
transformStream: number;
};
};
}
//#endregion
//#region src/core/plugins/index.d.ts
declare function createContext<T extends ProviderId>(providerId: T, modelId: string, originalParams: any): AiRequestContext;
declare function definePlugin(plugin: AiPlugin): AiPlugin;
declare function definePlugin<T extends (...args: any[]) => AiPlugin>(pluginFactory: T): T;
//#endregion
//#region src/core/options/openrouter.d.ts
type OpenRouterProviderOptions = {
models?: string[];
/**
* https://openrouter.ai/docs/use-cases/reasoning-tokens
* One of `max_tokens` or `effort` is required.
* If `exclude` is true, reasoning will be removed from the response. Default is false.
*/
reasoning?: {
exclude?: boolean;
} & ({
max_tokens: number;
} | {
effort: 'high' | 'medium' | 'low';
});
/**
* A unique identifier representing your end-user, which can
* help OpenRouter to monitor and detect abuse.
*/
user?: string;
extraBody?: Record<string, unknown>;
/**
* Enable usage accounting to get detailed token usage information.
* https://openrouter.ai/docs/use-cases/usage-accounting
*/
usage?: {
/**
* When true, includes token usage information in the response.
*/
include: boolean;
};
};
//#endregion
//#region src/core/options/xai.d.ts
declare const xaiProviderOptions: z.ZodObject<{
reasoningEffort: z.ZodOptional<z.ZodEnum<{
low: "low";
high: "high";
}>>;
searchParameters: z.ZodOptional<z.ZodObject<{
mode: z.ZodEnum<{
auto: "auto";
off: "off";
on: "on";
}>;
returnCitations: z.ZodOptional<z.ZodBoolean>;
fromDate: z.ZodOptional<z.ZodString>;
toDate: z.ZodOptional<z.ZodString>;
maxSearchResults: z.ZodOptional<z.ZodNumber>;
sources: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
type: z.ZodLiteral<"web">;
country: z.ZodOptional<z.ZodString>;
excludedWebsites: z.ZodOptional<z.ZodArray<z.ZodString>>;
allowedWebsites: z.ZodOptional<z.ZodArray<z.ZodString>>;
safeSearch: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>, z.ZodObject<{
type: z.ZodLiteral<"x">;
xHandles: z.ZodOptional<z.ZodArray<z.ZodString>>;
}, z.core.$strip>, z.ZodObject<{
type: z.ZodLiteral<"news">;
country: z.ZodOptional<z.ZodString>;
excludedWebsites: z.ZodOptional<z.ZodArray<z.ZodString>>;
safeSearch: z.ZodOptional<z.ZodBoolean>;
}, z.core.$strip>, z.ZodObject<{
type: z.ZodLiteral<"rss">;
links: z.ZodArray<z.ZodURL>;
}, z.core.$strip>]>>>;
}, z.core.$strip>>;
}, z.core.$strip>;
type XaiProviderOptions = z.infer<typeof xaiProviderOptions>;
//#endregion
//#region src/core/options/types.d.ts
/**
* 供应商选项类型,如果map中没有,说明没有约束
*/
type ProviderOptionsMap = {
openai: OpenAIResponsesProviderOptions;
anthropic: AnthropicProviderOptions;
google: GoogleGenerativeAIProviderOptions;
openrouter: OpenRouterProviderOptions;
xai: XaiProviderOptions;
};
type ExtractProviderOptions<T extends keyof ProviderOptionsMap> = ProviderOptionsMap[T];
/**
* 类型安全的ProviderOptions
* 对于已知供应商使用严格类型,对于未知供应商允许任意Record<string, JSONValue>
*/
type TypedProviderOptions = { [K in keyof ProviderOptionsMap]?: ProviderOptionsMap[K] } & { [K in string]?: Record<string, any> } & SharedV2ProviderMetadata;
//#endregion
export { type AiPlugin, type AiRequestContext, type AnthropicProviderSettings, type AzureOpenAIProviderSettings, type DeepSeekProviderSettings, ExtractProviderOptions, GenerateObjectParams, GenerateTextParams, type GoogleGenerativeAIProviderSettings, type HookResult, type OpenAICompatibleProviderSettings, type OpenAIProviderSettings, PluginManager as PluginManager$1, type PluginManagerConfig, ProviderConfig, ProviderError, type ProviderId, ProviderOptionsMap, ProviderSettings, type ProviderSettingsMap, StreamObjectParams, StreamTextParams, TypedProviderOptions, type XaiProviderSettings, createContext as createContext$1, definePlugin as definePlugin$1 };