@yh-ui/ai-sdk 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,627 @@
1
+ /**
2
+ * Vue-specific AI composables
3
+ *
4
+ * 提供与 YH-UI 组件深度集成的 Vue 3 Composition API
5
+ * 增强版本:多会话支持、XRequest 中间件、缓存重试
6
+ */
7
+ import { type Ref } from 'vue';
8
+ export interface StreamableValue<T = unknown> {
9
+ value: Ref<T>;
10
+ loading: Ref<boolean>;
11
+ error: Ref<Error | null>;
12
+ }
13
+ export interface ConversationMessage {
14
+ id: string;
15
+ role: 'user' | 'assistant' | 'system' | 'tool';
16
+ content: string;
17
+ name?: string;
18
+ toolCallId?: string;
19
+ toolCalls?: ToolCall[];
20
+ createdAt?: Date;
21
+ metadata?: Record<string, unknown>;
22
+ }
23
+ export interface ToolCall {
24
+ id: string;
25
+ type: 'function';
26
+ name: string;
27
+ arguments: Record<string, unknown>;
28
+ }
29
+ export interface ConversationConfig {
30
+ /** 消息历史保留条数 */
31
+ maxHistory?: number;
32
+ /** 是否自动保存到 localStorage */
33
+ persist?: boolean;
34
+ /** localStorage key */
35
+ storageKey?: string;
36
+ }
37
+ export interface ToolCallHandler {
38
+ name: string;
39
+ description?: string;
40
+ parameters?: Record<string, unknown>;
41
+ execute: (args: Record<string, unknown>) => Promise<unknown>;
42
+ }
43
+ export interface ProviderAdapter {
44
+ name: string;
45
+ baseUrl?: string;
46
+ apiKey?: string;
47
+ defaultModel?: string;
48
+ }
49
+ export interface ModelConfig {
50
+ model: string;
51
+ temperature?: number;
52
+ maxTokens?: number;
53
+ topP?: number;
54
+ frequencyPenalty?: number;
55
+ presencePenalty?: number;
56
+ stop?: string[];
57
+ }
58
+ export interface XRequestConfig {
59
+ /** 请求 URL */
60
+ url: string;
61
+ /** 请求方法 */
62
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
63
+ /** 请求头 */
64
+ headers?: Record<string, string>;
65
+ /** 请求体 */
66
+ body?: Record<string, unknown>;
67
+ /** 查询参数 */
68
+ params?: Record<string, string>;
69
+ /** 超时时间 (ms) */
70
+ timeout?: number;
71
+ /** 是否启用流式 */
72
+ stream?: boolean;
73
+ /** 请求标识 */
74
+ requestId?: string;
75
+ /** 额外数据 */
76
+ extra?: Record<string, unknown>;
77
+ }
78
+ export interface XRequestCallbacks {
79
+ /** 请求开始 */
80
+ onStart?: (config: XRequestConfig) => void;
81
+ /** 收到响应头 */
82
+ onResponse?: (response: Response) => void;
83
+ /** 流式 chunk */
84
+ onChunk?: (chunk: string, data?: unknown) => void;
85
+ /** 流式完成 */
86
+ onFinish?: (fullContent: string, data?: unknown) => void;
87
+ /** 请求错误 */
88
+ onError?: (error: Error) => void;
89
+ /** 请求完成 (无论成功失败) */
90
+ onFinally?: () => void;
91
+ }
92
+ export interface AIMiddleware {
93
+ /** 中间件名称 */
94
+ name: string;
95
+ /** 请求前拦截 */
96
+ onRequest?: (config: XRequestConfig) => XRequestConfig | Promise<XRequestConfig>;
97
+ /** 响应后拦截 */
98
+ onResponse?: (response: unknown, config: XRequestConfig) => unknown;
99
+ /** 流式 chunk 拦截 */
100
+ onChunk?: (chunk: string, config: XRequestConfig) => string;
101
+ /** 错误拦截 */
102
+ onError?: (error: Error, config: XRequestConfig) => Error;
103
+ }
104
+ export interface CacheConfig {
105
+ /** 启用缓存 */
106
+ enabled?: boolean;
107
+ /** 缓存 key */
108
+ key?: string;
109
+ /** 缓存时间 (ms) */
110
+ ttl?: number;
111
+ /** 缓存策略 */
112
+ strategy?: 'memory' | 'localStorage' | 'sessionStorage';
113
+ }
114
+ export interface RetryConfig {
115
+ /** 启用重试 */
116
+ enabled?: boolean;
117
+ /** 最大重试次数 */
118
+ maxRetries?: number;
119
+ /** 重试延迟 (ms) */
120
+ retryDelay?: number;
121
+ /** 重试条件 */
122
+ retryCondition?: (error: Error) => boolean;
123
+ }
124
+ export interface Conversation {
125
+ id: string;
126
+ title: string;
127
+ messages: ConversationMessage[];
128
+ createdAt: Date;
129
+ updatedAt: Date;
130
+ metadata?: Record<string, unknown>;
131
+ }
132
+ export interface UseConversationsOptions {
133
+ /** 最大会话数 */
134
+ maxConversations?: number;
135
+ /** 是否持久化 */
136
+ persist?: boolean;
137
+ /** 存储 key */
138
+ storageKey?: string;
139
+ /** 自动生成标题 */
140
+ autoTitle?: boolean;
141
+ }
142
+ /**
143
+ * 创建可流式更新的值
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * const { value, loading, error } = createStreamableValue<string>('')
148
+ *
149
+ * // 在流式更新时
150
+ * value.value = 'Hello '
151
+ * value.value = 'Hello World'
152
+ * loading.value = false
153
+ * ```
154
+ */
155
+ export declare function createStreamableValue<T = unknown>(initialValue?: T): StreamableValue<T>;
156
+ /**
157
+ * 组合使用 streamable value
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * const streamable = createStreamableValue('')
162
+ * const displayValue = useStreamableValue(streamable)
163
+ * ```
164
+ */
165
+ export declare function useStreamableValue<T>(streamable: StreamableValue<T>): {
166
+ value: import("vue").ComputedRef<T>;
167
+ loading: import("vue").ComputedRef<boolean>;
168
+ error: import("vue").ComputedRef<Error | null>;
169
+ };
170
+ /**
171
+ * 注册全局中间件
172
+ */
173
+ export declare function registerMiddleware(middleware: AIMiddleware): () => void;
174
+ /**
175
+ * 清理过期缓存
176
+ */
177
+ export declare function clearCache(): void;
178
+ /**
179
+ * XRequest - 增强版请求函数
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * // 基础使用
184
+ * const result = await XRequest({
185
+ * url: '/api/chat',
186
+ * body: { messages: [{ role: 'user', content: '你好' }] }
187
+ * })
188
+ *
189
+ * // 流式使用
190
+ * XRequest({
191
+ * url: '/api/chat/stream',
192
+ * body: { messages: [{ role: 'user', content: '你好' }] },
193
+ * stream: true,
194
+ * callbacks: {
195
+ * onChunk: (chunk) => console.log('收到:', chunk),
196
+ * onFinish: (content) => console.log('完成:', content)
197
+ * }
198
+ * })
199
+ * ```
200
+ */
201
+ export declare function XRequest(config: XRequestConfig, callbacks?: XRequestCallbacks, options?: {
202
+ middlewares?: AIMiddleware[];
203
+ cache?: CacheConfig;
204
+ retry?: RetryConfig;
205
+ }): Promise<unknown>;
206
+ /**
207
+ * 创建 XRequest 实例 (可复用的配置)
208
+ */
209
+ export declare function createXRequest(defaultConfig?: Partial<XRequestConfig>, defaultOptions?: {
210
+ middlewares?: AIMiddleware[];
211
+ cache?: CacheConfig;
212
+ retry?: RetryConfig;
213
+ }): (config: XRequestConfig, callbacks?: XRequestCallbacks) => Promise<unknown>;
214
+ /**
215
+ * 对话历史管理
216
+ *
217
+ * @example
218
+ * ```ts
219
+ * const { messages, addMessage, clearHistory, loadHistory } = useConversation()
220
+ *
221
+ * // 添加消息
222
+ * addMessage({ role: 'user', content: 'Hello' })
223
+ *
224
+ * // 获取历史
225
+ * console.log(messages.value)
226
+ * ```
227
+ */
228
+ export declare function useConversation(config?: ConversationConfig): {
229
+ messages: Ref<{
230
+ id: string;
231
+ role: "user" | "assistant" | "system" | "tool";
232
+ content: string;
233
+ name?: string | undefined;
234
+ toolCallId?: string | undefined;
235
+ toolCalls?: {
236
+ id: string;
237
+ type: "function";
238
+ name: string;
239
+ arguments: Record<string, unknown>;
240
+ }[] | undefined;
241
+ createdAt?: Date | undefined;
242
+ metadata?: Record<string, unknown> | undefined;
243
+ }[], ConversationMessage[] | {
244
+ id: string;
245
+ role: "user" | "assistant" | "system" | "tool";
246
+ content: string;
247
+ name?: string | undefined;
248
+ toolCallId?: string | undefined;
249
+ toolCalls?: {
250
+ id: string;
251
+ type: "function";
252
+ name: string;
253
+ arguments: Record<string, unknown>;
254
+ }[] | undefined;
255
+ createdAt?: Date | undefined;
256
+ metadata?: Record<string, unknown> | undefined;
257
+ }[]>;
258
+ addMessage: (message: Omit<ConversationMessage, "id" | "createdAt">) => ConversationMessage;
259
+ clearHistory: () => void;
260
+ loadHistory: () => void;
261
+ saveHistory: () => void;
262
+ };
263
+ /**
264
+ * 多会话管理 Hook
265
+ *
266
+ * @example
267
+ * ```ts
268
+ * const {
269
+ * conversations, // 会话列表
270
+ * currentId, // 当前会话 ID
271
+ * currentMessages, // 当前会话消息
272
+ * create, // 创建会话
273
+ * remove, // 删除会话
274
+ * select, // 切换会话
275
+ * updateTitle // 更新标题
276
+ * } = useConversations({
277
+ * maxConversations: 50,
278
+ * persist: true,
279
+ * autoTitle: true
280
+ * })
281
+ * ```
282
+ */
283
+ export declare function useConversations(options?: UseConversationsOptions): {
284
+ conversations: Ref<{
285
+ id: string;
286
+ title: string;
287
+ messages: {
288
+ id: string;
289
+ role: "user" | "assistant" | "system" | "tool";
290
+ content: string;
291
+ name?: string | undefined;
292
+ toolCallId?: string | undefined;
293
+ toolCalls?: {
294
+ id: string;
295
+ type: "function";
296
+ name: string;
297
+ arguments: Record<string, unknown>;
298
+ }[] | undefined;
299
+ createdAt?: Date | undefined;
300
+ metadata?: Record<string, unknown> | undefined;
301
+ }[];
302
+ createdAt: Date;
303
+ updatedAt: Date;
304
+ metadata?: Record<string, unknown> | undefined;
305
+ }[], Conversation[] | {
306
+ id: string;
307
+ title: string;
308
+ messages: {
309
+ id: string;
310
+ role: "user" | "assistant" | "system" | "tool";
311
+ content: string;
312
+ name?: string | undefined;
313
+ toolCallId?: string | undefined;
314
+ toolCalls?: {
315
+ id: string;
316
+ type: "function";
317
+ name: string;
318
+ arguments: Record<string, unknown>;
319
+ }[] | undefined;
320
+ createdAt?: Date | undefined;
321
+ metadata?: Record<string, unknown> | undefined;
322
+ }[];
323
+ createdAt: Date;
324
+ updatedAt: Date;
325
+ metadata?: Record<string, unknown> | undefined;
326
+ }[]>;
327
+ currentId: Ref<string | null, string | null>;
328
+ currentConversation: import("vue").ComputedRef<{
329
+ id: string;
330
+ title: string;
331
+ messages: {
332
+ id: string;
333
+ role: "user" | "assistant" | "system" | "tool";
334
+ content: string;
335
+ name?: string | undefined;
336
+ toolCallId?: string | undefined;
337
+ toolCalls?: {
338
+ id: string;
339
+ type: "function";
340
+ name: string;
341
+ arguments: Record<string, unknown>;
342
+ }[] | undefined;
343
+ createdAt?: Date | undefined;
344
+ metadata?: Record<string, unknown> | undefined;
345
+ }[];
346
+ createdAt: Date;
347
+ updatedAt: Date;
348
+ metadata?: Record<string, unknown> | undefined;
349
+ } | null>;
350
+ currentMessages: import("vue").ComputedRef<{
351
+ id: string;
352
+ role: "user" | "assistant" | "system" | "tool";
353
+ content: string;
354
+ name?: string | undefined;
355
+ toolCallId?: string | undefined;
356
+ toolCalls?: {
357
+ id: string;
358
+ type: "function";
359
+ name: string;
360
+ arguments: Record<string, unknown>;
361
+ }[] | undefined;
362
+ createdAt?: Date | undefined;
363
+ metadata?: Record<string, unknown> | undefined;
364
+ }[]>;
365
+ create: (initialMessages?: ConversationMessage[]) => string;
366
+ remove: (id: string) => void;
367
+ select: (id: string) => void;
368
+ updateTitle: (id: string, title: string) => void;
369
+ addMessage: (message: Omit<ConversationMessage, "id" | "createdAt">) => ConversationMessage | null;
370
+ clearCurrent: () => void;
371
+ };
372
+ export interface UseAIChatOptions {
373
+ /** API 端点 */
374
+ api: string;
375
+ /** 初始消息 */
376
+ initialMessages?: ConversationMessage[];
377
+ /** 请求头 */
378
+ headers?: Record<string, string>;
379
+ /** Body 额外参数 */
380
+ body?: Record<string, unknown>;
381
+ /** 是否流式 */
382
+ stream?: boolean;
383
+ /** 流式间隔 (ms) */
384
+ streamInterval?: number;
385
+ /** 工具定义 */
386
+ tools?: ToolCallHandler[];
387
+ /** 回调:发送前 */
388
+ onRequest?: (message: string) => void;
389
+ /** 回调:收到响应头 */
390
+ onResponse?: (response: Response) => void;
391
+ /** 回调:收到每个 chunk (流式) */
392
+ onChunk?: (chunk: string, message?: ConversationMessage) => void;
393
+ /** 回调:工具调用 */
394
+ onToolCall?: (toolCall: {
395
+ name: string;
396
+ args: Record<string, unknown>;
397
+ }) => void;
398
+ /** 回调:工具调用结果 */
399
+ onToolResult?: (toolName: string, result: unknown) => void;
400
+ /** 回调:完成 */
401
+ onFinish?: (message: ConversationMessage) => void;
402
+ /** 回调:出错 */
403
+ onError?: (error: Error) => void;
404
+ }
405
+ export interface UseAIChatReturn {
406
+ /** 消息列表 */
407
+ messages: Ref<ConversationMessage[]>;
408
+ /** 输入内容 */
409
+ input: Ref<string>;
410
+ /** 是否正在加载 */
411
+ isLoading: Ref<boolean>;
412
+ /** 是否正在流式 */
413
+ isStreaming: Ref<boolean>;
414
+ /** 错误 */
415
+ error: Ref<Error | null>;
416
+ /** 当前消息 (流式时) */
417
+ currentMessage: Ref<ConversationMessage | null>;
418
+ /** 发送消息 */
419
+ sendMessage: (content: string) => Promise<void>;
420
+ /** 流式发送 (带增量更新) */
421
+ sendMessageStream: (content: string) => Promise<void>;
422
+ /** 停止流式 */
423
+ stop: () => void;
424
+ /** 追加内容(用于流式) */
425
+ append: (content: string, role?: 'user' | 'assistant') => ConversationMessage;
426
+ /** 更新最后一条消息 */
427
+ updateLastMessage: (updates: Partial<ConversationMessage>) => void;
428
+ /** 重置 */
429
+ reload: () => void;
430
+ }
431
+ /**
432
+ * AI 对话 hook (增强版)
433
+ *
434
+ * @example
435
+ * ```ts
436
+ * // 基础对话
437
+ * const { messages, input, isLoading, sendMessage } = useAIChat({
438
+ * api: '/api/chat',
439
+ * onFinish: (msg) => console.log('完成:', msg.content)
440
+ * })
441
+ *
442
+ * // 流式对话
443
+ * const { messages, isStreaming, currentMessage, sendMessageStream, stop } = useAIChat({
444
+ * api: '/api/chat/stream',
445
+ * stream: true,
446
+ * onChunk: (chunk, msg) => console.log('收到:', chunk),
447
+ * onFinish: (msg) => console.log('完成:', msg.content)
448
+ * })
449
+ *
450
+ * // 工具调用
451
+ * const { messages, sendMessage } = useAIChat({
452
+ * api: '/api/chat',
453
+ * tools: [
454
+ * {
455
+ * name: 'get_weather',
456
+ * description: '获取天气',
457
+ * parameters: { city: { type: 'string' } },
458
+ * execute: async ({ city }) => ({ temp: 25, weather: 'sunny' })
459
+ * }
460
+ * ],
461
+ * onToolCall: (tc) => console.log('调用工具:', tc.name),
462
+ * onToolResult: (name, result) => console.log('工具结果:', result)
463
+ * })
464
+ * ```
465
+ */
466
+ export declare function useAIChat(options: UseAIChatOptions): UseAIChatReturn;
467
+ export interface UseAIStreamOptions {
468
+ /** 流式 API 端点 */
469
+ api: string;
470
+ /** 初始内容 */
471
+ initialContent?: string;
472
+ /** 回调:每个 chunk */
473
+ onChunk?: (chunk: string) => void;
474
+ /** 回调:完成 */
475
+ onFinish?: (fullContent: string) => void;
476
+ /** 回调:出错 */
477
+ onError?: (error: Error) => void;
478
+ }
479
+ export interface UseAIStreamReturn {
480
+ /** 当前内容 */
481
+ content: Ref<string>;
482
+ /** 是否正在流式 */
483
+ isStreaming: Ref<boolean>;
484
+ /** 错误 */
485
+ error: Ref<Error | null>;
486
+ /** 开始流式请求 */
487
+ start: (prompt: string) => Promise<void>;
488
+ /** 停止 */
489
+ stop: () => void;
490
+ }
491
+ /**
492
+ * 流式文本生成 hook
493
+ *
494
+ * @example
495
+ * ```ts
496
+ * const { content, isStreaming, start, stop } = useAIStream({
497
+ * api: '/api/chat/stream',
498
+ * onChunk: (chunk) => console.log('收到:', chunk),
499
+ * onFinish: (text) => console.log('完成:', text)
500
+ * })
501
+ *
502
+ * await start('请介绍一下 Vue 3')
503
+ * ```
504
+ */
505
+ export declare function useAIStream(options: UseAIStreamOptions): UseAIStreamReturn;
506
+ /**
507
+ * 创建 AI 函数工具
508
+ *
509
+ * @example
510
+ * ```ts
511
+ * const weatherTool = createYHFunctionTool({
512
+ * name: 'get_weather',
513
+ * description: '获取指定城市的天气',
514
+ * parameters: {
515
+ * type: 'object',
516
+ * properties: {
517
+ * city: { type: 'string', description: '城市名称' }
518
+ * },
519
+ * required: ['city']
520
+ * },
521
+ * execute: async ({ city }) => {
522
+ * return `当前${city}天气晴朗,25°C`
523
+ * }
524
+ * })
525
+ * ```
526
+ */
527
+ export declare function createYHFunctionTool<_T extends Record<string, unknown> = Record<string, unknown>>(tool: ToolCallHandler): {
528
+ type: "function";
529
+ name: string;
530
+ description: string;
531
+ parameters: Record<string, unknown>;
532
+ execute: (args: Record<string, unknown>) => Promise<unknown>;
533
+ };
534
+ /**
535
+ * Provider 预设配置
536
+ */
537
+ export interface ProviderPreset {
538
+ name: string;
539
+ baseUrl: string;
540
+ defaultModel: string;
541
+ supportsStreaming?: boolean;
542
+ supportsFunctionCalling?: boolean;
543
+ needsProjectId?: boolean;
544
+ }
545
+ /**
546
+ * 内置 Provider 预设
547
+ */
548
+ export declare const PROVIDER_PRESETS: Record<string, ProviderPreset>;
549
+ /**
550
+ * 获取 Provider 预设
551
+ */
552
+ export declare function getProviderPreset(name: string): ProviderPreset | undefined;
553
+ /**
554
+ * 创建 AI Provider 适配器
555
+ *
556
+ * @example
557
+ * ```ts
558
+ * // 使用预设
559
+ * const openai = createProviderAdapter({
560
+ * provider: 'openai',
561
+ * apiKey: process.env.OPENAI_API_KEY
562
+ * })
563
+ *
564
+ * // 自定义配置
565
+ * const openai = createProviderAdapter({
566
+ * name: 'openai',
567
+ * baseUrl: 'https://api.openai.com/v1',
568
+ * apiKey: process.env.OPENAI_API_KEY,
569
+ * defaultModel: 'gpt-4'
570
+ * })
571
+ * ```
572
+ */
573
+ export declare function createProviderAdapter(config: ProviderAdapter | {
574
+ provider: string;
575
+ apiKey?: string;
576
+ }): ProviderAdapter & {
577
+ createChat: (model?: string | ModelConfig) => unknown;
578
+ preset?: ProviderPreset;
579
+ };
580
+ /**
581
+ * 创建带 Vercel AI SDK 的 Provider 适配器
582
+ *
583
+ * @example
584
+ * ```ts
585
+ * import { createVercelAIProvider } from '@yh-ui/ai-sdk'
586
+ * import { openai } from '@ai-sdk/openai'
587
+ *
588
+ * const provider = createVercelAIProvider(openai, {
589
+ * baseURL: 'https://api.openai.com/v1'
590
+ * })
591
+ * ```
592
+ */
593
+ export declare function createVercelAIProvider(provider: unknown, config?: {
594
+ baseURL?: string;
595
+ apiKey?: string;
596
+ headers?: Record<string, string>;
597
+ }): {
598
+ languageModel: (modelId: string) => {
599
+ provider: unknown;
600
+ modelId: string;
601
+ config: {
602
+ baseURL?: string;
603
+ apiKey?: string;
604
+ headers?: Record<string, string>;
605
+ } | undefined;
606
+ };
607
+ };
608
+ export interface AIContextValue {
609
+ /** 当前会话 ID */
610
+ sessionId: Ref<string | null>;
611
+ /** 提供者配置 */
612
+ provider: Ref<ProviderAdapter | null>;
613
+ /** 模型配置 */
614
+ modelConfig: Ref<ModelConfig>;
615
+ /** 设置会话 */
616
+ setSession: (id: string) => void;
617
+ /** 设置提供者 */
618
+ setProvider: (provider: ProviderAdapter) => void;
619
+ /** 设置模型 */
620
+ setModel: (config: ModelConfig) => void;
621
+ }
622
+ declare const AIContextKey: unique symbol;
623
+ /**
624
+ * 创建 AI 上下文(供 provide/inject 使用)
625
+ */
626
+ export declare function createAIContext(initialProvider?: ProviderAdapter, initialModel?: string): AIContextValue;
627
+ export { AIContextKey };