@opentiny/tiny-robot-kit 0.4.0-alpha.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/dist/index.d.mts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 - present OpenTiny Authors.
|
|
4
|
+
Copyright (c) 2025 - present Huawei Cloud Computing Technologies Co., Ltd.
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/dist/index.d.mts
CHANGED
|
@@ -258,6 +258,38 @@ declare class AIClient {
|
|
|
258
258
|
updateConfig(config: Partial<AIModelConfig>): void;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
/**
|
|
262
|
+
* OpenAI提供商
|
|
263
|
+
* 用于与OpenAI API进行交互
|
|
264
|
+
*/
|
|
265
|
+
|
|
266
|
+
declare class OpenAIProvider extends BaseModelProvider {
|
|
267
|
+
private baseURL;
|
|
268
|
+
private apiKey;
|
|
269
|
+
private defaultModel;
|
|
270
|
+
/**
|
|
271
|
+
* @param config AI模型配置
|
|
272
|
+
*/
|
|
273
|
+
constructor(config: AIModelConfig);
|
|
274
|
+
/**
|
|
275
|
+
* 发送聊天请求并获取响应
|
|
276
|
+
* @param request 聊天请求参数
|
|
277
|
+
* @returns 聊天响应
|
|
278
|
+
*/
|
|
279
|
+
chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
|
|
280
|
+
/**
|
|
281
|
+
* 发送流式聊天请求并通过处理器处理响应
|
|
282
|
+
* @param request 聊天请求参数
|
|
283
|
+
* @param handler 流式响应处理器
|
|
284
|
+
*/
|
|
285
|
+
chatStream(request: ChatCompletionRequest, handler: StreamHandler): Promise<void>;
|
|
286
|
+
/**
|
|
287
|
+
* 更新配置
|
|
288
|
+
* @param config 新的AI模型配置
|
|
289
|
+
*/
|
|
290
|
+
updateConfig(config: AIModelConfig): void;
|
|
291
|
+
}
|
|
292
|
+
|
|
261
293
|
interface Tool {
|
|
262
294
|
type: 'function';
|
|
263
295
|
function: {
|
|
@@ -469,6 +501,11 @@ interface UseConversationOptions {
|
|
|
469
501
|
* When provided, conversation list and messages can be loaded and persisted.
|
|
470
502
|
*/
|
|
471
503
|
storage?: ConversationStorageStrategy;
|
|
504
|
+
/**
|
|
505
|
+
* Called when the initial conversation list has been loaded from storage.
|
|
506
|
+
* Only fired when storage.loadConversations is available and has completed.
|
|
507
|
+
*/
|
|
508
|
+
onLoad?: (conversations: ConversationInfo[]) => void;
|
|
472
509
|
}
|
|
473
510
|
interface UseConversationReturn {
|
|
474
511
|
conversations: Ref<ConversationInfo[]>;
|
|
@@ -590,6 +627,25 @@ declare function indexedDBStorageStrategyFactory(config?: IndexedDBConfig): Conv
|
|
|
590
627
|
* 提供一些实用的辅助函数
|
|
591
628
|
*/
|
|
592
629
|
|
|
630
|
+
/**
|
|
631
|
+
* 处理SSE流式响应
|
|
632
|
+
* @param response fetch响应对象
|
|
633
|
+
* @param handler 流处理器
|
|
634
|
+
*/
|
|
635
|
+
declare function handleSSEStream(response: Response, handler: StreamHandler, signal?: AbortSignal): Promise<void>;
|
|
636
|
+
/**
|
|
637
|
+
* 格式化消息
|
|
638
|
+
* 将各种格式的消息转换为标准的ChatMessage格式
|
|
639
|
+
* @param messages 消息数组
|
|
640
|
+
* @returns 标准格式的消息数组
|
|
641
|
+
*/
|
|
642
|
+
declare function formatMessages(messages: Array<ChatMessage | string>): ChatMessage[];
|
|
643
|
+
/**
|
|
644
|
+
* 从响应中提取文本内容
|
|
645
|
+
* @param response 聊天完成响应
|
|
646
|
+
* @returns 文本内容
|
|
647
|
+
*/
|
|
648
|
+
declare function extractTextFromResponse(response: ChatCompletionResponse): string;
|
|
593
649
|
/**
|
|
594
650
|
* 将 SSE 流转换为异步生成器。
|
|
595
651
|
* 将服务器发送事件(SSE)流式响应转换为异步生成器,逐个产出解析后的数据
|
|
@@ -688,4 +744,4 @@ declare const toolPlugin: (options: UseMessagePlugin & {
|
|
|
688
744
|
|
|
689
745
|
declare const useMessage: (options: UseMessageOptions) => UseMessageReturn;
|
|
690
746
|
|
|
691
|
-
export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, type BasePluginContext, type ChatCompletion, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Choice, type CompletionChoice, type Conversation, type ConversationInfo, type ConversationStorageStrategy, type DeltaChoice, EXCLUDE_MODE_REMOVE, ErrorType, type IndexedDBConfig, IndexedDBStrategy, type LocalStorageConfig, LocalStorageStrategy, type MaybePromise, type MessageMetadata, type MessageRequestBody, type MessageRole, type RequestProcessingState, type RequestState, StreamEventType, type StreamHandler, type Tool, type ToolCall, type Usage, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessagePlugin, type UseMessageReturn, fallbackRolePlugin, indexedDBStorageStrategyFactory, lengthPlugin, localStorageStrategyFactory, sseStreamToGenerator, thinkingPlugin, toolPlugin, useConversation, useMessage };
|
|
747
|
+
export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, BaseModelProvider, type BasePluginContext, type ChatCompletion, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Choice, type CompletionChoice, type Conversation, type ConversationInfo, type ConversationStorageStrategy, type DeltaChoice, EXCLUDE_MODE_REMOVE, ErrorType, type IndexedDBConfig, IndexedDBStrategy, type LocalStorageConfig, LocalStorageStrategy, type MaybePromise, type MessageMetadata, type MessageRequestBody, type MessageRole, OpenAIProvider, type RequestProcessingState, type RequestState, StreamEventType, type StreamHandler, type Tool, type ToolCall, type Usage, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessagePlugin, type UseMessageReturn, extractTextFromResponse, fallbackRolePlugin, formatMessages, handleSSEStream, indexedDBStorageStrategyFactory, lengthPlugin, localStorageStrategyFactory, sseStreamToGenerator, thinkingPlugin, toolPlugin, useConversation, useMessage };
|
package/dist/index.d.ts
CHANGED
|
@@ -258,6 +258,38 @@ declare class AIClient {
|
|
|
258
258
|
updateConfig(config: Partial<AIModelConfig>): void;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
/**
|
|
262
|
+
* OpenAI提供商
|
|
263
|
+
* 用于与OpenAI API进行交互
|
|
264
|
+
*/
|
|
265
|
+
|
|
266
|
+
declare class OpenAIProvider extends BaseModelProvider {
|
|
267
|
+
private baseURL;
|
|
268
|
+
private apiKey;
|
|
269
|
+
private defaultModel;
|
|
270
|
+
/**
|
|
271
|
+
* @param config AI模型配置
|
|
272
|
+
*/
|
|
273
|
+
constructor(config: AIModelConfig);
|
|
274
|
+
/**
|
|
275
|
+
* 发送聊天请求并获取响应
|
|
276
|
+
* @param request 聊天请求参数
|
|
277
|
+
* @returns 聊天响应
|
|
278
|
+
*/
|
|
279
|
+
chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
|
|
280
|
+
/**
|
|
281
|
+
* 发送流式聊天请求并通过处理器处理响应
|
|
282
|
+
* @param request 聊天请求参数
|
|
283
|
+
* @param handler 流式响应处理器
|
|
284
|
+
*/
|
|
285
|
+
chatStream(request: ChatCompletionRequest, handler: StreamHandler): Promise<void>;
|
|
286
|
+
/**
|
|
287
|
+
* 更新配置
|
|
288
|
+
* @param config 新的AI模型配置
|
|
289
|
+
*/
|
|
290
|
+
updateConfig(config: AIModelConfig): void;
|
|
291
|
+
}
|
|
292
|
+
|
|
261
293
|
interface Tool {
|
|
262
294
|
type: 'function';
|
|
263
295
|
function: {
|
|
@@ -469,6 +501,11 @@ interface UseConversationOptions {
|
|
|
469
501
|
* When provided, conversation list and messages can be loaded and persisted.
|
|
470
502
|
*/
|
|
471
503
|
storage?: ConversationStorageStrategy;
|
|
504
|
+
/**
|
|
505
|
+
* Called when the initial conversation list has been loaded from storage.
|
|
506
|
+
* Only fired when storage.loadConversations is available and has completed.
|
|
507
|
+
*/
|
|
508
|
+
onLoad?: (conversations: ConversationInfo[]) => void;
|
|
472
509
|
}
|
|
473
510
|
interface UseConversationReturn {
|
|
474
511
|
conversations: Ref<ConversationInfo[]>;
|
|
@@ -590,6 +627,25 @@ declare function indexedDBStorageStrategyFactory(config?: IndexedDBConfig): Conv
|
|
|
590
627
|
* 提供一些实用的辅助函数
|
|
591
628
|
*/
|
|
592
629
|
|
|
630
|
+
/**
|
|
631
|
+
* 处理SSE流式响应
|
|
632
|
+
* @param response fetch响应对象
|
|
633
|
+
* @param handler 流处理器
|
|
634
|
+
*/
|
|
635
|
+
declare function handleSSEStream(response: Response, handler: StreamHandler, signal?: AbortSignal): Promise<void>;
|
|
636
|
+
/**
|
|
637
|
+
* 格式化消息
|
|
638
|
+
* 将各种格式的消息转换为标准的ChatMessage格式
|
|
639
|
+
* @param messages 消息数组
|
|
640
|
+
* @returns 标准格式的消息数组
|
|
641
|
+
*/
|
|
642
|
+
declare function formatMessages(messages: Array<ChatMessage | string>): ChatMessage[];
|
|
643
|
+
/**
|
|
644
|
+
* 从响应中提取文本内容
|
|
645
|
+
* @param response 聊天完成响应
|
|
646
|
+
* @returns 文本内容
|
|
647
|
+
*/
|
|
648
|
+
declare function extractTextFromResponse(response: ChatCompletionResponse): string;
|
|
593
649
|
/**
|
|
594
650
|
* 将 SSE 流转换为异步生成器。
|
|
595
651
|
* 将服务器发送事件(SSE)流式响应转换为异步生成器,逐个产出解析后的数据
|
|
@@ -688,4 +744,4 @@ declare const toolPlugin: (options: UseMessagePlugin & {
|
|
|
688
744
|
|
|
689
745
|
declare const useMessage: (options: UseMessageOptions) => UseMessageReturn;
|
|
690
746
|
|
|
691
|
-
export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, type BasePluginContext, type ChatCompletion, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Choice, type CompletionChoice, type Conversation, type ConversationInfo, type ConversationStorageStrategy, type DeltaChoice, EXCLUDE_MODE_REMOVE, ErrorType, type IndexedDBConfig, IndexedDBStrategy, type LocalStorageConfig, LocalStorageStrategy, type MaybePromise, type MessageMetadata, type MessageRequestBody, type MessageRole, type RequestProcessingState, type RequestState, StreamEventType, type StreamHandler, type Tool, type ToolCall, type Usage, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessagePlugin, type UseMessageReturn, fallbackRolePlugin, indexedDBStorageStrategyFactory, lengthPlugin, localStorageStrategyFactory, sseStreamToGenerator, thinkingPlugin, toolPlugin, useConversation, useMessage };
|
|
747
|
+
export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, BaseModelProvider, type BasePluginContext, type ChatCompletion, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Choice, type CompletionChoice, type Conversation, type ConversationInfo, type ConversationStorageStrategy, type DeltaChoice, EXCLUDE_MODE_REMOVE, ErrorType, type IndexedDBConfig, IndexedDBStrategy, type LocalStorageConfig, LocalStorageStrategy, type MaybePromise, type MessageMetadata, type MessageRequestBody, type MessageRole, OpenAIProvider, type RequestProcessingState, type RequestState, StreamEventType, type StreamHandler, type Tool, type ToolCall, type Usage, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessagePlugin, type UseMessageReturn, extractTextFromResponse, fallbackRolePlugin, formatMessages, handleSSEStream, indexedDBStorageStrategyFactory, lengthPlugin, localStorageStrategyFactory, sseStreamToGenerator, thinkingPlugin, toolPlugin, useConversation, useMessage };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var ie=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var _e=Object.getOwnPropertyNames;var De=Object.prototype.hasOwnProperty;var Ue=(o,t)=>{for(var e in t)ie(o,e,{get:t[e],enumerable:!0})},qe=(o,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of _e(t))!De.call(o,s)&&s!==e&&ie(o,s,{get:()=>t[s],enumerable:!(n=ke(t,s))||n.enumerable});return o};var Be=o=>qe(ie({},"__esModule",{value:!0}),o);var Ve={};Ue(Ve,{AIClient:()=>Z,BaseModelProvider:()=>H,EXCLUDE_MODE_REMOVE:()=>Pe,ErrorType:()=>fe,IndexedDBStrategy:()=>V,LocalStorageStrategy:()=>G,OpenAIProvider:()=>j,StreamEventType:()=>me,extractTextFromResponse:()=>ye,fallbackRolePlugin:()=>ue,formatMessages:()=>he,handleSSEStream:()=>Y,indexedDBStorageStrategyFactory:()=>be,lengthPlugin:()=>de,localStorageStrategyFactory:()=>te,sseStreamToGenerator:()=>Ce,thinkingPlugin:()=>ge,toolPlugin:()=>je,useConversation:()=>Ge,useMessage:()=>ne});module.exports=Be(Ve);var H=class{constructor(t){this.config=t}updateConfig(t){this.config={...this.config,...t}}getConfig(){return{...this.config}}validateRequest(t){if(!t.messages||!Array.isArray(t.messages)||t.messages.length===0)throw new Error("\u8BF7\u6C42\u5FC5\u987B\u5305\u542B\u81F3\u5C11\u4E00\u6761\u6D88\u606F");for(let e of t.messages)if(!e.role||!e.content)throw new Error("\u6BCF\u6761\u6D88\u606F\u5FC5\u987B\u5305\u542B\u89D2\u8272\u548C\u5185\u5BB9")}};var fe=(c=>(c.NETWORK_ERROR="network_error",c.AUTHENTICATION_ERROR="authentication_error",c.RATE_LIMIT_ERROR="rate_limit_error",c.SERVER_ERROR="server_error",c.MODEL_ERROR="model_error",c.TIMEOUT_ERROR="timeout_error",c.UNKNOWN_ERROR="unknown_error",c))(fe||{}),me=(n=>(n.DATA="data",n.ERROR="error",n.DONE="done",n))(me||{});function K(o){return{type:o.type||"unknown_error",message:o.message||"\u672A\u77E5\u9519\u8BEF",statusCode:o.statusCode,originalError:o.originalError}}function le(o){if(!o.response)return K({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:o});if(o.response){let{status:t,data:e}=o.response;return t===401||t===403?K({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:t,originalError:o}):t===429?K({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:t,originalError:o}):t>=500?K({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:t,originalError:o}):K({type:"unknown_error",message:e?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${t}`,statusCode:t,originalError:o})}return o.code==="ECONNABORTED"?K({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:o}):K({type:"unknown_error",message:o.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:o})}async function Y(o,t,e){let n=o.body?.getReader();if(!n)throw new Error("Response body is null");let s=new TextDecoder,r="",a,c;e&&e.addEventListener("abort",()=>{n.cancel().catch(d=>console.error("Error cancelling reader:",d))},{once:!0});try{for(;;){if(e?.aborted){await n.cancel();break}let{done:d,value:f}=await n.read();if(d)break;let v=s.decode(f,{stream:!0});r+=v;let R=r.split(`
|
|
2
2
|
|
|
3
|
-
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""){if(x.trim()==="data: [DONE]"){
|
|
4
|
-
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""&&x.startsWith("data: ")){let A=x.slice(6);if(A==="[DONE]")return;try{yield JSON.parse(A)}catch(M){console.warn("Failed to parse SSE data:",A,M)}}}}finally{n?.removeEventListener("abort",a),e.releaseLock()}}var J=class extends Q{constructor(e){super(e);this.defaultModel="gpt-3.5-turbo";this.baseURL=e.apiUrl||"https://api.openai.com/v1",this.apiKey=e.apiKey||"",e.defaultModel&&(this.defaultModel=e.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(e){try{this.validateRequest(e);let n={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...e.options,stream:!1},s={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)};this.apiKey&&Object.assign(s.headers,{Authorization:`Bearer ${this.apiKey}`});let r=await fetch(`${this.baseURL}/chat/completions`,s);if(!r.ok){let a=await r.text();throw new Error(`HTTP error! status: ${r.status}, details: ${a}`)}return await r.json()}catch(n){throw ie(n)}}async chatStream(e,n){let{signal:s,...r}=e.options||{};try{this.validateRequest(e);let a={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...r,stream:!0},l={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(a),signal:s};this.apiKey&&Object.assign(l.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,l);if(!d.ok){let p=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${p}`)}await me(d,n,s)}catch(a){if(s?.aborted)return;n.onError(ie(a))}}updateConfig(e){super.updateConfig(e),e.apiUrl&&(this.baseURL=e.apiUrl),e.apiKey&&(this.apiKey=e.apiKey),e.defaultModel&&(this.defaultModel=e.defaultModel)}};var Y=class{constructor(t){this.config=t,this.provider=this.createProvider(t)}createProvider(t){if(t.provider==="custom"&&"providerImplementation"in t)return t.providerImplementation;if(t.provider==="deepseek"){let e={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new J({...e,...t})}else return new J(t)}async chat(t){return this.provider.chat(t)}async chatStream(t,e){let n={...t,options:{...t.options,stream:!0}};return this.provider.chatStream(n,e)}getConfig(){return{...this.config}}updateConfig(t){this.config={...this.config,...t},t.provider&&t.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};var ye=require("vue");function z(o,t=new WeakSet){if(o==null||typeof o!="object")return o;if(t.has(o))return Array.isArray(o)?[]:{};t.add(o);try{let e=(0,ye.toRaw)(o);if(Array.isArray(e))return e.map(s=>z(s,t));if(e instanceof Date||e instanceof RegExp||e instanceof ArrayBuffer||e instanceof Blob)return e;let n={};for(let s in e){if(typeof s=="symbol")continue;let r=Object.getOwnPropertyDescriptor(e,s);if(!r||r.get||r.set)continue;let a=e[s];typeof a!="function"&&typeof a!="symbol"&&(n[s]=z(a,t))}return n}catch(e){return console.warn("unwrapProxy error:",e),Array.isArray(o)?[]:{}}}var Z=o=>o.map(t=>{let{renderContent:e,...n}=t;if(!Array.isArray(e))return t;let s=e.filter(a=>a.type==="collapsible-text"),r=e.filter(a=>a.type==="markdown"||a.type==="text");return s.length>0&&(n.reasoning_content=s.map(a=>a.content).join("")),r.length>0&&(n.content=r.map(a=>a.content).join("")),n});var X=o=>{let t=localStorage.getItem(o);return t?JSON.parse(t):[]},W=class{constructor(t="tiny-robot-ai-conversations"){this.storageKey=t}saveConversation(t){try{let e=X(this.storageKey),n=e.findIndex(s=>s.id===t.id);n!==-1?Object.assign(e[n],t):e.unshift({...t,messages:[]}),localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(e){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e)}}loadConversations(){try{return X(this.storageKey).map(e=>({id:e.id,title:e.title,createdAt:e.createdAt,updatedAt:e.updatedAt,metadata:e.metadata}))}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}saveMessages(t,e){try{let n=X(this.storageKey),s=n.findIndex(r=>r.id===t);s!==-1&&(n[s].messages=e),localStorage.setItem(this.storageKey,JSON.stringify(n))}catch(n){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n)}}loadMessages(t){try{let n=X(this.storageKey).find(r=>r.id===t);return Z(n?.messages||[])}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}deleteConversation(t){let e=X(this.storageKey),n=e.findIndex(s=>s.id===t);n!==-1&&e.splice(n,1),localStorage.setItem(this.storageKey,JSON.stringify(e))}};var Ce=require("idb");var H=class{constructor(t="tiny-robot-ai-db",e=3){this.db=null;this.dbName=t,this.dbVersion=e}async getDB(){return this.db||(this.db=await(0,Ce.openDB)(this.dbName,this.dbVersion,{upgrade(t){t.objectStoreNames.contains("conversations")||t.createObjectStore("conversations",{keyPath:"id"}).createIndex("by-updated","updatedAt"),t.objectStoreNames.contains("messages")||t.createObjectStore("messages",{keyPath:"conversationId"})}})),this.db}async loadConversations(){try{return(await(await this.getDB()).getAllFromIndex("conversations","by-updated")).reverse()}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}async loadMessages(t){try{let n=await(await this.getDB()).get("messages",t);return n?Z(n.messages):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}async saveConversation(t){try{let e=await this.getDB(),n=z(t);await e.put("conversations",n)}catch(e){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e),e}}async saveMessages(t,e){try{let n=await this.getDB(),s=z(e);await n.put("messages",{conversationId:t,messages:s})}catch(n){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n),n}}async deleteConversation(t){try{let e=await this.getDB();await e.delete("conversations",t),await e.delete("messages",t)}catch(e){throw console.error("\u5220\u9664\u4F1A\u8BDD\u5931\u8D25:",e),e}}};function ee(o={}){return new W(o.key||"tiny-robot-ai-conversations")}function ve(o={}){return new H(o.dbName||"tiny-robot-ai-db",o.dbVersion||1)}var j=require("vue");var U=require("vue");var ce=(o={})=>{let{fallbackRole:t="assistant",...e}=o;return{name:"fallbackRole",...e,onBeforeRequest(n){let{requestBody:s,messages:r}=n;return s.messages=r.map(a=>({...a,role:a.role||t})),e.onBeforeRequest?.(n)}}};var ue=(o={})=>{let{continueContent:t="Please continue with your previous answer.",...e}=o;return{name:"length",...e,onAfterRequest:async n=>{let{lastChoice:s,appendMessage:r,requestNext:a}=n;return s?.finish_reason==="length"&&(r({role:"user",content:t}),a()),e.onAfterRequest?.(n)}}};var de=(o={})=>({name:"thinking",...o,onCompletionChunk(t){let{choice:e,currentMessage:n}=t,r=typeof(e?.message?.reasoning_content||e?.delta?.reasoning_content)=="string";return n.state?n.state.thinking=r:n.state={thinking:r},o.onCompletionChunk?.(t)},onTurnEnd(t){let e=t.currentTurn.slice(-1)[0];return e?.state&&(e.state.thinking=void 0),o.onTurnEnd?.(t)}});var we=require("vue");var G=class extends Error{constructor(t){super(t),this.name="AbortError"}};function qe(o){if(o.aborted)return{promise:Promise.reject(new G(String(o.reason??"Aborted"))),cleanup:()=>{}};let t=null;return{promise:new Promise((s,r)=>{t=()=>{r(new G(String(o.reason??"Aborted")))},o.addEventListener("abort",t,{once:!0})}),cleanup:()=>{t&&(o.removeEventListener("abort",t),t=null)}}}function Re(o,t){let{promise:e,cleanup:n}=qe(t);return Promise.race([o,e]).finally(n)}function xe(o,t){let e={};for(let n in o)t.includes(n)&&(e[n]=o[n]);return e}function Ae(o,t){let e={};for(let n in o)t.includes(n)||(e[n]=o[n]);return e}async function*te(o){if(Me(o)){yield*o;return}let t=await o;if(Me(t)){yield*t;return}yield t}function Me(o){return o&&typeof o=="object"&&typeof o[Symbol.asyncIterator]=="function"}var ge=o=>typeof o=="object"&&o!==null,be=o=>ge(o)&&typeof o.index=="number",V=(o,t)=>{for(let[e,n]of Object.entries(t)){let s=o[e];if(s)if(typeof s=="string"&&typeof n=="string")e==="type"&&s||(o[e]=s+n);else if(Array.isArray(s)&&Array.isArray(n))if(s.every(r=>be(r))&&n.every(r=>be(r))){let r=new Map(s.map(p=>[p.index,p])),a=new Map(n.map(p=>[p.index,p]));for(let[p,v]of a)if(r.has(p)){let R=r.get(p);r.set(p,V(R,v))}else r.set(p,v);let l=Math.max(...Array.from(r.keys()),-1)+1,d=l>s.length?Array.from({length:l}):s;for(let[p,v]of r)d[p]=v;o[e]=d}else o[e]=[...s,...n];else ge(s)&&ge(n)&&(o[e]=V(s,n));else o[e]=n}return o};function Be(o,t){let e=[];for(let n=0;n<o.length;n++){let s=o[n];if(s.role==="assistant"&&s.tool_calls&&s.tool_calls.length>0){let r=new Set(s.tool_calls.map(d=>d.id)),a=new Set;for(let d=n+1;d<o.length;d++){let p=o[d];p.role==="tool"&&p.tool_call_id&&r.has(p.tool_call_id)&&a.add(p.tool_call_id)}let l=s.tool_calls.map(d=>d.id).filter(d=>!a.has(d));l.length>0&&e.push({insertAfterIndex:n,missingToolCallIds:l})}}for(let n=e.length-1;n>=0;n--){let{insertAfterIndex:s,missingToolCallIds:r}=e[n],a=r.map(l=>({role:"tool",tool_call_id:l,content:t}));o.splice(s+1,0,...a)}}var Te="remove";function Ne(o,t,e,n){let s=o.filter(a=>a[e]),r=new Set(s.flatMap(a=>a.tool_calls?.map(l=>l.id)??[]));if(t===Te)for(let a=o.length-1;a>=0;a--){let l=o[a];(l[e]||l[n]||l.tool_call_id&&r.has(l.tool_call_id))&&o.splice(a,1)}else if(t===!0)for(let a of o)(a[e]||a.tool_call_id&&r.has(a.tool_call_id))&&(a[n]=!0,delete a[e])}var Fe=o=>{let{getTools:t,beforeCallTools:e,callTool:n,onToolCallStart:s,onToolCallEnd:r,toolCallCancelledContent:a="Tool call cancelled.",toolCallFailedContent:l="Tool call failed.",autoFillMissingToolMessages:d=!1,excludeToolMessagesNextTurn:p=!1,...v}=o,R=Symbol("doNotSendNextTurn"),x=Symbol("doNotSend"),A=(...m)=>{let[h,{primaryMessage:T}]=m;T.state.toolCall[h.id].status="running",s?.(...m)},M=(...m)=>{let[h,{status:T,primaryMessage:O}]=m;O.state.toolCall[h.id].status=T,r?.(...m)};return{name:"tool",...v,onTurnStart:m=>{let{messages:h}=m;return d&&Be(h,a),p&&Ne(h,p,R,x),v.onTurnStart?.(m)},onBeforeRequest:async m=>{let{messages:h,requestBody:T}=m;p===!0&&(T.messages=h.filter(E=>!E[x]));let O=await t?.();return O&&O.length>0&&(T.tools=O),v.onBeforeRequest?.(m)},onAfterRequest:async m=>{let{currentMessage:h,lastChoice:T,appendMessage:O,abortSignal:E,setRequestState:i,requestNext:c}=m;if(T?.finish_reason!=="tool_calls"||!h.tool_calls?.length)return;p&&(h[R]=!0),i("processing","calling-tools"),await e?.(h.tool_calls,{...m,currentMessage:h});let f=h.tool_calls.map(async y=>{let S=Math.floor(Date.now()/1e3),w=(0,we.reactive)({role:"tool",tool_call_id:y.id,content:"",metadata:{createdAt:S,updatedAt:S}});O(w);let q={...m,primaryMessage:h,toolMessage:w};A(y,q);try{let k=n(y,q),N=te(k);for await(let u of N){if(typeof u=="string")w.content+=u;else{let g={};try{g=JSON.parse(w.content||"{}")}catch(b){console.warn(b)}w.content=JSON.stringify(V(g,u))}w.metadata.updatedAt=Math.floor(Date.now()/1e3)}M(y,{...q,status:"success"})}catch(k){let N=k instanceof Error?k:new Error(String(k));if(E.aborted){M(y,{...q,status:"cancelled",error:N});return}console.error(k),w.content.length===0&&(w.content=l),M(y,{...q,status:"failed",error:N})}});return await Promise.all(f),c(),v.onAfterRequest?.(m)},onCompletionChunk:m=>{var T,O,E;let{currentMessage:h}=m;if(Array.isArray(h.tool_calls))for(let i of h.tool_calls)h.state?.toolCall?.[i.id]?.status||(h.state??(h.state={}),(T=h.state).toolCall??(T.toolCall={}),(O=h.state.toolCall)[E=i.id]??(O[E]={}));return v.onCompletionChunk?.(m)}}};var Ke=o=>{let t=[];for(let e of o){if(e.name){let n=t.findIndex(s=>s.name===e.name);n!==-1&&t.splice(n,1)}t.push(e)}return t},oe=o=>{let{initialMessages:t=[],requestMessageFields:e=[],requestMessageFieldsExclude:n=["state","metadata","loading"],plugins:s=[],onCompletionChunk:r}=o,a=(0,U.ref)("idle"),l=(0,U.ref)(void 0),d=(0,U.ref)(t),p=(0,U.ref)(o.responseProvider),v=null,R=[],x={},A=[ce(),de(),ue()],M=Ke(A.concat(s)),m=(0,U.computed)(()=>a.value==="processing"),h=async u=>{if(!u||!u.trim()){console.warn("Cannot send empty message");return}if(m.value){console.warn("Cannot send message while processing is in progress");return}let g=Math.floor(Date.now()/1e3);d.value.push({role:"user",content:u.trim(),metadata:{createdAt:g,updatedAt:g}}),R.push(d.value[d.value.length-1]),await w()},T=async(...u)=>{if(m.value){console.warn("Cannot send message while processing is in progress");return}d.value.push(...u),R.push(...u),await w()},O=u=>{let g=u;return e.length&&(g=g.map(b=>xe(b,e))),n.length&&(g=g.map(b=>Ae(b,n))),g},E=(u,g)=>{a.value=u,u==="processing"?l.value=g||"requesting":l.value=void 0},i=u=>{Object.assign(x,u)},c=u=>({messages:d.value,currentTurn:R,requestState:a.value,processingState:l.value,plugins:M,abortSignal:u,setRequestState:E,customContext:x,setCustomContext:i}),f=(u,g)=>typeof u.disabled=="function"?u.disabled(g):!!u.disabled,y=u=>!u||Object.keys(u).length===0?!1:Object.values(u).some(g=>!!g),S=async(u,g)=>{E("processing","requesting");let b=new Proxy({messages:O(d.value)},{set(D,P,F){return P==="messages"?(D.messages=O(F),!0):(D[P]=F,!0)}}),I=c(g);for(let D of M.filter(P=>!f(P,I)))await D.onBeforeRequest?.({...I,requestBody:b});let C=(0,U.reactive)({role:"",content:"",loading:!0});N(C);let _,se=u(b,g),B=te(se);for await(let D of B){E("processing","completing"),C.loading&&(C.loading=void 0);let P=D.choices?.find(L=>L.index===0);if(P){_=P;let L=()=>{C.metadata||(C.metadata={});let{created:$,...Ee}=D;C.metadata.createdAt=$,C.metadata.updatedAt=Math.floor(Date.now()/1e3),Object.assign(C.metadata,Ee);let re=y(P.delta)?P.delta:P.message;re||(re=P.delta||P.message||{}),V(C,re)};if(r){let $=c(g);r({...$,chunk:D,choice:P,currentMessage:C},L)}else L()}let F=c(g);for(let L of M.filter($=>!f($,F)))L.onCompletionChunk?.({...F,abortSignal:g,chunk:D,choice:P,currentMessage:C})}await k(C,u,g,_)},w=async()=>{let u=new AbortController;v=u,x={};try{E("processing","requesting");let g=c(u.signal);for(let C of M.filter(_=>!f(_,g)))await C.onTurnStart?.(g);let b=p.value;try{await S(b,u.signal),E("completed")}catch(C){if(u.signal.aborted||C instanceof G||C instanceof Error&&C.name==="AbortError")E("aborted");else throw C}let I=c(u.signal);for(let C of M.filter(_=>!f(_,I)))await C.onTurnEnd?.(I)}catch(g){E("error");let b=!1,I=c(u.signal);for(let C of M.filter(_=>!f(_,I)))b=!0,C.onError?.({...I,error:g});if(!b)throw g}finally{let g=c(u.signal);for(let b of M.filter(I=>!f(I,g)))try{b.onFinally?.(g)}catch(I){console.error(`Error in onFinally hook for plugin ${b.name||"Anonymous"}:`,I)}v=null,R.slice(-1)[0]&&(R.slice(-1)[0].loading=void 0),R=[]}},q=async()=>{v?.abort(),m.value&&await new Promise(u=>{let g=(0,U.watch)(m,b=>{b||(g(),u())},{immediate:!0})})},k=async(u,g,b,I)=>{let C=!1,_=c(b),se=M.filter(B=>!f(B,_)).map(B=>{if(!B.onAfterRequest)return null;let D=F=>{N(F)},P=()=>{C=!0};return B.onAfterRequest({..._,currentMessage:u,lastChoice:I,appendMessage:D,requestNext:P})}).filter(B=>B!==null);await Re(Promise.all(se),b),C&&await S(g,b)},N=u=>{let g=Array.isArray(u)?u:[u];d.value.push(...g),R.push(...g)};return{requestState:a,processingState:l,messages:d,responseProvider:p,isProcessing:m,sendMessage:h,send:T,abortRequest:q}};var ne=require("vue");function Pe(o,t=200,e=!1,n=!0,s=!1){return je(Le(t,e,n,s),o)}function je(o,t){function e(...n){return new Promise((s,r)=>{Promise.resolve(o(()=>t.apply(this,n),{fn:t,thisArg:this,args:n})).then(s).catch(r)})}return e}var Se=()=>{};function Le(...o){let t=0,e,n=!0,s=Se,r,a,l,d,p;!(0,ne.isRef)(o[0])&&typeof o[0]=="object"?{delay:a,trailing:l=!0,leading:d=!0,rejectOnCancel:p=!1}=o[0]:[a,l=!0,d=!0,p=!1]=o;let v=()=>{e&&(clearTimeout(e),e=void 0,s(),s=Se)};return x=>{let A=(0,ne.toValue)(a),M=Date.now()-t,m=()=>r=x();return v(),A<=0?(t=Date.now(),m()):(M>A?(t=Date.now(),(d||!n)&&m()):l&&(r=new Promise((h,T)=>{s=p?T:h,e=setTimeout(()=>{t=Date.now(),n=!0,h(m()),v()},Math.max(0,A-M))})),!d&&!e&&(e=setTimeout(()=>n=!0,A)),n=!1,r)}}var We=o=>{let t=o.storage||ee(),e=(0,j.ref)([]),n=new Map,s=new Map,r=(0,j.ref)(null),a=(0,j.computed)(()=>{let i=r.value;if(!i)return null;let c=e.value.find(y=>y.id===i);if(!c)return null;let f=n.get(i);return f?{...c,engine:f}:null}),l=i=>{if(!t?.saveMessages)return;let c=i||r.value,f=e.value.find(S=>S.id===c);if(!f)return;f.updatedAt=Date.now(),t?.saveConversation?.(f);let y=n.get(f.id);y&&t.saveMessages(f.id,y.messages.value)},d=(i,c)=>{if(!o.autoSaveMessages||!t?.saveMessages)return;let f=s.get(i);f&&f();let y=o.autoSaveThrottle??1e3,S=Pe(()=>{l(i)},y,!0,!0),w=(0,j.watch)(c.messages,S,{deep:!0});s.set(i,w)},p=i=>{let c=s.get(i);c&&(c(),s.delete(i))};t?.loadConversations&&Promise.resolve(t.loadConversations()).then(i=>{e.value=i}).catch(i=>{console.error("[useConversation] loadConversations failed:",i)});let v=async(i,c)=>{let f=n.get(i);if(f)return f;let y=c?.initialMessages??o.useMessageOptions.initialMessages??[];if(t?.loadMessages)try{y=await t.loadMessages(i)}catch(w){console.error("[useConversation] loadMessages failed:",w)}let S=oe({...o.useMessageOptions,...c,initialMessages:y});return n.set(i,S),d(i,S),S};function R(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}let x=i=>{let{id:c=R(),title:f,metadata:y,useMessageOptions:S}=i||{},w=Date.now(),q={id:c,title:f,createdAt:w,updatedAt:w,metadata:y};e.value.unshift(q);let k=oe({...o.useMessageOptions,...S});return n.set(c,k),d(c,k),t?.saveConversation?.(q),t?.saveMessages?.(c,k.messages.value),r.value=c,a.value},A=i=>{let{excludeId:c}=i||{};n.forEach((f,y)=>{if(c&&y===c)return;f.isProcessing?.value||(p(y),n.delete(y))})};return{conversations:e,activeConversationId:r,activeConversation:a,createConversation:x,switchConversation:async i=>i?r.value===i?a.value:e.value.find(f=>f.id===i)?(await v(i),A({excludeId:i}),r.value=i,a.value):null:null,deleteConversation:async i=>{let c=e.value.findIndex(y=>y.id===i);if(c===-1)return;await n.get(i)?.abortRequest(),p(i),n.delete(i),e.value.splice(c,1),t?.deleteConversation?.(i),r.value===i&&(r.value=null,A())},clear:()=>{e.value.map(c=>c.id).forEach(c=>{t?.deleteConversation?.(c)}),n.forEach(c=>{c.abortRequest()}),s.forEach(c=>{c()}),e.value=[],n.clear(),s.clear(),r.value=null},updateConversationTitle:(i,c)=>{let f=e.value.find(y=>y.id===i);f&&(f.title=c,f.updatedAt=Date.now(),t?.saveConversation?.(f))},saveMessages:l,sendMessage:i=>{a.value?.engine.sendMessage(i)},abortActiveRequest:async()=>{await a.value?.engine.abortRequest()}}};0&&(module.exports={AIClient,EXCLUDE_MODE_REMOVE,ErrorType,IndexedDBStrategy,LocalStorageStrategy,StreamEventType,fallbackRolePlugin,indexedDBStorageStrategyFactory,lengthPlugin,localStorageStrategyFactory,sseStreamToGenerator,thinkingPlugin,toolPlugin,useConversation,useMessage});
|
|
3
|
+
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""){if(x.trim()==="data: [DONE]"){c&&(a=c),t.onDone(a);continue}try{let A=x.match(/^data: (.+)$/m);if(!A)continue;let M=JSON.parse(A[1]);t.onData(M),c=M.choices?.[0]?.finish_reason||void 0}catch(A){console.error("Error parsing SSE message:",A)}}}(r.trim()==="data: [DONE]"||e?.aborted)&&(e?.aborted&&(a="aborted"),t.onDone(a))}catch(d){if(e?.aborted)return;throw d}}function he(o){return o.map(t=>typeof t=="object"&&"role"in t&&"content"in t?{role:t.role,content:String(t.content),...t.name?{name:t.name}:{}}:typeof t=="string"?{role:"user",content:t}:{role:"user",content:String(t)})}function ye(o){return!o.choices||!o.choices.length?"":o.choices[0].message?.content||""}function ce(o="The operation was aborted"){let t=new Error(o);return t.name="AbortError",t}async function*Ce(o,t={}){let e=o.body?.getReader();if(!e)throw new Error("ReadableStream not supported");let{signal:n}=t,s=new TextDecoder,r="",a=()=>{e.cancel()};n?.addEventListener("abort",a);try{for(;;){if(n?.aborted)throw ce();let c;try{c=await e.read()}catch(x){throw n?.aborted?ce():x}let{done:d,value:f}=c;if(d){if(n?.aborted)throw ce();return}let v=s.decode(f,{stream:!0});r+=v;let R=r.split(`
|
|
4
|
+
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""&&x.startsWith("data: ")){let A=x.slice(6);if(A==="[DONE]")return;try{yield JSON.parse(A)}catch(M){console.warn("Failed to parse SSE data:",A,M)}}}}finally{n?.removeEventListener("abort",a),e.releaseLock()}}var j=class extends H{constructor(e){super(e);this.defaultModel="gpt-3.5-turbo";this.baseURL=e.apiUrl||"https://api.openai.com/v1",this.apiKey=e.apiKey||"",e.defaultModel&&(this.defaultModel=e.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(e){try{this.validateRequest(e);let n={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...e.options,stream:!1},s={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)};this.apiKey&&Object.assign(s.headers,{Authorization:`Bearer ${this.apiKey}`});let r=await fetch(`${this.baseURL}/chat/completions`,s);if(!r.ok){let a=await r.text();throw new Error(`HTTP error! status: ${r.status}, details: ${a}`)}return await r.json()}catch(n){throw le(n)}}async chatStream(e,n){let{signal:s,...r}=e.options||{};try{this.validateRequest(e);let a={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...r,stream:!0},c={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(a),signal:s};this.apiKey&&Object.assign(c.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,c);if(!d.ok){let f=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${f}`)}await Y(d,n,s)}catch(a){if(s?.aborted)return;n.onError(le(a))}}updateConfig(e){super.updateConfig(e),e.apiUrl&&(this.baseURL=e.apiUrl),e.apiKey&&(this.apiKey=e.apiKey),e.defaultModel&&(this.defaultModel=e.defaultModel)}};var Z=class{constructor(t){this.config=t,this.provider=this.createProvider(t)}createProvider(t){if(t.provider==="custom"&&"providerImplementation"in t)return t.providerImplementation;if(t.provider==="deepseek"){let e={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new j({...e,...t})}else return new j(t)}async chat(t){return this.provider.chat(t)}async chatStream(t,e){let n={...t,options:{...t.options,stream:!0}};return this.provider.chatStream(n,e)}getConfig(){return{...this.config}}updateConfig(t){this.config={...this.config,...t},t.provider&&t.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};var ve=require("vue");function X(o,t=new WeakMap){if(o==null||typeof o!="object")return o;try{let e=(0,ve.toRaw)(o);if(t.has(e))return t.get(e);if(Array.isArray(e)){let s=[];return t.set(e,s),s.push(...e.map(r=>X(r,t))),s}if(e instanceof Date||e instanceof RegExp||e instanceof ArrayBuffer||e instanceof Blob)return e;let n={};t.set(e,n);for(let s of Object.keys(e)){let r=Object.getOwnPropertyDescriptor(e,s);if(!r||r.get||r.set)continue;let a=e[s];typeof a!="function"&&typeof a!="symbol"&&(n[s]=X(a,t))}return n}catch(e){return console.warn("unwrapProxy error:",e),Array.isArray(o)?[]:{}}}var ee=o=>o.map(t=>{let{renderContent:e,...n}=t;if(!Array.isArray(e))return t;let s=e.filter(a=>a.type==="collapsible-text"),r=e.filter(a=>a.type==="markdown"||a.type==="text");return s.length>0&&(n.reasoning_content=s.map(a=>a.content).join("")),r.length>0&&(n.content=r.map(a=>a.content).join("")),n});var Q=o=>{let t=localStorage.getItem(o);return t?JSON.parse(t):[]},G=class{constructor(t="tiny-robot-ai-conversations"){this.storageKey=t}saveConversation(t){try{let e=Q(this.storageKey),n=e.findIndex(s=>s.id===t.id);n!==-1?Object.assign(e[n],t):e.unshift({...t,messages:[]}),localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(e){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e)}}loadConversations(){try{return Q(this.storageKey).map(e=>({id:e.id,title:e.title,createdAt:e.createdAt,updatedAt:e.updatedAt,metadata:e.metadata}))}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}saveMessages(t,e){try{let n=Q(this.storageKey),s=n.findIndex(r=>r.id===t);s!==-1&&(n[s].messages=e),localStorage.setItem(this.storageKey,JSON.stringify(n))}catch(n){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n)}}loadMessages(t){try{let n=Q(this.storageKey).find(r=>r.id===t);return ee(n?.messages||[])}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}deleteConversation(t){let e=Q(this.storageKey),n=e.findIndex(s=>s.id===t);n!==-1&&e.splice(n,1),localStorage.setItem(this.storageKey,JSON.stringify(e))}};var Me=require("idb");var V=class{constructor(t="tiny-robot-ai-db",e=3){this.db=null;this.dbName=t,this.dbVersion=e}async getDB(){return this.db||(this.db=await(0,Me.openDB)(this.dbName,this.dbVersion,{upgrade(t){t.objectStoreNames.contains("conversations")||t.createObjectStore("conversations",{keyPath:"id"}).createIndex("by-updated","updatedAt"),t.objectStoreNames.contains("messages")||t.createObjectStore("messages",{keyPath:"conversationId"})}})),this.db}async loadConversations(){try{return(await(await this.getDB()).getAllFromIndex("conversations","by-updated")).reverse()}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}async loadMessages(t){try{let n=await(await this.getDB()).get("messages",t);return n?ee(n.messages):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}async saveConversation(t){try{let e=await this.getDB(),n=X(t);await e.put("conversations",n)}catch(e){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e),e}}async saveMessages(t,e){try{let n=await this.getDB(),s=X(e);await n.put("messages",{conversationId:t,messages:s})}catch(n){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n),n}}async deleteConversation(t){try{let e=await this.getDB();await e.delete("conversations",t),await e.delete("messages",t)}catch(e){throw console.error("\u5220\u9664\u4F1A\u8BDD\u5931\u8D25:",e),e}}};function te(o={}){return new G(o.key||"tiny-robot-ai-conversations")}function be(o={}){return new V(o.dbName||"tiny-robot-ai-db",o.dbVersion||1)}var L=require("vue");var U=require("vue");var ue=(o={})=>{let{fallbackRole:t="assistant",...e}=o;return{name:"fallbackRole",...e,onBeforeRequest(n){let{requestBody:s}=n;return s.messages=s.messages.map(r=>({...r,role:r.role||t})),e.onBeforeRequest?.(n)}}};var de=(o={})=>{let{continueContent:t="Please continue with your previous answer.",...e}=o;return{name:"length",...e,onAfterRequest:async n=>{let{lastChoice:s,appendMessage:r,requestNext:a}=n;return s?.finish_reason==="length"&&(r({role:"user",content:t}),a()),e.onAfterRequest?.(n)}}};var ge=(o={})=>({name:"thinking",...o,onCompletionChunk(t){let{choice:e,currentMessage:n}=t,r=typeof(e?.message?.reasoning_content||e?.delta?.reasoning_content)=="string";return n.state?n.state.thinking=r:n.state={thinking:r},o.onCompletionChunk?.(t)},onTurnEnd(t){let e=t.currentTurn.slice(-1)[0];return e?.state&&(e.state.thinking=void 0),o.onTurnEnd?.(t)}});var Se=require("vue");var $=class extends Error{constructor(t){super(t),this.name="AbortError"}};function Ne(o){if(o.aborted)return{promise:Promise.reject(new $(String(o.reason??"Aborted"))),cleanup:()=>{}};let t=null;return{promise:new Promise((s,r)=>{t=()=>{r(new $(String(o.reason??"Aborted")))},o.addEventListener("abort",t,{once:!0})}),cleanup:()=>{t&&(o.removeEventListener("abort",t),t=null)}}}function Ae(o,t){let{promise:e,cleanup:n}=Ne(t);return Promise.race([o,e]).finally(n)}function we(o,t){let e={};for(let n in o)t.includes(n)&&(e[n]=o[n]);return e}function Te(o,t){let e={};for(let n in o)t.includes(n)||(e[n]=o[n]);return e}async function*oe(o){if(Re(o)){yield*o;return}let t=await o;if(Re(t)){yield*t;return}yield t}function Re(o){return o&&typeof o=="object"&&typeof o[Symbol.asyncIterator]=="function"}var pe=o=>typeof o=="object"&&o!==null,xe=o=>pe(o)&&typeof o.index=="number",J=(o,t)=>{for(let[e,n]of Object.entries(t)){let s=o[e];if(s)if(typeof s=="string"&&typeof n=="string")e==="type"&&s||(o[e]=s+n);else if(Array.isArray(s)&&Array.isArray(n))if(s.every(r=>xe(r))&&n.every(r=>xe(r))){let r=new Map(s.map(f=>[f.index,f])),a=new Map(n.map(f=>[f.index,f]));for(let[f,v]of a)if(r.has(f)){let R=r.get(f);r.set(f,J(R,v))}else r.set(f,v);let c=Math.max(...Array.from(r.keys()),-1)+1,d=c>s.length?Array.from({length:c}):s;for(let[f,v]of r)d[f]=v;o[e]=d}else o[e]=[...s,...n];else pe(s)&&pe(n)&&(o[e]=J(s,n));else o[e]=n}return o};function Fe(o,t){let e=[];for(let n=0;n<o.length;n++){let s=o[n];if(s.role==="assistant"&&s.tool_calls&&s.tool_calls.length>0){let r=new Set(s.tool_calls.map(d=>d.id)),a=new Set;for(let d=n+1;d<o.length;d++){let f=o[d];f.role==="tool"&&f.tool_call_id&&r.has(f.tool_call_id)&&a.add(f.tool_call_id)}let c=s.tool_calls.map(d=>d.id).filter(d=>!a.has(d));c.length>0&&e.push({insertAfterIndex:n,missingToolCallIds:c})}}for(let n=e.length-1;n>=0;n--){let{insertAfterIndex:s,missingToolCallIds:r}=e[n],a=r.map(c=>({role:"tool",tool_call_id:c,content:t}));o.splice(s+1,0,...a)}}var Pe="remove";function Ke(o,t,e,n){let s=o.filter(a=>a[e]),r=new Set(s.flatMap(a=>a.tool_calls?.map(c=>c.id)??[]));if(t===Pe)for(let a=o.length-1;a>=0;a--){let c=o[a];(c[e]||c[n]||c.tool_call_id&&r.has(c.tool_call_id))&&o.splice(a,1)}else if(t===!0)for(let a of o)(a[e]||a.tool_call_id&&r.has(a.tool_call_id))&&(a[n]=!0,delete a[e])}var je=o=>{let{getTools:t,beforeCallTools:e,callTool:n,onToolCallStart:s,onToolCallEnd:r,toolCallCancelledContent:a="Tool call cancelled.",toolCallFailedContent:c="Tool call failed.",autoFillMissingToolMessages:d=!1,excludeToolMessagesNextTurn:f=!1,...v}=o,R=Symbol("doNotSendNextTurn"),x=Symbol("doNotSend"),A=(...m)=>{let[h,{primaryMessage:T}]=m;T.state.toolCall[h.id].status="running",s?.(...m)},M=(...m)=>{let[h,{status:T,primaryMessage:O}]=m;O.state.toolCall[h.id].status=T,r?.(...m)};return{name:"tool",...v,onTurnStart:m=>{let{messages:h}=m;return d&&Fe(h,a),f&&Ke(h,f,R,x),v.onTurnStart?.(m)},onBeforeRequest:async m=>{let{messages:h,requestBody:T}=m;f===!0&&(T.messages=h.filter(E=>!E[x]));let O=await t?.();return O&&O.length>0&&(T.tools=O),v.onBeforeRequest?.(m)},onAfterRequest:async m=>{let{currentMessage:h,lastChoice:T,appendMessage:O,abortSignal:E,setRequestState:i,requestNext:l}=m;if(T?.finish_reason!=="tool_calls"||!h.tool_calls?.length)return;f&&(h[R]=!0),i("processing","calling-tools"),await e?.(h.tool_calls,{...m,currentMessage:h});let g=h.tool_calls.map(async y=>{let S=Math.floor(Date.now()/1e3),w=(0,Se.reactive)({role:"tool",tool_call_id:y.id,content:"",metadata:{createdAt:S,updatedAt:S}});O(w);let q={...m,primaryMessage:h,toolMessage:w};A(y,q);try{let k=n(y,q),N=oe(k);for await(let u of N){if(typeof u=="string")w.content+=u;else{let p={};try{p=JSON.parse(w.content||"{}")}catch(b){console.warn(b)}w.content=JSON.stringify(J(p,u))}w.metadata.updatedAt=Math.floor(Date.now()/1e3)}M(y,{...q,status:"success"})}catch(k){let N=k instanceof Error?k:new Error(String(k));if(E.aborted){M(y,{...q,status:"cancelled",error:N});return}console.error(k),w.content.length===0&&(w.content=c),M(y,{...q,status:"failed",error:N})}});return await Promise.all(g),l(),v.onAfterRequest?.(m)},onCompletionChunk:m=>{var T,O,E;let{currentMessage:h}=m;if(Array.isArray(h.tool_calls))for(let i of h.tool_calls)h.state?.toolCall?.[i.id]?.status||(h.state??(h.state={}),(T=h.state).toolCall??(T.toolCall={}),(O=h.state.toolCall)[E=i.id]??(O[E]={}));return v.onCompletionChunk?.(m)}}};var Le=o=>{let t=[];for(let e of o){if(e.name){let n=t.findIndex(s=>s.name===e.name);n!==-1&&t.splice(n,1)}t.push(e)}return t},ne=o=>{let{initialMessages:t=[],requestMessageFields:e=[],requestMessageFieldsExclude:n=["state","metadata","loading"],plugins:s=[],onCompletionChunk:r}=o,a=(0,U.ref)("idle"),c=(0,U.ref)(void 0),d=(0,U.ref)(t),f=(0,U.ref)(o.responseProvider),v=null,R=[],x={},A=[ue(),ge(),de()],M=Le(A.concat(s)),m=(0,U.computed)(()=>a.value==="processing"),h=async u=>{if(!u||!u.trim()){console.warn("Cannot send empty message");return}if(m.value){console.warn("Cannot send message while processing is in progress");return}let p=Math.floor(Date.now()/1e3);d.value.push({role:"user",content:u.trim(),metadata:{createdAt:p,updatedAt:p}}),R.push(d.value[d.value.length-1]),await w()},T=async(...u)=>{if(m.value){console.warn("Cannot send message while processing is in progress");return}d.value.push(...u),R.push(...u),await w()},O=u=>{let p=u;return e.length&&(p=p.map(b=>we(b,e))),n.length&&(p=p.map(b=>Te(b,n))),p},E=(u,p)=>{a.value=u,u==="processing"?c.value=p||"requesting":c.value=void 0},i=u=>{Object.assign(x,u)},l=u=>({messages:d.value,currentTurn:R,requestState:a.value,processingState:c.value,plugins:M,abortSignal:u,setRequestState:E,customContext:x,setCustomContext:i}),g=(u,p)=>typeof u.disabled=="function"?u.disabled(p):!!u.disabled,y=u=>!u||Object.keys(u).length===0?!1:Object.values(u).some(p=>!!p),S=async(u,p)=>{E("processing","requesting");let b=new Proxy({messages:O(d.value)},{set(D,P,F){return P==="messages"?(D.messages=O(F),!0):(D[P]=F,!0)}}),I=l(p);for(let D of M.filter(P=>!g(P,I)))await D.onBeforeRequest?.({...I,requestBody:b});let C=(0,U.reactive)({role:"",content:"",loading:!0});N(C);let _,re=u(b,p),B=oe(re);for await(let D of B){E("processing","completing"),C.loading&&(C.loading=void 0);let P=D.choices?.find(W=>W.index===0);if(P){_=P;let W=()=>{C.metadata||(C.metadata={});let{created:z,...Ie}=D;C.metadata.createdAt=z,C.metadata.updatedAt=Math.floor(Date.now()/1e3),Object.assign(C.metadata,Ie);let ae=y(P.delta)?P.delta:P.message;ae||(ae=P.delta||P.message||{}),J(C,ae)};if(r){let z=l(p);r({...z,chunk:D,choice:P,currentMessage:C},W)}else W()}let F=l(p);for(let W of M.filter(z=>!g(z,F)))W.onCompletionChunk?.({...F,abortSignal:p,chunk:D,choice:P,currentMessage:C})}await k(C,u,p,_)},w=async()=>{let u=new AbortController;v=u,x={};try{E("processing","requesting");let p=l(u.signal);for(let C of M.filter(_=>!g(_,p)))await C.onTurnStart?.(p);let b=f.value;try{await S(b,u.signal),E("completed")}catch(C){if(u.signal.aborted||C instanceof $||C instanceof Error&&C.name==="AbortError")E("aborted");else throw C}let I=l(u.signal);for(let C of M.filter(_=>!g(_,I)))await C.onTurnEnd?.(I)}catch(p){E("error");let b=!1,I=l(u.signal);for(let C of M.filter(_=>!g(_,I)))C.onError&&(b=!0,C.onError({...I,error:p}));if(!b)throw p}finally{let p=l(u.signal);for(let b of M.filter(I=>!g(I,p)))try{b.onFinally?.(p)}catch(I){console.error(`Error in onFinally hook for plugin ${b.name||"Anonymous"}:`,I)}v=null,R.slice(-1)[0]&&(R.slice(-1)[0].loading=void 0),R=[]}},q=async()=>{v?.abort(),m.value&&await new Promise(u=>{let p=(0,U.watch)(m,b=>{b||(p(),u())},{immediate:!0})})},k=async(u,p,b,I)=>{let C=!1,_=l(b),re=M.filter(B=>!g(B,_)).map(B=>{if(!B.onAfterRequest)return null;let D=F=>{N(F)},P=()=>{C=!0};return B.onAfterRequest({..._,currentMessage:u,lastChoice:I,appendMessage:D,requestNext:P})}).filter(B=>B!==null);await Ae(Promise.all(re),b),C&&await S(p,b)},N=u=>{let p=Array.isArray(u)?u:[u];d.value.push(...p),R.push(...p)};return{requestState:a,processingState:c,messages:d,responseProvider:f,isProcessing:m,sendMessage:h,send:T,abortRequest:q}};var se=require("vue");function Oe(o,t=200,e=!1,n=!0,s=!1){return We(He(t,e,n,s),o)}function We(o,t){function e(...n){return new Promise((s,r)=>{Promise.resolve(o(()=>t.apply(this,n),{fn:t,thisArg:this,args:n})).then(s).catch(r)})}return e}var Ee=()=>{};function He(...o){let t=0,e,n=!0,s=Ee,r,a,c,d,f;!(0,se.isRef)(o[0])&&typeof o[0]=="object"?{delay:a,trailing:c=!0,leading:d=!0,rejectOnCancel:f=!1}=o[0]:[a,c=!0,d=!0,f=!1]=o;let v=()=>{e&&(clearTimeout(e),e=void 0,s(),s=Ee)};return x=>{let A=(0,se.toValue)(a),M=Date.now()-t,m=()=>r=x();return v(),A<=0?(t=Date.now(),m()):(M>A?(t=Date.now(),(d||!n)&&m()):c&&(r=new Promise((h,T)=>{s=f?T:h,e=setTimeout(()=>{t=Date.now(),n=!0,h(m()),v()},Math.max(0,A-M))})),!d&&!e&&(e=setTimeout(()=>n=!0,A)),n=!1,r)}}var Ge=o=>{let t=o.storage||te(),e=(0,L.ref)([]),n=new Map,s=new Map,r=(0,L.ref)(null),a=(0,L.computed)(()=>{let i=r.value;if(!i)return null;let l=e.value.find(y=>y.id===i);if(!l)return null;let g=n.get(i);return g?{...l,engine:g}:null}),c=i=>{if(!t?.saveMessages)return;let l=i||r.value,g=e.value.find(S=>S.id===l);if(!g)return;g.updatedAt=Date.now(),t?.saveConversation?.(g);let y=n.get(g.id);y&&t.saveMessages(g.id,y.messages.value)},d=(i,l)=>{if(!o.autoSaveMessages||!t?.saveMessages)return;let g=s.get(i);g&&g();let y=o.autoSaveThrottle??1e3,S=Oe(()=>{c(i)},y,!0,!0),w=(0,L.watch)(l.messages,S,{deep:!0});s.set(i,w)},f=i=>{let l=s.get(i);l&&(l(),s.delete(i))};t?.loadConversations&&Promise.resolve(t.loadConversations()).then(i=>{if(!i?.length)return[];if(e.value.length===0)return e.value=i,e.value;let l=new Map(e.value.map(g=>[g.id,g]));return i.forEach(g=>{l.has(g.id)||l.set(g.id,g)}),e.value=Array.from(l.values()),e.value}).then(i=>{o.onLoad?.(i)}).catch(i=>{console.error("[useConversation] loadConversations failed:",i)});let v=async(i,l)=>{let g=n.get(i);if(g)return g;let y=l?.initialMessages??o.useMessageOptions.initialMessages??[];if(t?.loadMessages)try{y=await t.loadMessages(i)}catch(w){console.error("[useConversation] loadMessages failed:",w)}let S=ne({...o.useMessageOptions,...l,initialMessages:y});return n.set(i,S),d(i,S),S};function R(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}let x=i=>{let{id:l=R(),title:g,metadata:y,useMessageOptions:S}=i||{},w=Date.now(),q={id:l,title:g,createdAt:w,updatedAt:w,metadata:y};e.value.unshift(q);let k=ne({...o.useMessageOptions,...S});return n.set(l,k),d(l,k),t?.saveConversation?.(q),t?.saveMessages?.(l,k.messages.value),r.value=l,a.value},A=i=>{let{excludeId:l}=i||{};n.forEach((g,y)=>{if(l&&y===l)return;g.isProcessing?.value||(f(y),n.delete(y))})};return{conversations:e,activeConversationId:r,activeConversation:a,createConversation:x,switchConversation:async i=>i?r.value===i?a.value:e.value.find(g=>g.id===i)?(await v(i),A({excludeId:i}),r.value=i,a.value):null:null,deleteConversation:async i=>{let l=e.value.findIndex(y=>y.id===i);if(l===-1)return;await n.get(i)?.abortRequest(),f(i),n.delete(i),e.value.splice(l,1),t?.deleteConversation?.(i),r.value===i&&(r.value=null,A())},clear:()=>{e.value.map(l=>l.id).forEach(l=>{t?.deleteConversation?.(l)}),n.forEach(l=>{l.abortRequest()}),s.forEach(l=>{l()}),e.value=[],n.clear(),s.clear(),r.value=null},updateConversationTitle:(i,l)=>{let g=e.value.find(y=>y.id===i);g&&(g.title=l,g.updatedAt=Date.now(),t?.saveConversation?.(g))},saveMessages:c,sendMessage:i=>{a.value?.engine.sendMessage(i)},abortActiveRequest:async()=>{await a.value?.engine.abortRequest()}}};0&&(module.exports={AIClient,BaseModelProvider,EXCLUDE_MODE_REMOVE,ErrorType,IndexedDBStrategy,LocalStorageStrategy,OpenAIProvider,StreamEventType,extractTextFromResponse,fallbackRolePlugin,formatMessages,handleSSEStream,indexedDBStorageStrategyFactory,lengthPlugin,localStorageStrategyFactory,sseStreamToGenerator,thinkingPlugin,toolPlugin,useConversation,useMessage});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var G=class{constructor(t){this.config=t}updateConfig(t){this.config={...this.config,...t}}getConfig(){return{...this.config}}validateRequest(t){if(!t.messages||!Array.isArray(t.messages)||t.messages.length===0)throw new Error("\u8BF7\u6C42\u5FC5\u987B\u5305\u542B\u81F3\u5C11\u4E00\u6761\u6D88\u606F");for(let e of t.messages)if(!e.role||!e.content)throw new Error("\u6BCF\u6761\u6D88\u606F\u5FC5\u987B\u5305\u542B\u89D2\u8272\u548C\u5185\u5BB9")}};var Me=(c=>(c.NETWORK_ERROR="network_error",c.AUTHENTICATION_ERROR="authentication_error",c.RATE_LIMIT_ERROR="rate_limit_error",c.SERVER_ERROR="server_error",c.MODEL_ERROR="model_error",c.TIMEOUT_ERROR="timeout_error",c.UNKNOWN_ERROR="unknown_error",c))(Me||{}),be=(n=>(n.DATA="data",n.ERROR="error",n.DONE="done",n))(be||{});function F(o){return{type:o.type||"unknown_error",message:o.message||"\u672A\u77E5\u9519\u8BEF",statusCode:o.statusCode,originalError:o.originalError}}function te(o){if(!o.response)return F({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:o});if(o.response){let{status:t,data:e}=o.response;return t===401||t===403?F({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:t,originalError:o}):t===429?F({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:t,originalError:o}):t>=500?F({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:t,originalError:o}):F({type:"unknown_error",message:e?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${t}`,statusCode:t,originalError:o})}return o.code==="ECONNABORTED"?F({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:o}):F({type:"unknown_error",message:o.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:o})}async function ne(o,t,e){let n=o.body?.getReader();if(!n)throw new Error("Response body is null");let s=new TextDecoder,r="",a,c;e&&e.addEventListener("abort",()=>{n.cancel().catch(d=>console.error("Error cancelling reader:",d))},{once:!0});try{for(;;){if(e?.aborted){await n.cancel();break}let{done:d,value:f}=await n.read();if(d)break;let v=s.decode(f,{stream:!0});r+=v;let R=r.split(`
|
|
2
2
|
|
|
3
|
-
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""){if(x.trim()==="data: [DONE]"){
|
|
4
|
-
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""&&x.startsWith("data: ")){let A=x.slice(6);if(A==="[DONE]")return;try{yield JSON.parse(A)}catch(M){console.warn("Failed to parse SSE data:",A,M)}}}}finally{n?.removeEventListener("abort",a),e.releaseLock()}}var H=class extends z{constructor(e){super(e);this.defaultModel="gpt-3.5-turbo";this.baseURL=e.apiUrl||"https://api.openai.com/v1",this.apiKey=e.apiKey||"",e.defaultModel&&(this.defaultModel=e.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(e){try{this.validateRequest(e);let n={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...e.options,stream:!1},s={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)};this.apiKey&&Object.assign(s.headers,{Authorization:`Bearer ${this.apiKey}`});let r=await fetch(`${this.baseURL}/chat/completions`,s);if(!r.ok){let a=await r.text();throw new Error(`HTTP error! status: ${r.status}, details: ${a}`)}return await r.json()}catch(n){throw te(n)}}async chatStream(e,n){let{signal:s,...r}=e.options||{};try{this.validateRequest(e);let a={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...r,stream:!0},l={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(a),signal:s};this.apiKey&&Object.assign(l.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,l);if(!d.ok){let p=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${p}`)}await ie(d,n,s)}catch(a){if(s?.aborted)return;n.onError(te(a))}}updateConfig(e){super.updateConfig(e),e.apiUrl&&(this.baseURL=e.apiUrl),e.apiKey&&(this.apiKey=e.apiKey),e.defaultModel&&(this.defaultModel=e.defaultModel)}};var ne=class{constructor(t){this.config=t,this.provider=this.createProvider(t)}createProvider(t){if(t.provider==="custom"&&"providerImplementation"in t)return t.providerImplementation;if(t.provider==="deepseek"){let e={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new H({...e,...t})}else return new H(t)}async chat(t){return this.provider.chat(t)}async chatStream(t,e){let n={...t,options:{...t.options,stream:!0}};return this.provider.chatStream(n,e)}getConfig(){return{...this.config}}updateConfig(t){this.config={...this.config,...t},t.provider&&t.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};import{toRaw as xe}from"vue";function G(o,t=new WeakSet){if(o==null||typeof o!="object")return o;if(t.has(o))return Array.isArray(o)?[]:{};t.add(o);try{let e=xe(o);if(Array.isArray(e))return e.map(s=>G(s,t));if(e instanceof Date||e instanceof RegExp||e instanceof ArrayBuffer||e instanceof Blob)return e;let n={};for(let s in e){if(typeof s=="symbol")continue;let r=Object.getOwnPropertyDescriptor(e,s);if(!r||r.get||r.set)continue;let a=e[s];typeof a!="function"&&typeof a!="symbol"&&(n[s]=G(a,t))}return n}catch(e){return console.warn("unwrapProxy error:",e),Array.isArray(o)?[]:{}}}var X=o=>o.map(t=>{let{renderContent:e,...n}=t;if(!Array.isArray(e))return t;let s=e.filter(a=>a.type==="collapsible-text"),r=e.filter(a=>a.type==="markdown"||a.type==="text");return s.length>0&&(n.reasoning_content=s.map(a=>a.content).join("")),r.length>0&&(n.content=r.map(a=>a.content).join("")),n});var V=o=>{let t=localStorage.getItem(o);return t?JSON.parse(t):[]},$=class{constructor(t="tiny-robot-ai-conversations"){this.storageKey=t}saveConversation(t){try{let e=V(this.storageKey),n=e.findIndex(s=>s.id===t.id);n!==-1?Object.assign(e[n],t):e.unshift({...t,messages:[]}),localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(e){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e)}}loadConversations(){try{return V(this.storageKey).map(e=>({id:e.id,title:e.title,createdAt:e.createdAt,updatedAt:e.updatedAt,metadata:e.metadata}))}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}saveMessages(t,e){try{let n=V(this.storageKey),s=n.findIndex(r=>r.id===t);s!==-1&&(n[s].messages=e),localStorage.setItem(this.storageKey,JSON.stringify(n))}catch(n){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n)}}loadMessages(t){try{let n=V(this.storageKey).find(r=>r.id===t);return X(n?.messages||[])}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}deleteConversation(t){let e=V(this.storageKey),n=e.findIndex(s=>s.id===t);n!==-1&&e.splice(n,1),localStorage.setItem(this.storageKey,JSON.stringify(e))}};import{openDB as Ae}from"idb";var J=class{constructor(t="tiny-robot-ai-db",e=3){this.db=null;this.dbName=t,this.dbVersion=e}async getDB(){return this.db||(this.db=await Ae(this.dbName,this.dbVersion,{upgrade(t){t.objectStoreNames.contains("conversations")||t.createObjectStore("conversations",{keyPath:"id"}).createIndex("by-updated","updatedAt"),t.objectStoreNames.contains("messages")||t.createObjectStore("messages",{keyPath:"conversationId"})}})),this.db}async loadConversations(){try{return(await(await this.getDB()).getAllFromIndex("conversations","by-updated")).reverse()}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}async loadMessages(t){try{let n=await(await this.getDB()).get("messages",t);return n?X(n.messages):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}async saveConversation(t){try{let e=await this.getDB(),n=G(t);await e.put("conversations",n)}catch(e){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e),e}}async saveMessages(t,e){try{let n=await this.getDB(),s=G(e);await n.put("messages",{conversationId:t,messages:s})}catch(n){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n),n}}async deleteConversation(t){try{let e=await this.getDB();await e.delete("conversations",t),await e.delete("messages",t)}catch(e){throw console.error("\u5220\u9664\u4F1A\u8BDD\u5931\u8D25:",e),e}}};function se(o={}){return new $(o.key||"tiny-robot-ai-conversations")}function we(o={}){return new J(o.dbName||"tiny-robot-ai-db",o.dbVersion||1)}import{computed as Fe,ref as Ce,watch as Ke}from"vue";import{computed as Ie,reactive as ke,ref as Y,watch as _e}from"vue";var le=(o={})=>{let{fallbackRole:t="assistant",...e}=o;return{name:"fallbackRole",...e,onBeforeRequest(n){let{requestBody:s,messages:r}=n;return s.messages=r.map(a=>({...a,role:a.role||t})),e.onBeforeRequest?.(n)}}};var ce=(o={})=>{let{continueContent:t="Please continue with your previous answer.",...e}=o;return{name:"length",...e,onAfterRequest:async n=>{let{lastChoice:s,appendMessage:r,requestNext:a}=n;return s?.finish_reason==="length"&&(r({role:"user",content:t}),a()),e.onAfterRequest?.(n)}}};var ue=(o={})=>({name:"thinking",...o,onCompletionChunk(t){let{choice:e,currentMessage:n}=t,r=typeof(e?.message?.reasoning_content||e?.delta?.reasoning_content)=="string";return n.state?n.state.thinking=r:n.state={thinking:r},o.onCompletionChunk?.(t)},onTurnEnd(t){let e=t.currentTurn.slice(-1)[0];return e?.state&&(e.state.thinking=void 0),o.onTurnEnd?.(t)}});import{reactive as Se}from"vue";var j=class extends Error{constructor(t){super(t),this.name="AbortError"}};function Te(o){if(o.aborted)return{promise:Promise.reject(new j(String(o.reason??"Aborted"))),cleanup:()=>{}};let t=null;return{promise:new Promise((s,r)=>{t=()=>{r(new j(String(o.reason??"Aborted")))},o.addEventListener("abort",t,{once:!0})}),cleanup:()=>{t&&(o.removeEventListener("abort",t),t=null)}}}function pe(o,t){let{promise:e,cleanup:n}=Te(t);return Promise.race([o,e]).finally(n)}function fe(o,t){let e={};for(let n in o)t.includes(n)&&(e[n]=o[n]);return e}function me(o,t){let e={};for(let n in o)t.includes(n)||(e[n]=o[n]);return e}async function*Q(o){if(de(o)){yield*o;return}let t=await o;if(de(t)){yield*t;return}yield t}function de(o){return o&&typeof o=="object"&&typeof o[Symbol.asyncIterator]=="function"}var re=o=>typeof o=="object"&&o!==null,ge=o=>re(o)&&typeof o.index=="number",L=(o,t)=>{for(let[e,n]of Object.entries(t)){let s=o[e];if(s)if(typeof s=="string"&&typeof n=="string")e==="type"&&s||(o[e]=s+n);else if(Array.isArray(s)&&Array.isArray(n))if(s.every(r=>ge(r))&&n.every(r=>ge(r))){let r=new Map(s.map(p=>[p.index,p])),a=new Map(n.map(p=>[p.index,p]));for(let[p,v]of a)if(r.has(p)){let R=r.get(p);r.set(p,L(R,v))}else r.set(p,v);let l=Math.max(...Array.from(r.keys()),-1)+1,d=l>s.length?Array.from({length:l}):s;for(let[p,v]of r)d[p]=v;o[e]=d}else o[e]=[...s,...n];else re(s)&&re(n)&&(o[e]=L(s,n));else o[e]=n}return o};function Pe(o,t){let e=[];for(let n=0;n<o.length;n++){let s=o[n];if(s.role==="assistant"&&s.tool_calls&&s.tool_calls.length>0){let r=new Set(s.tool_calls.map(d=>d.id)),a=new Set;for(let d=n+1;d<o.length;d++){let p=o[d];p.role==="tool"&&p.tool_call_id&&r.has(p.tool_call_id)&&a.add(p.tool_call_id)}let l=s.tool_calls.map(d=>d.id).filter(d=>!a.has(d));l.length>0&&e.push({insertAfterIndex:n,missingToolCallIds:l})}}for(let n=e.length-1;n>=0;n--){let{insertAfterIndex:s,missingToolCallIds:r}=e[n],a=r.map(l=>({role:"tool",tool_call_id:l,content:t}));o.splice(s+1,0,...a)}}var Ee="remove";function Oe(o,t,e,n){let s=o.filter(a=>a[e]),r=new Set(s.flatMap(a=>a.tool_calls?.map(l=>l.id)??[]));if(t===Ee)for(let a=o.length-1;a>=0;a--){let l=o[a];(l[e]||l[n]||l.tool_call_id&&r.has(l.tool_call_id))&&o.splice(a,1)}else if(t===!0)for(let a of o)(a[e]||a.tool_call_id&&r.has(a.tool_call_id))&&(a[n]=!0,delete a[e])}var yt=o=>{let{getTools:t,beforeCallTools:e,callTool:n,onToolCallStart:s,onToolCallEnd:r,toolCallCancelledContent:a="Tool call cancelled.",toolCallFailedContent:l="Tool call failed.",autoFillMissingToolMessages:d=!1,excludeToolMessagesNextTurn:p=!1,...v}=o,R=Symbol("doNotSendNextTurn"),x=Symbol("doNotSend"),A=(...m)=>{let[h,{primaryMessage:T}]=m;T.state.toolCall[h.id].status="running",s?.(...m)},M=(...m)=>{let[h,{status:T,primaryMessage:O}]=m;O.state.toolCall[h.id].status=T,r?.(...m)};return{name:"tool",...v,onTurnStart:m=>{let{messages:h}=m;return d&&Pe(h,a),p&&Oe(h,p,R,x),v.onTurnStart?.(m)},onBeforeRequest:async m=>{let{messages:h,requestBody:T}=m;p===!0&&(T.messages=h.filter(E=>!E[x]));let O=await t?.();return O&&O.length>0&&(T.tools=O),v.onBeforeRequest?.(m)},onAfterRequest:async m=>{let{currentMessage:h,lastChoice:T,appendMessage:O,abortSignal:E,setRequestState:i,requestNext:c}=m;if(T?.finish_reason!=="tool_calls"||!h.tool_calls?.length)return;p&&(h[R]=!0),i("processing","calling-tools"),await e?.(h.tool_calls,{...m,currentMessage:h});let f=h.tool_calls.map(async y=>{let S=Math.floor(Date.now()/1e3),w=Se({role:"tool",tool_call_id:y.id,content:"",metadata:{createdAt:S,updatedAt:S}});O(w);let U={...m,primaryMessage:h,toolMessage:w};A(y,U);try{let k=n(y,U),B=Q(k);for await(let u of B){if(typeof u=="string")w.content+=u;else{let g={};try{g=JSON.parse(w.content||"{}")}catch(b){console.warn(b)}w.content=JSON.stringify(L(g,u))}w.metadata.updatedAt=Math.floor(Date.now()/1e3)}M(y,{...U,status:"success"})}catch(k){let B=k instanceof Error?k:new Error(String(k));if(E.aborted){M(y,{...U,status:"cancelled",error:B});return}console.error(k),w.content.length===0&&(w.content=l),M(y,{...U,status:"failed",error:B})}});return await Promise.all(f),c(),v.onAfterRequest?.(m)},onCompletionChunk:m=>{var T,O,E;let{currentMessage:h}=m;if(Array.isArray(h.tool_calls))for(let i of h.tool_calls)h.state?.toolCall?.[i.id]?.status||(h.state??(h.state={}),(T=h.state).toolCall??(T.toolCall={}),(O=h.state.toolCall)[E=i.id]??(O[E]={}));return v.onCompletionChunk?.(m)}}};var De=o=>{let t=[];for(let e of o){if(e.name){let n=t.findIndex(s=>s.name===e.name);n!==-1&&t.splice(n,1)}t.push(e)}return t},ae=o=>{let{initialMessages:t=[],requestMessageFields:e=[],requestMessageFieldsExclude:n=["state","metadata","loading"],plugins:s=[],onCompletionChunk:r}=o,a=Y("idle"),l=Y(void 0),d=Y(t),p=Y(o.responseProvider),v=null,R=[],x={},A=[le(),ue(),ce()],M=De(A.concat(s)),m=Ie(()=>a.value==="processing"),h=async u=>{if(!u||!u.trim()){console.warn("Cannot send empty message");return}if(m.value){console.warn("Cannot send message while processing is in progress");return}let g=Math.floor(Date.now()/1e3);d.value.push({role:"user",content:u.trim(),metadata:{createdAt:g,updatedAt:g}}),R.push(d.value[d.value.length-1]),await w()},T=async(...u)=>{if(m.value){console.warn("Cannot send message while processing is in progress");return}d.value.push(...u),R.push(...u),await w()},O=u=>{let g=u;return e.length&&(g=g.map(b=>fe(b,e))),n.length&&(g=g.map(b=>me(b,n))),g},E=(u,g)=>{a.value=u,u==="processing"?l.value=g||"requesting":l.value=void 0},i=u=>{Object.assign(x,u)},c=u=>({messages:d.value,currentTurn:R,requestState:a.value,processingState:l.value,plugins:M,abortSignal:u,setRequestState:E,customContext:x,setCustomContext:i}),f=(u,g)=>typeof u.disabled=="function"?u.disabled(g):!!u.disabled,y=u=>!u||Object.keys(u).length===0?!1:Object.values(u).some(g=>!!g),S=async(u,g)=>{E("processing","requesting");let b=new Proxy({messages:O(d.value)},{set(D,P,N){return P==="messages"?(D.messages=O(N),!0):(D[P]=N,!0)}}),I=c(g);for(let D of M.filter(P=>!f(P,I)))await D.onBeforeRequest?.({...I,requestBody:b});let C=ke({role:"",content:"",loading:!0});B(C);let _,Z=u(b,g),q=Q(Z);for await(let D of q){E("processing","completing"),C.loading&&(C.loading=void 0);let P=D.choices?.find(K=>K.index===0);if(P){_=P;let K=()=>{C.metadata||(C.metadata={});let{created:W,...ve}=D;C.metadata.createdAt=W,C.metadata.updatedAt=Math.floor(Date.now()/1e3),Object.assign(C.metadata,ve);let ee=y(P.delta)?P.delta:P.message;ee||(ee=P.delta||P.message||{}),L(C,ee)};if(r){let W=c(g);r({...W,chunk:D,choice:P,currentMessage:C},K)}else K()}let N=c(g);for(let K of M.filter(W=>!f(W,N)))K.onCompletionChunk?.({...N,abortSignal:g,chunk:D,choice:P,currentMessage:C})}await k(C,u,g,_)},w=async()=>{let u=new AbortController;v=u,x={};try{E("processing","requesting");let g=c(u.signal);for(let C of M.filter(_=>!f(_,g)))await C.onTurnStart?.(g);let b=p.value;try{await S(b,u.signal),E("completed")}catch(C){if(u.signal.aborted||C instanceof j||C instanceof Error&&C.name==="AbortError")E("aborted");else throw C}let I=c(u.signal);for(let C of M.filter(_=>!f(_,I)))await C.onTurnEnd?.(I)}catch(g){E("error");let b=!1,I=c(u.signal);for(let C of M.filter(_=>!f(_,I)))b=!0,C.onError?.({...I,error:g});if(!b)throw g}finally{let g=c(u.signal);for(let b of M.filter(I=>!f(I,g)))try{b.onFinally?.(g)}catch(I){console.error(`Error in onFinally hook for plugin ${b.name||"Anonymous"}:`,I)}v=null,R.slice(-1)[0]&&(R.slice(-1)[0].loading=void 0),R=[]}},U=async()=>{v?.abort(),m.value&&await new Promise(u=>{let g=_e(m,b=>{b||(g(),u())},{immediate:!0})})},k=async(u,g,b,I)=>{let C=!1,_=c(b),Z=M.filter(q=>!f(q,_)).map(q=>{if(!q.onAfterRequest)return null;let D=N=>{B(N)},P=()=>{C=!0};return q.onAfterRequest({..._,currentMessage:u,lastChoice:I,appendMessage:D,requestNext:P})}).filter(q=>q!==null);await pe(Promise.all(Z),b),C&&await S(g,b)},B=u=>{let g=Array.isArray(u)?u:[u];d.value.push(...g),R.push(...g)};return{requestState:a,processingState:l,messages:d,responseProvider:p,isProcessing:m,sendMessage:h,send:T,abortRequest:U}};import{isRef as Ue,toValue as qe}from"vue";function ye(o,t=200,e=!1,n=!0,s=!1){return Be(Ne(t,e,n,s),o)}function Be(o,t){function e(...n){return new Promise((s,r)=>{Promise.resolve(o(()=>t.apply(this,n),{fn:t,thisArg:this,args:n})).then(s).catch(r)})}return e}var he=()=>{};function Ne(...o){let t=0,e,n=!0,s=he,r,a,l,d,p;!Ue(o[0])&&typeof o[0]=="object"?{delay:a,trailing:l=!0,leading:d=!0,rejectOnCancel:p=!1}=o[0]:[a,l=!0,d=!0,p=!1]=o;let v=()=>{e&&(clearTimeout(e),e=void 0,s(),s=he)};return x=>{let A=qe(a),M=Date.now()-t,m=()=>r=x();return v(),A<=0?(t=Date.now(),m()):(M>A?(t=Date.now(),(d||!n)&&m()):l&&(r=new Promise((h,T)=>{s=p?T:h,e=setTimeout(()=>{t=Date.now(),n=!0,h(m()),v()},Math.max(0,A-M))})),!d&&!e&&(e=setTimeout(()=>n=!0,A)),n=!1,r)}}var It=o=>{let t=o.storage||se(),e=Ce([]),n=new Map,s=new Map,r=Ce(null),a=Fe(()=>{let i=r.value;if(!i)return null;let c=e.value.find(y=>y.id===i);if(!c)return null;let f=n.get(i);return f?{...c,engine:f}:null}),l=i=>{if(!t?.saveMessages)return;let c=i||r.value,f=e.value.find(S=>S.id===c);if(!f)return;f.updatedAt=Date.now(),t?.saveConversation?.(f);let y=n.get(f.id);y&&t.saveMessages(f.id,y.messages.value)},d=(i,c)=>{if(!o.autoSaveMessages||!t?.saveMessages)return;let f=s.get(i);f&&f();let y=o.autoSaveThrottle??1e3,S=ye(()=>{l(i)},y,!0,!0),w=Ke(c.messages,S,{deep:!0});s.set(i,w)},p=i=>{let c=s.get(i);c&&(c(),s.delete(i))};t?.loadConversations&&Promise.resolve(t.loadConversations()).then(i=>{e.value=i}).catch(i=>{console.error("[useConversation] loadConversations failed:",i)});let v=async(i,c)=>{let f=n.get(i);if(f)return f;let y=c?.initialMessages??o.useMessageOptions.initialMessages??[];if(t?.loadMessages)try{y=await t.loadMessages(i)}catch(w){console.error("[useConversation] loadMessages failed:",w)}let S=ae({...o.useMessageOptions,...c,initialMessages:y});return n.set(i,S),d(i,S),S};function R(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}let x=i=>{let{id:c=R(),title:f,metadata:y,useMessageOptions:S}=i||{},w=Date.now(),U={id:c,title:f,createdAt:w,updatedAt:w,metadata:y};e.value.unshift(U);let k=ae({...o.useMessageOptions,...S});return n.set(c,k),d(c,k),t?.saveConversation?.(U),t?.saveMessages?.(c,k.messages.value),r.value=c,a.value},A=i=>{let{excludeId:c}=i||{};n.forEach((f,y)=>{if(c&&y===c)return;f.isProcessing?.value||(p(y),n.delete(y))})};return{conversations:e,activeConversationId:r,activeConversation:a,createConversation:x,switchConversation:async i=>i?r.value===i?a.value:e.value.find(f=>f.id===i)?(await v(i),A({excludeId:i}),r.value=i,a.value):null:null,deleteConversation:async i=>{let c=e.value.findIndex(y=>y.id===i);if(c===-1)return;await n.get(i)?.abortRequest(),p(i),n.delete(i),e.value.splice(c,1),t?.deleteConversation?.(i),r.value===i&&(r.value=null,A())},clear:()=>{e.value.map(c=>c.id).forEach(c=>{t?.deleteConversation?.(c)}),n.forEach(c=>{c.abortRequest()}),s.forEach(c=>{c()}),e.value=[],n.clear(),s.clear(),r.value=null},updateConversationTitle:(i,c)=>{let f=e.value.find(y=>y.id===i);f&&(f.title=c,f.updatedAt=Date.now(),t?.saveConversation?.(f))},saveMessages:l,sendMessage:i=>{a.value?.engine.sendMessage(i)},abortActiveRequest:async()=>{await a.value?.engine.abortRequest()}}};export{ne as AIClient,Ee as EXCLUDE_MODE_REMOVE,Me as ErrorType,J as IndexedDBStrategy,$ as LocalStorageStrategy,be as StreamEventType,le as fallbackRolePlugin,we as indexedDBStorageStrategyFactory,ce as lengthPlugin,se as localStorageStrategyFactory,Re as sseStreamToGenerator,ue as thinkingPlugin,yt as toolPlugin,It as useConversation,ae as useMessage};
|
|
3
|
+
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""){if(x.trim()==="data: [DONE]"){c&&(a=c),t.onDone(a);continue}try{let A=x.match(/^data: (.+)$/m);if(!A)continue;let M=JSON.parse(A[1]);t.onData(M),c=M.choices?.[0]?.finish_reason||void 0}catch(A){console.error("Error parsing SSE message:",A)}}}(r.trim()==="data: [DONE]"||e?.aborted)&&(e?.aborted&&(a="aborted"),t.onDone(a))}catch(d){if(e?.aborted)return;throw d}}function Re(o){return o.map(t=>typeof t=="object"&&"role"in t&&"content"in t?{role:t.role,content:String(t.content),...t.name?{name:t.name}:{}}:typeof t=="string"?{role:"user",content:t}:{role:"user",content:String(t)})}function xe(o){return!o.choices||!o.choices.length?"":o.choices[0].message?.content||""}function oe(o="The operation was aborted"){let t=new Error(o);return t.name="AbortError",t}async function*Ae(o,t={}){let e=o.body?.getReader();if(!e)throw new Error("ReadableStream not supported");let{signal:n}=t,s=new TextDecoder,r="",a=()=>{e.cancel()};n?.addEventListener("abort",a);try{for(;;){if(n?.aborted)throw oe();let c;try{c=await e.read()}catch(x){throw n?.aborted?oe():x}let{done:d,value:f}=c;if(d){if(n?.aborted)throw oe();return}let v=s.decode(f,{stream:!0});r+=v;let R=r.split(`
|
|
4
|
+
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""&&x.startsWith("data: ")){let A=x.slice(6);if(A==="[DONE]")return;try{yield JSON.parse(A)}catch(M){console.warn("Failed to parse SSE data:",A,M)}}}}finally{n?.removeEventListener("abort",a),e.releaseLock()}}var j=class extends G{constructor(e){super(e);this.defaultModel="gpt-3.5-turbo";this.baseURL=e.apiUrl||"https://api.openai.com/v1",this.apiKey=e.apiKey||"",e.defaultModel&&(this.defaultModel=e.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(e){try{this.validateRequest(e);let n={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...e.options,stream:!1},s={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)};this.apiKey&&Object.assign(s.headers,{Authorization:`Bearer ${this.apiKey}`});let r=await fetch(`${this.baseURL}/chat/completions`,s);if(!r.ok){let a=await r.text();throw new Error(`HTTP error! status: ${r.status}, details: ${a}`)}return await r.json()}catch(n){throw te(n)}}async chatStream(e,n){let{signal:s,...r}=e.options||{};try{this.validateRequest(e);let a={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...r,stream:!0},c={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(a),signal:s};this.apiKey&&Object.assign(c.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,c);if(!d.ok){let f=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${f}`)}await ne(d,n,s)}catch(a){if(s?.aborted)return;n.onError(te(a))}}updateConfig(e){super.updateConfig(e),e.apiUrl&&(this.baseURL=e.apiUrl),e.apiKey&&(this.apiKey=e.apiKey),e.defaultModel&&(this.defaultModel=e.defaultModel)}};var se=class{constructor(t){this.config=t,this.provider=this.createProvider(t)}createProvider(t){if(t.provider==="custom"&&"providerImplementation"in t)return t.providerImplementation;if(t.provider==="deepseek"){let e={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new j({...e,...t})}else return new j(t)}async chat(t){return this.provider.chat(t)}async chatStream(t,e){let n={...t,options:{...t.options,stream:!0}};return this.provider.chatStream(n,e)}getConfig(){return{...this.config}}updateConfig(t){this.config={...this.config,...t},t.provider&&t.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};import{toRaw as we}from"vue";function V(o,t=new WeakMap){if(o==null||typeof o!="object")return o;try{let e=we(o);if(t.has(e))return t.get(e);if(Array.isArray(e)){let s=[];return t.set(e,s),s.push(...e.map(r=>V(r,t))),s}if(e instanceof Date||e instanceof RegExp||e instanceof ArrayBuffer||e instanceof Blob)return e;let n={};t.set(e,n);for(let s of Object.keys(e)){let r=Object.getOwnPropertyDescriptor(e,s);if(!r||r.get||r.set)continue;let a=e[s];typeof a!="function"&&typeof a!="symbol"&&(n[s]=V(a,t))}return n}catch(e){return console.warn("unwrapProxy error:",e),Array.isArray(o)?[]:{}}}var X=o=>o.map(t=>{let{renderContent:e,...n}=t;if(!Array.isArray(e))return t;let s=e.filter(a=>a.type==="collapsible-text"),r=e.filter(a=>a.type==="markdown"||a.type==="text");return s.length>0&&(n.reasoning_content=s.map(a=>a.content).join("")),r.length>0&&(n.content=r.map(a=>a.content).join("")),n});var $=o=>{let t=localStorage.getItem(o);return t?JSON.parse(t):[]},J=class{constructor(t="tiny-robot-ai-conversations"){this.storageKey=t}saveConversation(t){try{let e=$(this.storageKey),n=e.findIndex(s=>s.id===t.id);n!==-1?Object.assign(e[n],t):e.unshift({...t,messages:[]}),localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(e){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e)}}loadConversations(){try{return $(this.storageKey).map(e=>({id:e.id,title:e.title,createdAt:e.createdAt,updatedAt:e.updatedAt,metadata:e.metadata}))}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}saveMessages(t,e){try{let n=$(this.storageKey),s=n.findIndex(r=>r.id===t);s!==-1&&(n[s].messages=e),localStorage.setItem(this.storageKey,JSON.stringify(n))}catch(n){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n)}}loadMessages(t){try{let n=$(this.storageKey).find(r=>r.id===t);return X(n?.messages||[])}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}deleteConversation(t){let e=$(this.storageKey),n=e.findIndex(s=>s.id===t);n!==-1&&e.splice(n,1),localStorage.setItem(this.storageKey,JSON.stringify(e))}};import{openDB as Te}from"idb";var z=class{constructor(t="tiny-robot-ai-db",e=3){this.db=null;this.dbName=t,this.dbVersion=e}async getDB(){return this.db||(this.db=await Te(this.dbName,this.dbVersion,{upgrade(t){t.objectStoreNames.contains("conversations")||t.createObjectStore("conversations",{keyPath:"id"}).createIndex("by-updated","updatedAt"),t.objectStoreNames.contains("messages")||t.createObjectStore("messages",{keyPath:"conversationId"})}})),this.db}async loadConversations(){try{return(await(await this.getDB()).getAllFromIndex("conversations","by-updated")).reverse()}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}async loadMessages(t){try{let n=await(await this.getDB()).get("messages",t);return n?X(n.messages):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}async saveConversation(t){try{let e=await this.getDB(),n=V(t);await e.put("conversations",n)}catch(e){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e),e}}async saveMessages(t,e){try{let n=await this.getDB(),s=V(e);await n.put("messages",{conversationId:t,messages:s})}catch(n){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n),n}}async deleteConversation(t){try{let e=await this.getDB();await e.delete("conversations",t),await e.delete("messages",t)}catch(e){throw console.error("\u5220\u9664\u4F1A\u8BDD\u5931\u8D25:",e),e}}};function re(o={}){return new J(o.key||"tiny-robot-ai-conversations")}function Se(o={}){return new z(o.dbName||"tiny-robot-ai-db",o.dbVersion||1)}import{computed as je,ref as Ce,watch as Le}from"vue";import{computed as _e,reactive as De,ref as Y,watch as Ue}from"vue";var le=(o={})=>{let{fallbackRole:t="assistant",...e}=o;return{name:"fallbackRole",...e,onBeforeRequest(n){let{requestBody:s}=n;return s.messages=s.messages.map(r=>({...r,role:r.role||t})),e.onBeforeRequest?.(n)}}};var ce=(o={})=>{let{continueContent:t="Please continue with your previous answer.",...e}=o;return{name:"length",...e,onAfterRequest:async n=>{let{lastChoice:s,appendMessage:r,requestNext:a}=n;return s?.finish_reason==="length"&&(r({role:"user",content:t}),a()),e.onAfterRequest?.(n)}}};var ue=(o={})=>({name:"thinking",...o,onCompletionChunk(t){let{choice:e,currentMessage:n}=t,r=typeof(e?.message?.reasoning_content||e?.delta?.reasoning_content)=="string";return n.state?n.state.thinking=r:n.state={thinking:r},o.onCompletionChunk?.(t)},onTurnEnd(t){let e=t.currentTurn.slice(-1)[0];return e?.state&&(e.state.thinking=void 0),o.onTurnEnd?.(t)}});import{reactive as Ee}from"vue";var L=class extends Error{constructor(t){super(t),this.name="AbortError"}};function Pe(o){if(o.aborted)return{promise:Promise.reject(new L(String(o.reason??"Aborted"))),cleanup:()=>{}};let t=null;return{promise:new Promise((s,r)=>{t=()=>{r(new L(String(o.reason??"Aborted")))},o.addEventListener("abort",t,{once:!0})}),cleanup:()=>{t&&(o.removeEventListener("abort",t),t=null)}}}function pe(o,t){let{promise:e,cleanup:n}=Pe(t);return Promise.race([o,e]).finally(n)}function fe(o,t){let e={};for(let n in o)t.includes(n)&&(e[n]=o[n]);return e}function me(o,t){let e={};for(let n in o)t.includes(n)||(e[n]=o[n]);return e}async function*Q(o){if(de(o)){yield*o;return}let t=await o;if(de(t)){yield*t;return}yield t}function de(o){return o&&typeof o=="object"&&typeof o[Symbol.asyncIterator]=="function"}var ae=o=>typeof o=="object"&&o!==null,ge=o=>ae(o)&&typeof o.index=="number",W=(o,t)=>{for(let[e,n]of Object.entries(t)){let s=o[e];if(s)if(typeof s=="string"&&typeof n=="string")e==="type"&&s||(o[e]=s+n);else if(Array.isArray(s)&&Array.isArray(n))if(s.every(r=>ge(r))&&n.every(r=>ge(r))){let r=new Map(s.map(f=>[f.index,f])),a=new Map(n.map(f=>[f.index,f]));for(let[f,v]of a)if(r.has(f)){let R=r.get(f);r.set(f,W(R,v))}else r.set(f,v);let c=Math.max(...Array.from(r.keys()),-1)+1,d=c>s.length?Array.from({length:c}):s;for(let[f,v]of r)d[f]=v;o[e]=d}else o[e]=[...s,...n];else ae(s)&&ae(n)&&(o[e]=W(s,n));else o[e]=n}return o};function Oe(o,t){let e=[];for(let n=0;n<o.length;n++){let s=o[n];if(s.role==="assistant"&&s.tool_calls&&s.tool_calls.length>0){let r=new Set(s.tool_calls.map(d=>d.id)),a=new Set;for(let d=n+1;d<o.length;d++){let f=o[d];f.role==="tool"&&f.tool_call_id&&r.has(f.tool_call_id)&&a.add(f.tool_call_id)}let c=s.tool_calls.map(d=>d.id).filter(d=>!a.has(d));c.length>0&&e.push({insertAfterIndex:n,missingToolCallIds:c})}}for(let n=e.length-1;n>=0;n--){let{insertAfterIndex:s,missingToolCallIds:r}=e[n],a=r.map(c=>({role:"tool",tool_call_id:c,content:t}));o.splice(s+1,0,...a)}}var Ie="remove";function ke(o,t,e,n){let s=o.filter(a=>a[e]),r=new Set(s.flatMap(a=>a.tool_calls?.map(c=>c.id)??[]));if(t===Ie)for(let a=o.length-1;a>=0;a--){let c=o[a];(c[e]||c[n]||c.tool_call_id&&r.has(c.tool_call_id))&&o.splice(a,1)}else if(t===!0)for(let a of o)(a[e]||a.tool_call_id&&r.has(a.tool_call_id))&&(a[n]=!0,delete a[e])}var vt=o=>{let{getTools:t,beforeCallTools:e,callTool:n,onToolCallStart:s,onToolCallEnd:r,toolCallCancelledContent:a="Tool call cancelled.",toolCallFailedContent:c="Tool call failed.",autoFillMissingToolMessages:d=!1,excludeToolMessagesNextTurn:f=!1,...v}=o,R=Symbol("doNotSendNextTurn"),x=Symbol("doNotSend"),A=(...m)=>{let[h,{primaryMessage:T}]=m;T.state.toolCall[h.id].status="running",s?.(...m)},M=(...m)=>{let[h,{status:T,primaryMessage:O}]=m;O.state.toolCall[h.id].status=T,r?.(...m)};return{name:"tool",...v,onTurnStart:m=>{let{messages:h}=m;return d&&Oe(h,a),f&&ke(h,f,R,x),v.onTurnStart?.(m)},onBeforeRequest:async m=>{let{messages:h,requestBody:T}=m;f===!0&&(T.messages=h.filter(E=>!E[x]));let O=await t?.();return O&&O.length>0&&(T.tools=O),v.onBeforeRequest?.(m)},onAfterRequest:async m=>{let{currentMessage:h,lastChoice:T,appendMessage:O,abortSignal:E,setRequestState:i,requestNext:l}=m;if(T?.finish_reason!=="tool_calls"||!h.tool_calls?.length)return;f&&(h[R]=!0),i("processing","calling-tools"),await e?.(h.tool_calls,{...m,currentMessage:h});let g=h.tool_calls.map(async y=>{let S=Math.floor(Date.now()/1e3),w=Ee({role:"tool",tool_call_id:y.id,content:"",metadata:{createdAt:S,updatedAt:S}});O(w);let U={...m,primaryMessage:h,toolMessage:w};A(y,U);try{let k=n(y,U),B=Q(k);for await(let u of B){if(typeof u=="string")w.content+=u;else{let p={};try{p=JSON.parse(w.content||"{}")}catch(b){console.warn(b)}w.content=JSON.stringify(W(p,u))}w.metadata.updatedAt=Math.floor(Date.now()/1e3)}M(y,{...U,status:"success"})}catch(k){let B=k instanceof Error?k:new Error(String(k));if(E.aborted){M(y,{...U,status:"cancelled",error:B});return}console.error(k),w.content.length===0&&(w.content=c),M(y,{...U,status:"failed",error:B})}});return await Promise.all(g),l(),v.onAfterRequest?.(m)},onCompletionChunk:m=>{var T,O,E;let{currentMessage:h}=m;if(Array.isArray(h.tool_calls))for(let i of h.tool_calls)h.state?.toolCall?.[i.id]?.status||(h.state??(h.state={}),(T=h.state).toolCall??(T.toolCall={}),(O=h.state.toolCall)[E=i.id]??(O[E]={}));return v.onCompletionChunk?.(m)}}};var qe=o=>{let t=[];for(let e of o){if(e.name){let n=t.findIndex(s=>s.name===e.name);n!==-1&&t.splice(n,1)}t.push(e)}return t},ie=o=>{let{initialMessages:t=[],requestMessageFields:e=[],requestMessageFieldsExclude:n=["state","metadata","loading"],plugins:s=[],onCompletionChunk:r}=o,a=Y("idle"),c=Y(void 0),d=Y(t),f=Y(o.responseProvider),v=null,R=[],x={},A=[le(),ue(),ce()],M=qe(A.concat(s)),m=_e(()=>a.value==="processing"),h=async u=>{if(!u||!u.trim()){console.warn("Cannot send empty message");return}if(m.value){console.warn("Cannot send message while processing is in progress");return}let p=Math.floor(Date.now()/1e3);d.value.push({role:"user",content:u.trim(),metadata:{createdAt:p,updatedAt:p}}),R.push(d.value[d.value.length-1]),await w()},T=async(...u)=>{if(m.value){console.warn("Cannot send message while processing is in progress");return}d.value.push(...u),R.push(...u),await w()},O=u=>{let p=u;return e.length&&(p=p.map(b=>fe(b,e))),n.length&&(p=p.map(b=>me(b,n))),p},E=(u,p)=>{a.value=u,u==="processing"?c.value=p||"requesting":c.value=void 0},i=u=>{Object.assign(x,u)},l=u=>({messages:d.value,currentTurn:R,requestState:a.value,processingState:c.value,plugins:M,abortSignal:u,setRequestState:E,customContext:x,setCustomContext:i}),g=(u,p)=>typeof u.disabled=="function"?u.disabled(p):!!u.disabled,y=u=>!u||Object.keys(u).length===0?!1:Object.values(u).some(p=>!!p),S=async(u,p)=>{E("processing","requesting");let b=new Proxy({messages:O(d.value)},{set(D,P,N){return P==="messages"?(D.messages=O(N),!0):(D[P]=N,!0)}}),I=l(p);for(let D of M.filter(P=>!g(P,I)))await D.onBeforeRequest?.({...I,requestBody:b});let C=De({role:"",content:"",loading:!0});B(C);let _,Z=u(b,p),q=Q(Z);for await(let D of q){E("processing","completing"),C.loading&&(C.loading=void 0);let P=D.choices?.find(K=>K.index===0);if(P){_=P;let K=()=>{C.metadata||(C.metadata={});let{created:H,...ve}=D;C.metadata.createdAt=H,C.metadata.updatedAt=Math.floor(Date.now()/1e3),Object.assign(C.metadata,ve);let ee=y(P.delta)?P.delta:P.message;ee||(ee=P.delta||P.message||{}),W(C,ee)};if(r){let H=l(p);r({...H,chunk:D,choice:P,currentMessage:C},K)}else K()}let N=l(p);for(let K of M.filter(H=>!g(H,N)))K.onCompletionChunk?.({...N,abortSignal:p,chunk:D,choice:P,currentMessage:C})}await k(C,u,p,_)},w=async()=>{let u=new AbortController;v=u,x={};try{E("processing","requesting");let p=l(u.signal);for(let C of M.filter(_=>!g(_,p)))await C.onTurnStart?.(p);let b=f.value;try{await S(b,u.signal),E("completed")}catch(C){if(u.signal.aborted||C instanceof L||C instanceof Error&&C.name==="AbortError")E("aborted");else throw C}let I=l(u.signal);for(let C of M.filter(_=>!g(_,I)))await C.onTurnEnd?.(I)}catch(p){E("error");let b=!1,I=l(u.signal);for(let C of M.filter(_=>!g(_,I)))C.onError&&(b=!0,C.onError({...I,error:p}));if(!b)throw p}finally{let p=l(u.signal);for(let b of M.filter(I=>!g(I,p)))try{b.onFinally?.(p)}catch(I){console.error(`Error in onFinally hook for plugin ${b.name||"Anonymous"}:`,I)}v=null,R.slice(-1)[0]&&(R.slice(-1)[0].loading=void 0),R=[]}},U=async()=>{v?.abort(),m.value&&await new Promise(u=>{let p=Ue(m,b=>{b||(p(),u())},{immediate:!0})})},k=async(u,p,b,I)=>{let C=!1,_=l(b),Z=M.filter(q=>!g(q,_)).map(q=>{if(!q.onAfterRequest)return null;let D=N=>{B(N)},P=()=>{C=!0};return q.onAfterRequest({..._,currentMessage:u,lastChoice:I,appendMessage:D,requestNext:P})}).filter(q=>q!==null);await pe(Promise.all(Z),b),C&&await S(p,b)},B=u=>{let p=Array.isArray(u)?u:[u];d.value.push(...p),R.push(...p)};return{requestState:a,processingState:c,messages:d,responseProvider:f,isProcessing:m,sendMessage:h,send:T,abortRequest:U}};import{isRef as Be,toValue as Ne}from"vue";function ye(o,t=200,e=!1,n=!0,s=!1){return Fe(Ke(t,e,n,s),o)}function Fe(o,t){function e(...n){return new Promise((s,r)=>{Promise.resolve(o(()=>t.apply(this,n),{fn:t,thisArg:this,args:n})).then(s).catch(r)})}return e}var he=()=>{};function Ke(...o){let t=0,e,n=!0,s=he,r,a,c,d,f;!Be(o[0])&&typeof o[0]=="object"?{delay:a,trailing:c=!0,leading:d=!0,rejectOnCancel:f=!1}=o[0]:[a,c=!0,d=!0,f=!1]=o;let v=()=>{e&&(clearTimeout(e),e=void 0,s(),s=he)};return x=>{let A=Ne(a),M=Date.now()-t,m=()=>r=x();return v(),A<=0?(t=Date.now(),m()):(M>A?(t=Date.now(),(d||!n)&&m()):c&&(r=new Promise((h,T)=>{s=f?T:h,e=setTimeout(()=>{t=Date.now(),n=!0,h(m()),v()},Math.max(0,A-M))})),!d&&!e&&(e=setTimeout(()=>n=!0,A)),n=!1,r)}}var _t=o=>{let t=o.storage||re(),e=Ce([]),n=new Map,s=new Map,r=Ce(null),a=je(()=>{let i=r.value;if(!i)return null;let l=e.value.find(y=>y.id===i);if(!l)return null;let g=n.get(i);return g?{...l,engine:g}:null}),c=i=>{if(!t?.saveMessages)return;let l=i||r.value,g=e.value.find(S=>S.id===l);if(!g)return;g.updatedAt=Date.now(),t?.saveConversation?.(g);let y=n.get(g.id);y&&t.saveMessages(g.id,y.messages.value)},d=(i,l)=>{if(!o.autoSaveMessages||!t?.saveMessages)return;let g=s.get(i);g&&g();let y=o.autoSaveThrottle??1e3,S=ye(()=>{c(i)},y,!0,!0),w=Le(l.messages,S,{deep:!0});s.set(i,w)},f=i=>{let l=s.get(i);l&&(l(),s.delete(i))};t?.loadConversations&&Promise.resolve(t.loadConversations()).then(i=>{if(!i?.length)return[];if(e.value.length===0)return e.value=i,e.value;let l=new Map(e.value.map(g=>[g.id,g]));return i.forEach(g=>{l.has(g.id)||l.set(g.id,g)}),e.value=Array.from(l.values()),e.value}).then(i=>{o.onLoad?.(i)}).catch(i=>{console.error("[useConversation] loadConversations failed:",i)});let v=async(i,l)=>{let g=n.get(i);if(g)return g;let y=l?.initialMessages??o.useMessageOptions.initialMessages??[];if(t?.loadMessages)try{y=await t.loadMessages(i)}catch(w){console.error("[useConversation] loadMessages failed:",w)}let S=ie({...o.useMessageOptions,...l,initialMessages:y});return n.set(i,S),d(i,S),S};function R(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}let x=i=>{let{id:l=R(),title:g,metadata:y,useMessageOptions:S}=i||{},w=Date.now(),U={id:l,title:g,createdAt:w,updatedAt:w,metadata:y};e.value.unshift(U);let k=ie({...o.useMessageOptions,...S});return n.set(l,k),d(l,k),t?.saveConversation?.(U),t?.saveMessages?.(l,k.messages.value),r.value=l,a.value},A=i=>{let{excludeId:l}=i||{};n.forEach((g,y)=>{if(l&&y===l)return;g.isProcessing?.value||(f(y),n.delete(y))})};return{conversations:e,activeConversationId:r,activeConversation:a,createConversation:x,switchConversation:async i=>i?r.value===i?a.value:e.value.find(g=>g.id===i)?(await v(i),A({excludeId:i}),r.value=i,a.value):null:null,deleteConversation:async i=>{let l=e.value.findIndex(y=>y.id===i);if(l===-1)return;await n.get(i)?.abortRequest(),f(i),n.delete(i),e.value.splice(l,1),t?.deleteConversation?.(i),r.value===i&&(r.value=null,A())},clear:()=>{e.value.map(l=>l.id).forEach(l=>{t?.deleteConversation?.(l)}),n.forEach(l=>{l.abortRequest()}),s.forEach(l=>{l()}),e.value=[],n.clear(),s.clear(),r.value=null},updateConversationTitle:(i,l)=>{let g=e.value.find(y=>y.id===i);g&&(g.title=l,g.updatedAt=Date.now(),t?.saveConversation?.(g))},saveMessages:c,sendMessage:i=>{a.value?.engine.sendMessage(i)},abortActiveRequest:async()=>{await a.value?.engine.abortRequest()}}};export{se as AIClient,G as BaseModelProvider,Ie as EXCLUDE_MODE_REMOVE,Me as ErrorType,z as IndexedDBStrategy,J as LocalStorageStrategy,j as OpenAIProvider,be as StreamEventType,xe as extractTextFromResponse,le as fallbackRolePlugin,Re as formatMessages,ne as handleSSEStream,Se as indexedDBStorageStrategyFactory,ce as lengthPlugin,re as localStorageStrategyFactory,Ae as sseStreamToGenerator,ue as thinkingPlugin,vt as toolPlugin,_t as useConversation,ie as useMessage};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opentiny/tiny-robot-kit",
|
|
3
|
-
"version": "0.4.0
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"idb": "^8.0.3"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "558095a424930d99e079e6e1cf4fe8929d48c7b2"
|
|
33
33
|
}
|