@opentiny/tiny-robot-kit 0.2.0-alpha.6 → 0.2.0-alpha.8

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/dist/index.d.mts CHANGED
@@ -1,5 +1,43 @@
1
1
  import { Ref, Reactive } from 'vue';
2
2
 
3
+ /**
4
+ * 模型Provider基类
5
+ */
6
+ declare abstract class BaseModelProvider {
7
+ protected config: AIModelConfig;
8
+ /**
9
+ * @param config AI模型配置
10
+ */
11
+ constructor(config: AIModelConfig);
12
+ /**
13
+ * 发送聊天请求并获取响应
14
+ * @param request 聊天请求参数
15
+ * @returns 聊天响应
16
+ */
17
+ abstract chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
18
+ /**
19
+ * 发送流式聊天请求并通过处理器处理响应
20
+ * @param request 聊天请求参数
21
+ * @param handler 流式响应处理器
22
+ */
23
+ abstract chatStream(request: ChatCompletionRequest, handler: StreamHandler): Promise<void>;
24
+ /**
25
+ * 更新配置
26
+ * @param config 新的AI模型配置
27
+ */
28
+ updateConfig(config: AIModelConfig): void;
29
+ /**
30
+ * 获取当前配置
31
+ * @returns AI模型配置
32
+ */
33
+ getConfig(): AIModelConfig;
34
+ /**
35
+ * 验证请求参数
36
+ * @param request 聊天请求参数
37
+ */
38
+ protected validateRequest(request: ChatCompletionRequest): void;
39
+ }
40
+
3
41
  /**
4
42
  * 消息角色类型
5
43
  */
@@ -103,6 +141,7 @@ type AIProvider = 'openai' | 'deepseek' | 'custom';
103
141
  */
104
142
  interface AIModelConfig {
105
143
  provider: AIProvider;
144
+ providerImplementation?: BaseModelProvider;
106
145
  apiKey?: string;
107
146
  apiUrl?: string;
108
147
  apiVersion?: string;
@@ -193,44 +232,6 @@ declare class AIClient {
193
232
  updateConfig(config: Partial<AIModelConfig>): void;
194
233
  }
195
234
 
196
- /**
197
- * 模型Provider基类
198
- */
199
- declare abstract class BaseModelProvider {
200
- protected config: AIModelConfig;
201
- /**
202
- * @param config AI模型配置
203
- */
204
- constructor(config: AIModelConfig);
205
- /**
206
- * 发送聊天请求并获取响应
207
- * @param request 聊天请求参数
208
- * @returns 聊天响应
209
- */
210
- abstract chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
211
- /**
212
- * 发送流式聊天请求并通过处理器处理响应
213
- * @param request 聊天请求参数
214
- * @param handler 流式响应处理器
215
- */
216
- abstract chatStream(request: ChatCompletionRequest, handler: StreamHandler): Promise<void>;
217
- /**
218
- * 更新配置
219
- * @param config 新的AI模型配置
220
- */
221
- updateConfig(config: AIModelConfig): void;
222
- /**
223
- * 获取当前配置
224
- * @returns AI模型配置
225
- */
226
- getConfig(): AIModelConfig;
227
- /**
228
- * 验证请求参数
229
- * @param request 聊天请求参数
230
- */
231
- protected validateRequest(request: ChatCompletionRequest): void;
232
- }
233
-
234
235
  /**
235
236
  * OpenAI提供商
236
237
  * 用于与OpenAI API进行交互
@@ -268,6 +269,12 @@ declare class OpenAIProvider extends BaseModelProvider {
268
269
  * 提供一些实用的辅助函数
269
270
  */
270
271
 
272
+ /**
273
+ * 处理SSE流式响应
274
+ * @param response fetch响应对象
275
+ * @param handler 流处理器
276
+ */
277
+ declare function handleSSEStream(response: Response, handler: StreamHandler, signal?: AbortSignal): Promise<void>;
271
278
  /**
272
279
  * 格式化消息
273
280
  * 将各种格式的消息转换为标准的ChatMessage格式
@@ -450,4 +457,4 @@ interface UseConversationReturn {
450
457
  */
451
458
  declare function useConversation(options: UseConversationOptions): UseConversationReturn;
452
459
 
453
- export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, BaseModelProvider, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Conversation, type ConversationState, type ConversationStorageStrategy, ErrorType, FinalStatus, GeneratingStatus, LocalStorageStrategy, type MessageRole, type MessageState, OpenAIProvider, STATUS, StreamEventType, type StreamHandler, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessageReturn, extractTextFromResponse, formatMessages, useConversation, useMessage };
460
+ export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, BaseModelProvider, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Conversation, type ConversationState, type ConversationStorageStrategy, ErrorType, FinalStatus, GeneratingStatus, LocalStorageStrategy, type MessageRole, type MessageState, OpenAIProvider, STATUS, StreamEventType, type StreamHandler, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessageReturn, extractTextFromResponse, formatMessages, handleSSEStream, useConversation, useMessage };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,43 @@
1
1
  import { Ref, Reactive } from 'vue';
2
2
 
3
+ /**
4
+ * 模型Provider基类
5
+ */
6
+ declare abstract class BaseModelProvider {
7
+ protected config: AIModelConfig;
8
+ /**
9
+ * @param config AI模型配置
10
+ */
11
+ constructor(config: AIModelConfig);
12
+ /**
13
+ * 发送聊天请求并获取响应
14
+ * @param request 聊天请求参数
15
+ * @returns 聊天响应
16
+ */
17
+ abstract chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
18
+ /**
19
+ * 发送流式聊天请求并通过处理器处理响应
20
+ * @param request 聊天请求参数
21
+ * @param handler 流式响应处理器
22
+ */
23
+ abstract chatStream(request: ChatCompletionRequest, handler: StreamHandler): Promise<void>;
24
+ /**
25
+ * 更新配置
26
+ * @param config 新的AI模型配置
27
+ */
28
+ updateConfig(config: AIModelConfig): void;
29
+ /**
30
+ * 获取当前配置
31
+ * @returns AI模型配置
32
+ */
33
+ getConfig(): AIModelConfig;
34
+ /**
35
+ * 验证请求参数
36
+ * @param request 聊天请求参数
37
+ */
38
+ protected validateRequest(request: ChatCompletionRequest): void;
39
+ }
40
+
3
41
  /**
4
42
  * 消息角色类型
5
43
  */
@@ -103,6 +141,7 @@ type AIProvider = 'openai' | 'deepseek' | 'custom';
103
141
  */
104
142
  interface AIModelConfig {
105
143
  provider: AIProvider;
144
+ providerImplementation?: BaseModelProvider;
106
145
  apiKey?: string;
107
146
  apiUrl?: string;
108
147
  apiVersion?: string;
@@ -193,44 +232,6 @@ declare class AIClient {
193
232
  updateConfig(config: Partial<AIModelConfig>): void;
194
233
  }
195
234
 
196
- /**
197
- * 模型Provider基类
198
- */
199
- declare abstract class BaseModelProvider {
200
- protected config: AIModelConfig;
201
- /**
202
- * @param config AI模型配置
203
- */
204
- constructor(config: AIModelConfig);
205
- /**
206
- * 发送聊天请求并获取响应
207
- * @param request 聊天请求参数
208
- * @returns 聊天响应
209
- */
210
- abstract chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
211
- /**
212
- * 发送流式聊天请求并通过处理器处理响应
213
- * @param request 聊天请求参数
214
- * @param handler 流式响应处理器
215
- */
216
- abstract chatStream(request: ChatCompletionRequest, handler: StreamHandler): Promise<void>;
217
- /**
218
- * 更新配置
219
- * @param config 新的AI模型配置
220
- */
221
- updateConfig(config: AIModelConfig): void;
222
- /**
223
- * 获取当前配置
224
- * @returns AI模型配置
225
- */
226
- getConfig(): AIModelConfig;
227
- /**
228
- * 验证请求参数
229
- * @param request 聊天请求参数
230
- */
231
- protected validateRequest(request: ChatCompletionRequest): void;
232
- }
233
-
234
235
  /**
235
236
  * OpenAI提供商
236
237
  * 用于与OpenAI API进行交互
@@ -268,6 +269,12 @@ declare class OpenAIProvider extends BaseModelProvider {
268
269
  * 提供一些实用的辅助函数
269
270
  */
270
271
 
272
+ /**
273
+ * 处理SSE流式响应
274
+ * @param response fetch响应对象
275
+ * @param handler 流处理器
276
+ */
277
+ declare function handleSSEStream(response: Response, handler: StreamHandler, signal?: AbortSignal): Promise<void>;
271
278
  /**
272
279
  * 格式化消息
273
280
  * 将各种格式的消息转换为标准的ChatMessage格式
@@ -450,4 +457,4 @@ interface UseConversationReturn {
450
457
  */
451
458
  declare function useConversation(options: UseConversationOptions): UseConversationReturn;
452
459
 
453
- export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, BaseModelProvider, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Conversation, type ConversationState, type ConversationStorageStrategy, ErrorType, FinalStatus, GeneratingStatus, LocalStorageStrategy, type MessageRole, type MessageState, OpenAIProvider, STATUS, StreamEventType, type StreamHandler, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessageReturn, extractTextFromResponse, formatMessages, useConversation, useMessage };
460
+ export { type AIAdapterError, AIClient, type AIModelConfig, type AIProvider, BaseModelProvider, type ChatCompletionOptions, type ChatCompletionRequest, type ChatCompletionResponse, type ChatCompletionResponseChoice, type ChatCompletionResponseMessage, type ChatCompletionResponseUsage, type ChatCompletionStreamResponse, type ChatCompletionStreamResponseChoice, type ChatCompletionStreamResponseDelta, type ChatHistory, type ChatMessage, type Conversation, type ConversationState, type ConversationStorageStrategy, ErrorType, FinalStatus, GeneratingStatus, LocalStorageStrategy, type MessageRole, type MessageState, OpenAIProvider, STATUS, StreamEventType, type StreamHandler, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessageReturn, extractTextFromResponse, formatMessages, handleSSEStream, useConversation, useMessage };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";var b=Object.defineProperty;var H=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var j=Object.prototype.hasOwnProperty;var $=(s,e)=>{for(var t in e)b(s,t,{get:e[t],enumerable:!0})},L=(s,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let d of B(e))!j.call(s,d)&&d!==t&&b(s,d,{get:()=>e[d],enumerable:!(a=H(e,d))||a.enumerable});return s};var F=s=>L(b({},"__esModule",{value:!0}),s);var z={};$(z,{AIClient:()=>y,BaseModelProvider:()=>S,ErrorType:()=>P,FinalStatus:()=>G,GeneratingStatus:()=>q,LocalStorageStrategy:()=>A,OpenAIProvider:()=>R,STATUS:()=>K,StreamEventType:()=>U,extractTextFromResponse:()=>k,formatMessages:()=>_,useConversation:()=>J,useMessage:()=>O});module.exports=F(z);var S=class{constructor(e){this.config=e}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}validateRequest(e){if(!e.messages||!Array.isArray(e.messages)||e.messages.length===0)throw new Error("\u8BF7\u6C42\u5FC5\u987B\u5305\u542B\u81F3\u5C11\u4E00\u6761\u6D88\u606F");for(let t of e.messages)if(!t.role||!t.content)throw new Error("\u6BCF\u6761\u6D88\u606F\u5FC5\u987B\u5305\u542B\u89D2\u8272\u548C\u5185\u5BB9")}};var P=(p=>(p.NETWORK_ERROR="network_error",p.AUTHENTICATION_ERROR="authentication_error",p.RATE_LIMIT_ERROR="rate_limit_error",p.SERVER_ERROR="server_error",p.MODEL_ERROR="model_error",p.TIMEOUT_ERROR="timeout_error",p.UNKNOWN_ERROR="unknown_error",p))(P||{}),U=(a=>(a.DATA="data",a.ERROR="error",a.DONE="done",a))(U||{});function v(s){return{type:s.type||"unknown_error",message:s.message||"\u672A\u77E5\u9519\u8BEF",statusCode:s.statusCode,originalError:s.originalError}}function x(s){if(!s.response)return v({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:s});if(s.response){let{status:e,data:t}=s.response;return e===401||e===403?v({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:e,originalError:s}):e===429?v({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:s}):e>=500?v({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:s}):v({type:"unknown_error",message:t?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:s})}return s.code==="ECONNABORTED"?v({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:s}):v({type:"unknown_error",message:s.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:s})}async function D(s,e,t){let a=s.body?.getReader();if(!a)throw new Error("Response body is null");let d=new TextDecoder,i="";t&&t.addEventListener("abort",()=>{a.cancel().catch(o=>console.error("Error cancelling reader:",o))},{once:!0});try{for(;;){if(t?.aborted){await a.cancel();break}let{done:o,value:p}=await a.read();if(o)break;let u=d.decode(p,{stream:!0});i+=u;let c=i.split(`
1
+ "use strict";var x=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var j=Object.prototype.hasOwnProperty;var $=(s,e)=>{for(var t in e)x(s,t,{get:e[t],enumerable:!0})},L=(s,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let d of H(e))!j.call(s,d)&&d!==t&&x(s,d,{get:()=>e[d],enumerable:!(a=B(e,d))||a.enumerable});return s};var F=s=>L(x({},"__esModule",{value:!0}),s);var z={};$(z,{AIClient:()=>A,BaseModelProvider:()=>S,ErrorType:()=>U,FinalStatus:()=>G,GeneratingStatus:()=>q,LocalStorageStrategy:()=>E,OpenAIProvider:()=>R,STATUS:()=>K,StreamEventType:()=>D,extractTextFromResponse:()=>k,formatMessages:()=>_,handleSSEStream:()=>y,useConversation:()=>J,useMessage:()=>w});module.exports=F(z);var S=class{constructor(e){this.config=e}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}validateRequest(e){if(!e.messages||!Array.isArray(e.messages)||e.messages.length===0)throw new Error("\u8BF7\u6C42\u5FC5\u987B\u5305\u542B\u81F3\u5C11\u4E00\u6761\u6D88\u606F");for(let t of e.messages)if(!t.role||!t.content)throw new Error("\u6BCF\u6761\u6D88\u606F\u5FC5\u987B\u5305\u542B\u89D2\u8272\u548C\u5185\u5BB9")}};var U=(p=>(p.NETWORK_ERROR="network_error",p.AUTHENTICATION_ERROR="authentication_error",p.RATE_LIMIT_ERROR="rate_limit_error",p.SERVER_ERROR="server_error",p.MODEL_ERROR="model_error",p.TIMEOUT_ERROR="timeout_error",p.UNKNOWN_ERROR="unknown_error",p))(U||{}),D=(a=>(a.DATA="data",a.ERROR="error",a.DONE="done",a))(D||{});function v(s){return{type:s.type||"unknown_error",message:s.message||"\u672A\u77E5\u9519\u8BEF",statusCode:s.statusCode,originalError:s.originalError}}function O(s){if(!s.response)return v({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:s});if(s.response){let{status:e,data:t}=s.response;return e===401||e===403?v({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:e,originalError:s}):e===429?v({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:s}):e>=500?v({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:s}):v({type:"unknown_error",message:t?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:s})}return s.code==="ECONNABORTED"?v({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:s}):v({type:"unknown_error",message:s.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:s})}async function y(s,e,t){let a=s.body?.getReader();if(!a)throw new Error("Response body is null");let d=new TextDecoder,i="";t&&t.addEventListener("abort",()=>{a.cancel().catch(o=>console.error("Error cancelling reader:",o))},{once:!0});try{for(;;){if(t?.aborted){await a.cancel();break}let{done:o,value:p}=await a.read();if(o)break;let u=d.decode(p,{stream:!0});i+=u;let c=i.split(`
2
2
 
3
- `);i=c.pop()||"";for(let h of c)if(h.trim()!==""){if(h.trim()==="data: [DONE]"){e.onDone();continue}try{let m=h.match(/^data: (.+)$/m);if(!m)continue;let M=JSON.parse(m[1]);e.onData(M)}catch(m){console.error("Error parsing SSE message:",m)}}}(i.trim()==="data: [DONE]"||t?.aborted)&&e.onDone()}catch(o){if(t?.aborted)return;throw o}}function _(s){return s.map(e=>typeof e=="object"&&"role"in e&&"content"in e?{role:e.role,content:String(e.content),...e.name?{name:e.name}:{}}:typeof e=="string"?{role:"user",content:e}:{role:"user",content:String(e)})}function k(s){return!s.choices||!s.choices.length?"":s.choices[0].message?.content||""}var R=class extends S{constructor(t){super(t);this.defaultModel="gpt-3.5-turbo";this.baseURL=t.apiUrl||"https://api.openai.com/v1",this.apiKey=t.apiKey||"",t.defaultModel&&(this.defaultModel=t.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(t){try{this.validateRequest(t);let a={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...t.options,stream:!1},d={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)};this.apiKey&&Object.assign(d.headers,{Authorization:`Bearer ${this.apiKey}`});let i=await fetch(`${this.baseURL}/chat/completions`,d);if(!i.ok){let o=await i.text();throw new Error(`HTTP error! status: ${i.status}, details: ${o}`)}return await i.json()}catch(a){throw x(a)}}async chatStream(t,a){let{signal:d,...i}=t.options||{};try{this.validateRequest(t);let o={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...i,stream:!0},p={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(o),signal:d};this.apiKey&&Object.assign(p.headers,{Authorization:`Bearer ${this.apiKey}`});let u=await fetch(`${this.baseURL}/chat/completions`,p);if(!u.ok){let c=await u.text();throw new Error(`HTTP error! status: ${u.status}, details: ${c}`)}await D(u,a,d)}catch(o){if(d?.aborted)return;a.onError(x(o))}}updateConfig(t){super.updateConfig(t),t.apiUrl&&(this.baseURL=t.apiUrl),t.apiKey&&(this.apiKey=t.apiKey),t.defaultModel&&(this.defaultModel=t.defaultModel)}};var y=class{constructor(e){this.config=e,this.provider=this.createProvider(e)}createProvider(e){if(e.provider==="custom"&&"providerImplementation"in e)return e.providerImplementation;switch(e.provider){case"deepseek":let t={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new R({...t,...e});case"openai":default:return new R(e)}}async chat(e){return this.provider.chat(e)}async chatStream(e,t){let a={...e,options:{...e.options,stream:!0}};return this.provider.chatStream(a,t)}getConfig(){return{...this.config}}updateConfig(e){this.config={...this.config,...e},e.provider&&e.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};var C=require("vue"),K=(o=>(o.INIT="init",o.PROCESSING="processing",o.STREAMING="streaming",o.FINISHED="finished",o.ABORTED="aborted",o.ERROR="error",o))(K||{}),q=["processing","streaming"],G=["finished","aborted","error"];function O(s){let{client:e,useStreamByDefault:t=!0,errorMessage:a="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:d=[]}=s,i=(0,C.ref)([...d]),o=(0,C.ref)(""),p=(0,C.ref)(t),u=null,c=(0,C.reactive)({status:"init",errorMsg:null}),h=async r=>{let g={role:"assistant",content:(await e.chat({messages:(0,C.toRaw)(i.value),options:{stream:!1,signal:r.signal}})).choices[0].message.content};i.value.push(g)},m=async r=>{await e.chatStream({messages:(0,C.toRaw)(i.value),options:{stream:!0,signal:r.signal}},{onData:n=>{c.status="streaming",i.value[i.value.length-1].role==="user"&&i.value.push({role:"assistant",content:""});let g=n.choices?.[0];g&&g.delta.content&&(i.value[i.value.length-1].content+=g.delta.content)},onError:n=>{c.status="error",c.errorMsg=a,console.error("Stream request error:",n)},onDone:()=>{c.status="finished"}})},M=async()=>{c.status="processing",c.errorMsg=null,u=new AbortController;try{p.value?await m(u):await h(u),c.status="finished"}catch(r){c.errorMsg=a,c.status="error",console.error("Send message error:",r)}finally{u=null}};return{messages:i,messageState:c,inputMessage:o,useStream:p,sendMessage:async(r=o.value,n=!0)=>{if(!r?.trim()||q.includes(c.status))return;let g={role:"user",content:r};i.value.push(g),n&&(o.value=""),await M()},clearMessages:()=>{i.value=[],c.errorMsg=null},addMessage:r=>{i.value.push(r)},abortRequest:()=>{u&&(u.abort(),u=null,c.status="aborted")},retryRequest:async r=>{r===0||!i.value[r]||i.value[r].role==="user"||(i.value.splice(r),await M())}}}var E=require("vue");var A=class{constructor(e="tiny-robot-ai-conversations"){this.storageKey=e}saveConversations(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(t){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",t)}}loadConversations(){try{let e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",e),[]}}};function W(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function J(s){let{client:e,storage:t=new A,autoSave:a=!0,useStreamByDefault:d=!0,errorMessage:i="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=s,o=(0,E.reactive)({conversations:[],currentId:null,loading:!1}),p=O({client:e,useStreamByDefault:d,errorMessage:i,initialMessages:[]});(0,E.watch)(()=>p.messages.value,l=>{if(o.currentId&&l.length>0){let r=o.conversations.findIndex(n=>n.id===o.currentId);r!==-1&&(o.conversations[r].messages=[...l],o.conversations[r].updatedAt=Date.now(),a&&f())}},{deep:!0});let u=(l="\u65B0\u4F1A\u8BDD",r={})=>{let n=W(),g={id:n,title:l,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:r};return o.conversations.unshift(g),c(n),a&&f(),n},c=l=>{let r=o.conversations.find(n=>n.id===l);r&&(o.currentId=l,p.clearMessages(),r.messages.length>0&&r.messages.forEach(n=>p.addMessage(n)))},h=l=>{let r=o.conversations.findIndex(n=>n.id===l);r!==-1&&(o.conversations.splice(r,1),o.currentId===l&&(o.conversations.length>0?c(o.conversations[0].id):(o.currentId=null,p.clearMessages())),a&&f())},m=(l,r)=>{let n=o.conversations.find(g=>g.id===l);n&&(n.title=r,n.updatedAt=Date.now(),a&&f())},M=(l,r)=>{let n=o.conversations.find(g=>g.id===l);n&&(n.metadata={...n.metadata,...r},n.updatedAt=Date.now(),a&&f())},f=async()=>{try{await t.saveConversations(o.conversations)}catch(l){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",l)}},I=async()=>{o.loading=!0;try{let l=await t.loadConversations();o.conversations=l,l.length>0&&!o.currentId&&c(l[0].id)}catch(l){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",l)}finally{o.loading=!1}},w=async l=>{let r=o.conversations.find(n=>n.id===l);if(!r||r.messages.length<2)return r?.title||"\u65B0\u4F1A\u8BDD";try{let n={role:"system",content:"\u8BF7\u6839\u636E\u4EE5\u4E0B\u5BF9\u8BDD\u5185\u5BB9\uFF0C\u751F\u6210\u4E00\u4E2A\u7B80\u77ED\u7684\u6807\u9898\uFF08\u4E0D\u8D85\u8FC720\u4E2A\u5B57\u7B26\uFF09\u3002\u53EA\u9700\u8981\u8FD4\u56DE\u6807\u9898\u6587\u672C\uFF0C\u4E0D\u9700\u8981\u4EFB\u4F55\u89E3\u91CA\u6216\u989D\u5916\u5185\u5BB9\u3002"},g=r.messages.slice(0,Math.min(4,r.messages.length)),N=(await e.chat({messages:[n,...g],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return m(l,N),N}catch(n){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",n),r.title}},T=()=>o.currentId&&o.conversations.find(l=>l.id===o.currentId)||null;return I(),{state:o,messageManager:p,createConversation:u,switchConversation:c,deleteConversation:h,updateTitle:m,updateMetadata:M,saveConversations:f,loadConversations:I,generateTitle:w,getCurrentConversation:T}}0&&(module.exports={AIClient,BaseModelProvider,ErrorType,FinalStatus,GeneratingStatus,LocalStorageStrategy,OpenAIProvider,STATUS,StreamEventType,extractTextFromResponse,formatMessages,useConversation,useMessage});
3
+ `);i=c.pop()||"";for(let h of c)if(h.trim()!==""){if(h.trim()==="data: [DONE]"){e.onDone();continue}try{let m=h.match(/^data: (.+)$/m);if(!m)continue;let M=JSON.parse(m[1]);e.onData(M)}catch(m){console.error("Error parsing SSE message:",m)}}}(i.trim()==="data: [DONE]"||t?.aborted)&&e.onDone()}catch(o){if(t?.aborted)return;throw o}}function _(s){return s.map(e=>typeof e=="object"&&"role"in e&&"content"in e?{role:e.role,content:String(e.content),...e.name?{name:e.name}:{}}:typeof e=="string"?{role:"user",content:e}:{role:"user",content:String(e)})}function k(s){return!s.choices||!s.choices.length?"":s.choices[0].message?.content||""}var R=class extends S{constructor(t){super(t);this.defaultModel="gpt-3.5-turbo";this.baseURL=t.apiUrl||"https://api.openai.com/v1",this.apiKey=t.apiKey||"",t.defaultModel&&(this.defaultModel=t.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(t){try{this.validateRequest(t);let a={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...t.options,stream:!1},d={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)};this.apiKey&&Object.assign(d.headers,{Authorization:`Bearer ${this.apiKey}`});let i=await fetch(`${this.baseURL}/chat/completions`,d);if(!i.ok){let o=await i.text();throw new Error(`HTTP error! status: ${i.status}, details: ${o}`)}return await i.json()}catch(a){throw O(a)}}async chatStream(t,a){let{signal:d,...i}=t.options||{};try{this.validateRequest(t);let o={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...i,stream:!0},p={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(o),signal:d};this.apiKey&&Object.assign(p.headers,{Authorization:`Bearer ${this.apiKey}`});let u=await fetch(`${this.baseURL}/chat/completions`,p);if(!u.ok){let c=await u.text();throw new Error(`HTTP error! status: ${u.status}, details: ${c}`)}await y(u,a,d)}catch(o){if(d?.aborted)return;a.onError(O(o))}}updateConfig(t){super.updateConfig(t),t.apiUrl&&(this.baseURL=t.apiUrl),t.apiKey&&(this.apiKey=t.apiKey),t.defaultModel&&(this.defaultModel=t.defaultModel)}};var A=class{constructor(e){this.config=e,this.provider=this.createProvider(e)}createProvider(e){if(e.provider==="custom"&&"providerImplementation"in e)return e.providerImplementation;switch(e.provider){case"deepseek":let t={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new R({...t,...e});case"openai":default:return new R(e)}}async chat(e){return this.provider.chat(e)}async chatStream(e,t){let a={...e,options:{...e.options,stream:!0}};return this.provider.chatStream(a,t)}getConfig(){return{...this.config}}updateConfig(e){this.config={...this.config,...e},e.provider&&e.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};var C=require("vue"),K=(o=>(o.INIT="init",o.PROCESSING="processing",o.STREAMING="streaming",o.FINISHED="finished",o.ABORTED="aborted",o.ERROR="error",o))(K||{}),q=["processing","streaming"],G=["finished","aborted","error"];function w(s){let{client:e,useStreamByDefault:t=!0,errorMessage:a="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:d=[]}=s,i=(0,C.ref)([...d]),o=(0,C.ref)(""),p=(0,C.ref)(t),u=null,c=(0,C.reactive)({status:"init",errorMsg:null}),h=async r=>{let g={role:"assistant",content:(await e.chat({messages:(0,C.toRaw)(i.value),options:{stream:!1,signal:r.signal}})).choices[0].message.content};i.value.push(g)},m=async r=>{await e.chatStream({messages:(0,C.toRaw)(i.value),options:{stream:!0,signal:r.signal}},{onData:n=>{c.status="streaming",i.value[i.value.length-1].role==="user"&&i.value.push({role:"assistant",content:""});let g=n.choices?.[0];g&&g.delta.content&&(i.value[i.value.length-1].content+=g.delta.content)},onError:n=>{c.status="error",c.errorMsg=a,console.error("Stream request error:",n)},onDone:()=>{c.status="finished"}})},M=async()=>{c.status="processing",c.errorMsg=null,u=new AbortController;try{p.value?await m(u):await h(u),c.status="finished"}catch(r){c.errorMsg=a,c.status="error",console.error("Send message error:",r)}finally{u=null}};return{messages:i,messageState:c,inputMessage:o,useStream:p,sendMessage:async(r=o.value,n=!0)=>{if(!r?.trim()||q.includes(c.status))return;let g={role:"user",content:r};i.value.push(g),n&&(o.value=""),await M()},clearMessages:()=>{i.value=[],c.errorMsg=null},addMessage:r=>{i.value.push(r)},abortRequest:()=>{u&&(u.abort(),u=null,c.status="aborted")},retryRequest:async r=>{r===0||!i.value[r]||i.value[r].role==="user"||(i.value.splice(r),await M())}}}var I=require("vue");var E=class{constructor(e="tiny-robot-ai-conversations"){this.storageKey=e}saveConversations(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(t){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",t)}}loadConversations(){try{let e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",e),[]}}};function W(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function J(s){let{client:e,storage:t=new E,autoSave:a=!0,useStreamByDefault:d=!0,errorMessage:i="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=s,o=(0,I.reactive)({conversations:[],currentId:null,loading:!1}),p=w({client:e,useStreamByDefault:d,errorMessage:i,initialMessages:[]});(0,I.watch)(()=>p.messages.value,l=>{if(o.currentId&&l.length>0){let r=o.conversations.findIndex(n=>n.id===o.currentId);r!==-1&&(o.conversations[r].messages=[...l],o.conversations[r].updatedAt=Date.now(),a&&f())}},{deep:!0});let u=(l="\u65B0\u4F1A\u8BDD",r={})=>{let n=W(),g={id:n,title:l,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:r};return o.conversations.unshift(g),c(n),a&&f(),n},c=l=>{let r=o.conversations.find(n=>n.id===l);r&&(o.currentId=l,p.clearMessages(),r.messages.length>0&&r.messages.forEach(n=>p.addMessage(n)))},h=l=>{let r=o.conversations.findIndex(n=>n.id===l);r!==-1&&(o.conversations.splice(r,1),o.currentId===l&&(o.conversations.length>0?c(o.conversations[0].id):(o.currentId=null,p.clearMessages())),a&&f())},m=(l,r)=>{let n=o.conversations.find(g=>g.id===l);n&&(n.title=r,n.updatedAt=Date.now(),a&&f())},M=(l,r)=>{let n=o.conversations.find(g=>g.id===l);n&&(n.metadata={...n.metadata,...r},n.updatedAt=Date.now(),a&&f())},f=async()=>{try{await t.saveConversations(o.conversations)}catch(l){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",l)}},b=async()=>{o.loading=!0;try{let l=await t.loadConversations();o.conversations=l,l.length>0&&!o.currentId&&c(l[0].id)}catch(l){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",l)}finally{o.loading=!1}},T=async l=>{let r=o.conversations.find(n=>n.id===l);if(!r||r.messages.length<2)return r?.title||"\u65B0\u4F1A\u8BDD";try{let n={role:"system",content:"\u8BF7\u6839\u636E\u4EE5\u4E0B\u5BF9\u8BDD\u5185\u5BB9\uFF0C\u751F\u6210\u4E00\u4E2A\u7B80\u77ED\u7684\u6807\u9898\uFF08\u4E0D\u8D85\u8FC720\u4E2A\u5B57\u7B26\uFF09\u3002\u53EA\u9700\u8981\u8FD4\u56DE\u6807\u9898\u6587\u672C\uFF0C\u4E0D\u9700\u8981\u4EFB\u4F55\u89E3\u91CA\u6216\u989D\u5916\u5185\u5BB9\u3002"},g=r.messages.slice(0,Math.min(4,r.messages.length)),N=(await e.chat({messages:[n,...g],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return m(l,N),N}catch(n){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",n),r.title}},P=()=>o.currentId&&o.conversations.find(l=>l.id===o.currentId)||null;return b(),{state:o,messageManager:p,createConversation:u,switchConversation:c,deleteConversation:h,updateTitle:m,updateMetadata:M,saveConversations:f,loadConversations:b,generateTitle:T,getCurrentConversation:P}}0&&(module.exports={AIClient,BaseModelProvider,ErrorType,FinalStatus,GeneratingStatus,LocalStorageStrategy,OpenAIProvider,STATUS,StreamEventType,extractTextFromResponse,formatMessages,handleSSEStream,useConversation,useMessage});
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- var M=class{constructor(e){this.config=e}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}validateRequest(e){if(!e.messages||!Array.isArray(e.messages)||e.messages.length===0)throw new Error("\u8BF7\u6C42\u5FC5\u987B\u5305\u542B\u81F3\u5C11\u4E00\u6761\u6D88\u606F");for(let o of e.messages)if(!o.role||!o.content)throw new Error("\u6BCF\u6761\u6D88\u606F\u5FC5\u987B\u5305\u542B\u89D2\u8272\u548C\u5185\u5BB9")}};var P=(p=>(p.NETWORK_ERROR="network_error",p.AUTHENTICATION_ERROR="authentication_error",p.RATE_LIMIT_ERROR="rate_limit_error",p.SERVER_ERROR="server_error",p.MODEL_ERROR="model_error",p.TIMEOUT_ERROR="timeout_error",p.UNKNOWN_ERROR="unknown_error",p))(P||{}),U=(l=>(l.DATA="data",l.ERROR="error",l.DONE="done",l))(U||{});function f(r){return{type:r.type||"unknown_error",message:r.message||"\u672A\u77E5\u9519\u8BEF",statusCode:r.statusCode,originalError:r.originalError}}function y(r){if(!r.response)return f({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:r});if(r.response){let{status:e,data:o}=r.response;return e===401||e===403?f({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:e,originalError:r}):e===429?f({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:r}):e>=500?f({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:r}):f({type:"unknown_error",message:o?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:r})}return r.code==="ECONNABORTED"?f({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:r}):f({type:"unknown_error",message:r.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:r})}async function w(r,e,o){let l=r.body?.getReader();if(!l)throw new Error("Response body is null");let g=new TextDecoder,a="";o&&o.addEventListener("abort",()=>{l.cancel().catch(t=>console.error("Error cancelling reader:",t))},{once:!0});try{for(;;){if(o?.aborted){await l.cancel();break}let{done:t,value:p}=await l.read();if(t)break;let d=g.decode(p,{stream:!0});a+=d;let c=a.split(`
1
+ var M=class{constructor(e){this.config=e}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}validateRequest(e){if(!e.messages||!Array.isArray(e.messages)||e.messages.length===0)throw new Error("\u8BF7\u6C42\u5FC5\u987B\u5305\u542B\u81F3\u5C11\u4E00\u6761\u6D88\u606F");for(let o of e.messages)if(!o.role||!o.content)throw new Error("\u6BCF\u6761\u6D88\u606F\u5FC5\u987B\u5305\u542B\u89D2\u8272\u548C\u5185\u5BB9")}};var N=(p=>(p.NETWORK_ERROR="network_error",p.AUTHENTICATION_ERROR="authentication_error",p.RATE_LIMIT_ERROR="rate_limit_error",p.SERVER_ERROR="server_error",p.MODEL_ERROR="model_error",p.TIMEOUT_ERROR="timeout_error",p.UNKNOWN_ERROR="unknown_error",p))(N||{}),U=(l=>(l.DATA="data",l.ERROR="error",l.DONE="done",l))(U||{});function f(r){return{type:r.type||"unknown_error",message:r.message||"\u672A\u77E5\u9519\u8BEF",statusCode:r.statusCode,originalError:r.originalError}}function y(r){if(!r.response)return f({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:r});if(r.response){let{status:e,data:o}=r.response;return e===401||e===403?f({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:e,originalError:r}):e===429?f({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:r}):e>=500?f({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:r}):f({type:"unknown_error",message:o?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:r})}return r.code==="ECONNABORTED"?f({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:r}):f({type:"unknown_error",message:r.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:r})}async function A(r,e,o){let l=r.body?.getReader();if(!l)throw new Error("Response body is null");let g=new TextDecoder,a="";o&&o.addEventListener("abort",()=>{l.cancel().catch(t=>console.error("Error cancelling reader:",t))},{once:!0});try{for(;;){if(o?.aborted){await l.cancel();break}let{done:t,value:p}=await l.read();if(t)break;let d=g.decode(p,{stream:!0});a+=d;let c=a.split(`
2
2
 
3
- `);a=c.pop()||"";for(let C of c)if(C.trim()!==""){if(C.trim()==="data: [DONE]"){e.onDone();continue}try{let m=C.match(/^data: (.+)$/m);if(!m)continue;let v=JSON.parse(m[1]);e.onData(v)}catch(m){console.error("Error parsing SSE message:",m)}}}(a.trim()==="data: [DONE]"||o?.aborted)&&e.onDone()}catch(t){if(o?.aborted)return;throw t}}function D(r){return r.map(e=>typeof e=="object"&&"role"in e&&"content"in e?{role:e.role,content:String(e.content),...e.name?{name:e.name}:{}}:typeof e=="string"?{role:"user",content:e}:{role:"user",content:String(e)})}function _(r){return!r.choices||!r.choices.length?"":r.choices[0].message?.content||""}var R=class extends M{constructor(o){super(o);this.defaultModel="gpt-3.5-turbo";this.baseURL=o.apiUrl||"https://api.openai.com/v1",this.apiKey=o.apiKey||"",o.defaultModel&&(this.defaultModel=o.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(o){try{this.validateRequest(o);let l={model:o.options?.model||this.config.defaultModel||this.defaultModel,messages:o.messages,...o.options,stream:!1},g={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)};this.apiKey&&Object.assign(g.headers,{Authorization:`Bearer ${this.apiKey}`});let a=await fetch(`${this.baseURL}/chat/completions`,g);if(!a.ok){let t=await a.text();throw new Error(`HTTP error! status: ${a.status}, details: ${t}`)}return await a.json()}catch(l){throw y(l)}}async chatStream(o,l){let{signal:g,...a}=o.options||{};try{this.validateRequest(o);let t={model:o.options?.model||this.config.defaultModel||this.defaultModel,messages:o.messages,...a,stream:!0},p={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(t),signal:g};this.apiKey&&Object.assign(p.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,p);if(!d.ok){let c=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${c}`)}await w(d,l,g)}catch(t){if(g?.aborted)return;l.onError(y(t))}}updateConfig(o){super.updateConfig(o),o.apiUrl&&(this.baseURL=o.apiUrl),o.apiKey&&(this.apiKey=o.apiKey),o.defaultModel&&(this.defaultModel=o.defaultModel)}};var A=class{constructor(e){this.config=e,this.provider=this.createProvider(e)}createProvider(e){if(e.provider==="custom"&&"providerImplementation"in e)return e.providerImplementation;switch(e.provider){case"deepseek":let o={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new R({...o,...e});case"openai":default:return new R(e)}}async chat(e){return this.provider.chat(e)}async chatStream(e,o){let l={...e,options:{...e.options,stream:!0}};return this.provider.chatStream(l,o)}getConfig(){return{...this.config}}updateConfig(e){this.config={...this.config,...e},e.provider&&e.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};import{reactive as k,ref as E,toRaw as T}from"vue";var K=(t=>(t.INIT="init",t.PROCESSING="processing",t.STREAMING="streaming",t.FINISHED="finished",t.ABORTED="aborted",t.ERROR="error",t))(K||{}),q=["processing","streaming"],te=["finished","aborted","error"];function N(r){let{client:e,useStreamByDefault:o=!0,errorMessage:l="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:g=[]}=r,a=E([...g]),t=E(""),p=E(o),d=null,c=k({status:"init",errorMsg:null}),C=async s=>{let u={role:"assistant",content:(await e.chat({messages:T(a.value),options:{stream:!1,signal:s.signal}})).choices[0].message.content};a.value.push(u)},m=async s=>{await e.chatStream({messages:T(a.value),options:{stream:!0,signal:s.signal}},{onData:n=>{c.status="streaming",a.value[a.value.length-1].role==="user"&&a.value.push({role:"assistant",content:""});let u=n.choices?.[0];u&&u.delta.content&&(a.value[a.value.length-1].content+=u.delta.content)},onError:n=>{c.status="error",c.errorMsg=l,console.error("Stream request error:",n)},onDone:()=>{c.status="finished"}})},v=async()=>{c.status="processing",c.errorMsg=null,d=new AbortController;try{p.value?await m(d):await C(d),c.status="finished"}catch(s){c.errorMsg=l,c.status="error",console.error("Send message error:",s)}finally{d=null}};return{messages:a,messageState:c,inputMessage:t,useStream:p,sendMessage:async(s=t.value,n=!0)=>{if(!s?.trim()||q.includes(c.status))return;let u={role:"user",content:s};a.value.push(u),n&&(t.value=""),await v()},clearMessages:()=>{a.value=[],c.errorMsg=null},addMessage:s=>{a.value.push(s)},abortRequest:()=>{d&&(d.abort(),d=null,c.status="aborted")},retryRequest:async s=>{s===0||!a.value[s]||a.value[s].role==="user"||(a.value.splice(s),await v())}}}import{reactive as H,watch as B}from"vue";var I=class{constructor(e="tiny-robot-ai-conversations"){this.storageKey=e}saveConversations(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(o){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",o)}}loadConversations(){try{let e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",e),[]}}};function j(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function ne(r){let{client:e,storage:o=new I,autoSave:l=!0,useStreamByDefault:g=!0,errorMessage:a="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=r,t=H({conversations:[],currentId:null,loading:!1}),p=N({client:e,useStreamByDefault:g,errorMessage:a,initialMessages:[]});B(()=>p.messages.value,i=>{if(t.currentId&&i.length>0){let s=t.conversations.findIndex(n=>n.id===t.currentId);s!==-1&&(t.conversations[s].messages=[...i],t.conversations[s].updatedAt=Date.now(),l&&h())}},{deep:!0});let d=(i="\u65B0\u4F1A\u8BDD",s={})=>{let n=j(),u={id:n,title:i,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:s};return t.conversations.unshift(u),c(n),l&&h(),n},c=i=>{let s=t.conversations.find(n=>n.id===i);s&&(t.currentId=i,p.clearMessages(),s.messages.length>0&&s.messages.forEach(n=>p.addMessage(n)))},C=i=>{let s=t.conversations.findIndex(n=>n.id===i);s!==-1&&(t.conversations.splice(s,1),t.currentId===i&&(t.conversations.length>0?c(t.conversations[0].id):(t.currentId=null,p.clearMessages())),l&&h())},m=(i,s)=>{let n=t.conversations.find(u=>u.id===i);n&&(n.title=s,n.updatedAt=Date.now(),l&&h())},v=(i,s)=>{let n=t.conversations.find(u=>u.id===i);n&&(n.metadata={...n.metadata,...s},n.updatedAt=Date.now(),l&&h())},h=async()=>{try{await o.saveConversations(t.conversations)}catch(i){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",i)}},S=async()=>{t.loading=!0;try{let i=await o.loadConversations();t.conversations=i,i.length>0&&!t.currentId&&c(i[0].id)}catch(i){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",i)}finally{t.loading=!1}},b=async i=>{let s=t.conversations.find(n=>n.id===i);if(!s||s.messages.length<2)return s?.title||"\u65B0\u4F1A\u8BDD";try{let n={role:"system",content:"\u8BF7\u6839\u636E\u4EE5\u4E0B\u5BF9\u8BDD\u5185\u5BB9\uFF0C\u751F\u6210\u4E00\u4E2A\u7B80\u77ED\u7684\u6807\u9898\uFF08\u4E0D\u8D85\u8FC720\u4E2A\u5B57\u7B26\uFF09\u3002\u53EA\u9700\u8981\u8FD4\u56DE\u6807\u9898\u6587\u672C\uFF0C\u4E0D\u9700\u8981\u4EFB\u4F55\u89E3\u91CA\u6216\u989D\u5916\u5185\u5BB9\u3002"},u=s.messages.slice(0,Math.min(4,s.messages.length)),O=(await e.chat({messages:[n,...u],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return m(i,O),O}catch(n){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",n),s.title}},x=()=>t.currentId&&t.conversations.find(i=>i.id===t.currentId)||null;return S(),{state:t,messageManager:p,createConversation:d,switchConversation:c,deleteConversation:C,updateTitle:m,updateMetadata:v,saveConversations:h,loadConversations:S,generateTitle:b,getCurrentConversation:x}}export{A as AIClient,M as BaseModelProvider,P as ErrorType,te as FinalStatus,q as GeneratingStatus,I as LocalStorageStrategy,R as OpenAIProvider,K as STATUS,U as StreamEventType,_ as extractTextFromResponse,D as formatMessages,ne as useConversation,N as useMessage};
3
+ `);a=c.pop()||"";for(let C of c)if(C.trim()!==""){if(C.trim()==="data: [DONE]"){e.onDone();continue}try{let m=C.match(/^data: (.+)$/m);if(!m)continue;let v=JSON.parse(m[1]);e.onData(v)}catch(m){console.error("Error parsing SSE message:",m)}}}(a.trim()==="data: [DONE]"||o?.aborted)&&e.onDone()}catch(t){if(o?.aborted)return;throw t}}function D(r){return r.map(e=>typeof e=="object"&&"role"in e&&"content"in e?{role:e.role,content:String(e.content),...e.name?{name:e.name}:{}}:typeof e=="string"?{role:"user",content:e}:{role:"user",content:String(e)})}function _(r){return!r.choices||!r.choices.length?"":r.choices[0].message?.content||""}var R=class extends M{constructor(o){super(o);this.defaultModel="gpt-3.5-turbo";this.baseURL=o.apiUrl||"https://api.openai.com/v1",this.apiKey=o.apiKey||"",o.defaultModel&&(this.defaultModel=o.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(o){try{this.validateRequest(o);let l={model:o.options?.model||this.config.defaultModel||this.defaultModel,messages:o.messages,...o.options,stream:!1},g={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)};this.apiKey&&Object.assign(g.headers,{Authorization:`Bearer ${this.apiKey}`});let a=await fetch(`${this.baseURL}/chat/completions`,g);if(!a.ok){let t=await a.text();throw new Error(`HTTP error! status: ${a.status}, details: ${t}`)}return await a.json()}catch(l){throw y(l)}}async chatStream(o,l){let{signal:g,...a}=o.options||{};try{this.validateRequest(o);let t={model:o.options?.model||this.config.defaultModel||this.defaultModel,messages:o.messages,...a,stream:!0},p={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(t),signal:g};this.apiKey&&Object.assign(p.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,p);if(!d.ok){let c=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${c}`)}await A(d,l,g)}catch(t){if(g?.aborted)return;l.onError(y(t))}}updateConfig(o){super.updateConfig(o),o.apiUrl&&(this.baseURL=o.apiUrl),o.apiKey&&(this.apiKey=o.apiKey),o.defaultModel&&(this.defaultModel=o.defaultModel)}};var E=class{constructor(e){this.config=e,this.provider=this.createProvider(e)}createProvider(e){if(e.provider==="custom"&&"providerImplementation"in e)return e.providerImplementation;switch(e.provider){case"deepseek":let o={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new R({...o,...e});case"openai":default:return new R(e)}}async chat(e){return this.provider.chat(e)}async chatStream(e,o){let l={...e,options:{...e.options,stream:!0}};return this.provider.chatStream(l,o)}getConfig(){return{...this.config}}updateConfig(e){this.config={...this.config,...e},e.provider&&e.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};import{reactive as k,ref as I,toRaw as T}from"vue";var K=(t=>(t.INIT="init",t.PROCESSING="processing",t.STREAMING="streaming",t.FINISHED="finished",t.ABORTED="aborted",t.ERROR="error",t))(K||{}),q=["processing","streaming"],te=["finished","aborted","error"];function P(r){let{client:e,useStreamByDefault:o=!0,errorMessage:l="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:g=[]}=r,a=I([...g]),t=I(""),p=I(o),d=null,c=k({status:"init",errorMsg:null}),C=async s=>{let u={role:"assistant",content:(await e.chat({messages:T(a.value),options:{stream:!1,signal:s.signal}})).choices[0].message.content};a.value.push(u)},m=async s=>{await e.chatStream({messages:T(a.value),options:{stream:!0,signal:s.signal}},{onData:n=>{c.status="streaming",a.value[a.value.length-1].role==="user"&&a.value.push({role:"assistant",content:""});let u=n.choices?.[0];u&&u.delta.content&&(a.value[a.value.length-1].content+=u.delta.content)},onError:n=>{c.status="error",c.errorMsg=l,console.error("Stream request error:",n)},onDone:()=>{c.status="finished"}})},v=async()=>{c.status="processing",c.errorMsg=null,d=new AbortController;try{p.value?await m(d):await C(d),c.status="finished"}catch(s){c.errorMsg=l,c.status="error",console.error("Send message error:",s)}finally{d=null}};return{messages:a,messageState:c,inputMessage:t,useStream:p,sendMessage:async(s=t.value,n=!0)=>{if(!s?.trim()||q.includes(c.status))return;let u={role:"user",content:s};a.value.push(u),n&&(t.value=""),await v()},clearMessages:()=>{a.value=[],c.errorMsg=null},addMessage:s=>{a.value.push(s)},abortRequest:()=>{d&&(d.abort(),d=null,c.status="aborted")},retryRequest:async s=>{s===0||!a.value[s]||a.value[s].role==="user"||(a.value.splice(s),await v())}}}import{reactive as B,watch as H}from"vue";var b=class{constructor(e="tiny-robot-ai-conversations"){this.storageKey=e}saveConversations(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(o){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",o)}}loadConversations(){try{let e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",e),[]}}};function j(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function ne(r){let{client:e,storage:o=new b,autoSave:l=!0,useStreamByDefault:g=!0,errorMessage:a="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=r,t=B({conversations:[],currentId:null,loading:!1}),p=P({client:e,useStreamByDefault:g,errorMessage:a,initialMessages:[]});H(()=>p.messages.value,i=>{if(t.currentId&&i.length>0){let s=t.conversations.findIndex(n=>n.id===t.currentId);s!==-1&&(t.conversations[s].messages=[...i],t.conversations[s].updatedAt=Date.now(),l&&h())}},{deep:!0});let d=(i="\u65B0\u4F1A\u8BDD",s={})=>{let n=j(),u={id:n,title:i,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:s};return t.conversations.unshift(u),c(n),l&&h(),n},c=i=>{let s=t.conversations.find(n=>n.id===i);s&&(t.currentId=i,p.clearMessages(),s.messages.length>0&&s.messages.forEach(n=>p.addMessage(n)))},C=i=>{let s=t.conversations.findIndex(n=>n.id===i);s!==-1&&(t.conversations.splice(s,1),t.currentId===i&&(t.conversations.length>0?c(t.conversations[0].id):(t.currentId=null,p.clearMessages())),l&&h())},m=(i,s)=>{let n=t.conversations.find(u=>u.id===i);n&&(n.title=s,n.updatedAt=Date.now(),l&&h())},v=(i,s)=>{let n=t.conversations.find(u=>u.id===i);n&&(n.metadata={...n.metadata,...s},n.updatedAt=Date.now(),l&&h())},h=async()=>{try{await o.saveConversations(t.conversations)}catch(i){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",i)}},S=async()=>{t.loading=!0;try{let i=await o.loadConversations();t.conversations=i,i.length>0&&!t.currentId&&c(i[0].id)}catch(i){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",i)}finally{t.loading=!1}},x=async i=>{let s=t.conversations.find(n=>n.id===i);if(!s||s.messages.length<2)return s?.title||"\u65B0\u4F1A\u8BDD";try{let n={role:"system",content:"\u8BF7\u6839\u636E\u4EE5\u4E0B\u5BF9\u8BDD\u5185\u5BB9\uFF0C\u751F\u6210\u4E00\u4E2A\u7B80\u77ED\u7684\u6807\u9898\uFF08\u4E0D\u8D85\u8FC720\u4E2A\u5B57\u7B26\uFF09\u3002\u53EA\u9700\u8981\u8FD4\u56DE\u6807\u9898\u6587\u672C\uFF0C\u4E0D\u9700\u8981\u4EFB\u4F55\u89E3\u91CA\u6216\u989D\u5916\u5185\u5BB9\u3002"},u=s.messages.slice(0,Math.min(4,s.messages.length)),w=(await e.chat({messages:[n,...u],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return m(i,w),w}catch(n){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",n),s.title}},O=()=>t.currentId&&t.conversations.find(i=>i.id===t.currentId)||null;return S(),{state:t,messageManager:p,createConversation:d,switchConversation:c,deleteConversation:C,updateTitle:m,updateMetadata:v,saveConversations:h,loadConversations:S,generateTitle:x,getCurrentConversation:O}}export{E as AIClient,M as BaseModelProvider,N as ErrorType,te as FinalStatus,q as GeneratingStatus,b as LocalStorageStrategy,R as OpenAIProvider,K as STATUS,U as StreamEventType,_ as extractTextFromResponse,D as formatMessages,A as handleSSEStream,ne as useConversation,P as useMessage};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentiny/tiny-robot-kit",
3
- "version": "0.2.0-alpha.6",
3
+ "version": "0.2.0-alpha.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -26,5 +26,5 @@
26
26
  "peerDependencies": {
27
27
  "vue": ">=3.0.0"
28
28
  },
29
- "gitHead": "3068fcc667cb81a7669a3eab2de99d9f4ae736ed"
29
+ "gitHead": "84e0af60d94603496cece1b3ecd0f0e54bd0ad53"
30
30
  }