@opentiny/tiny-robot-kit 0.3.0-alpha.3 → 0.3.0-alpha.30

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
@@ -47,12 +47,12 @@ type MessageRole = 'system' | 'user' | 'assistant';
47
47
  */
48
48
  interface ChatMessage {
49
49
  role: MessageRole;
50
- content: string;
51
- messages?: {
50
+ content: string | {
52
51
  type: string;
53
- [extra: string]: unknown;
52
+ [x: string]: unknown;
54
53
  }[];
55
54
  name?: string;
55
+ [x: string]: unknown;
56
56
  }
57
57
  /**
58
58
  * 聊天历史记录
@@ -83,6 +83,7 @@ interface ChatCompletionRequest {
83
83
  interface ChatCompletionResponseMessage {
84
84
  role: MessageRole;
85
85
  content: string;
86
+ [x: string]: unknown;
86
87
  }
87
88
  /**
88
89
  * 聊天完成响应选择
@@ -117,6 +118,7 @@ interface ChatCompletionResponse {
117
118
  interface ChatCompletionStreamResponseDelta {
118
119
  content?: string;
119
120
  role?: MessageRole;
121
+ [x: string]: unknown;
120
122
  }
121
123
  /**
122
124
  * 流式聊天完成响应选择
@@ -186,12 +188,8 @@ declare enum StreamEventType {
186
188
  */
187
189
  interface StreamHandler {
188
190
  onData: (data: ChatCompletionStreamResponse) => void;
189
- onMessage?: (msgObj: {
190
- type: string;
191
- [extra: string]: unknown;
192
- }) => void;
193
191
  onError: (error: AIAdapterError) => void;
194
- onDone: () => void;
192
+ onDone: (finishReason?: string) => void;
195
193
  }
196
194
 
197
195
  /**
@@ -331,6 +329,13 @@ interface UseMessageOptions {
331
329
  errorMessage?: string;
332
330
  /** 初始消息列表 */
333
331
  initialMessages?: ChatMessage[];
332
+ events?: {
333
+ onReceiveData?: <T = any>(data: T, messages: Ref<ChatMessage[]>, preventDefault: () => void) => void;
334
+ onFinish?: (finishReason: string | undefined, context: {
335
+ messages: Ref<ChatMessage[]>;
336
+ messageState: Reactive<MessageState>;
337
+ }, preventDefault: () => void) => void;
338
+ };
334
339
  }
335
340
  /**
336
341
  * useMessage返回值接口
@@ -344,11 +349,13 @@ interface UseMessageReturn {
344
349
  /** 是否使用流式响应 */
345
350
  useStream: Ref<boolean>;
346
351
  /** 发送消息 */
347
- sendMessage: (content?: string, clearInput?: boolean) => Promise<void>;
352
+ sendMessage: (content?: ChatMessage['content'], clearInput?: boolean) => Promise<void>;
353
+ /** 手动执行addMessage添加消息后,可以执行send发送消息 */
354
+ send: () => Promise<void>;
348
355
  /** 清空消息 */
349
356
  clearMessages: () => void;
350
357
  /** 添加消息 */
351
- addMessage: (message: ChatMessage) => void;
358
+ addMessage: (message: ChatMessage | ChatMessage[]) => void;
352
359
  /** 中止请求 */
353
360
  abortRequest: () => void;
354
361
  /** 重试请求 */
@@ -414,6 +421,9 @@ interface ConversationState {
414
421
  /** 是否正在加载 */
415
422
  loading: boolean;
416
423
  }
424
+ type UseConversationEvents = UseMessageOptions['events'] & {
425
+ onLoaded?: (conversations: Conversation[]) => void;
426
+ };
417
427
  /**
418
428
  * useConversation选项接口
419
429
  */
@@ -424,10 +434,14 @@ interface UseConversationOptions {
424
434
  storage?: ConversationStorageStrategy;
425
435
  /** 是否自动保存 */
426
436
  autoSave?: boolean;
437
+ /** 是否允许空会话 */
438
+ allowEmpty?: boolean;
427
439
  /** 是否默认使用流式响应 */
428
440
  useStreamByDefault?: boolean;
429
441
  /** 错误消息模板 */
430
442
  errorMessage?: string;
443
+ /** 事件回调 */
444
+ events?: UseConversationEvents;
431
445
  }
432
446
  /**
433
447
  * useConversation返回值接口
@@ -465,4 +479,4 @@ interface UseConversationReturn {
465
479
  */
466
480
  declare function useConversation(options: UseConversationOptions): UseConversationReturn;
467
481
 
468
- 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 };
482
+ 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 UseConversationEvents, type UseConversationOptions, type UseConversationReturn, type UseMessageOptions, type UseMessageReturn, extractTextFromResponse, formatMessages, handleSSEStream, useConversation, useMessage };
package/dist/index.d.ts CHANGED
@@ -47,12 +47,12 @@ type MessageRole = 'system' | 'user' | 'assistant';
47
47
  */
48
48
  interface ChatMessage {
49
49
  role: MessageRole;
50
- content: string;
51
- messages?: {
50
+ content: string | {
52
51
  type: string;
53
- [extra: string]: unknown;
52
+ [x: string]: unknown;
54
53
  }[];
55
54
  name?: string;
55
+ [x: string]: unknown;
56
56
  }
57
57
  /**
58
58
  * 聊天历史记录
@@ -83,6 +83,7 @@ interface ChatCompletionRequest {
83
83
  interface ChatCompletionResponseMessage {
84
84
  role: MessageRole;
85
85
  content: string;
86
+ [x: string]: unknown;
86
87
  }
87
88
  /**
88
89
  * 聊天完成响应选择
@@ -117,6 +118,7 @@ interface ChatCompletionResponse {
117
118
  interface ChatCompletionStreamResponseDelta {
118
119
  content?: string;
119
120
  role?: MessageRole;
121
+ [x: string]: unknown;
120
122
  }
121
123
  /**
122
124
  * 流式聊天完成响应选择
@@ -186,12 +188,8 @@ declare enum StreamEventType {
186
188
  */
187
189
  interface StreamHandler {
188
190
  onData: (data: ChatCompletionStreamResponse) => void;
189
- onMessage?: (msgObj: {
190
- type: string;
191
- [extra: string]: unknown;
192
- }) => void;
193
191
  onError: (error: AIAdapterError) => void;
194
- onDone: () => void;
192
+ onDone: (finishReason?: string) => void;
195
193
  }
196
194
 
197
195
  /**
@@ -331,6 +329,13 @@ interface UseMessageOptions {
331
329
  errorMessage?: string;
332
330
  /** 初始消息列表 */
333
331
  initialMessages?: ChatMessage[];
332
+ events?: {
333
+ onReceiveData?: <T = any>(data: T, messages: Ref<ChatMessage[]>, preventDefault: () => void) => void;
334
+ onFinish?: (finishReason: string | undefined, context: {
335
+ messages: Ref<ChatMessage[]>;
336
+ messageState: Reactive<MessageState>;
337
+ }, preventDefault: () => void) => void;
338
+ };
334
339
  }
335
340
  /**
336
341
  * useMessage返回值接口
@@ -344,11 +349,13 @@ interface UseMessageReturn {
344
349
  /** 是否使用流式响应 */
345
350
  useStream: Ref<boolean>;
346
351
  /** 发送消息 */
347
- sendMessage: (content?: string, clearInput?: boolean) => Promise<void>;
352
+ sendMessage: (content?: ChatMessage['content'], clearInput?: boolean) => Promise<void>;
353
+ /** 手动执行addMessage添加消息后,可以执行send发送消息 */
354
+ send: () => Promise<void>;
348
355
  /** 清空消息 */
349
356
  clearMessages: () => void;
350
357
  /** 添加消息 */
351
- addMessage: (message: ChatMessage) => void;
358
+ addMessage: (message: ChatMessage | ChatMessage[]) => void;
352
359
  /** 中止请求 */
353
360
  abortRequest: () => void;
354
361
  /** 重试请求 */
@@ -414,6 +421,9 @@ interface ConversationState {
414
421
  /** 是否正在加载 */
415
422
  loading: boolean;
416
423
  }
424
+ type UseConversationEvents = UseMessageOptions['events'] & {
425
+ onLoaded?: (conversations: Conversation[]) => void;
426
+ };
417
427
  /**
418
428
  * useConversation选项接口
419
429
  */
@@ -424,10 +434,14 @@ interface UseConversationOptions {
424
434
  storage?: ConversationStorageStrategy;
425
435
  /** 是否自动保存 */
426
436
  autoSave?: boolean;
437
+ /** 是否允许空会话 */
438
+ allowEmpty?: boolean;
427
439
  /** 是否默认使用流式响应 */
428
440
  useStreamByDefault?: boolean;
429
441
  /** 错误消息模板 */
430
442
  errorMessage?: string;
443
+ /** 事件回调 */
444
+ events?: UseConversationEvents;
431
445
  }
432
446
  /**
433
447
  * useConversation返回值接口
@@ -465,4 +479,4 @@ interface UseConversationReturn {
465
479
  */
466
480
  declare function useConversation(options: UseConversationOptions): UseConversationReturn;
467
481
 
468
- 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 };
482
+ 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 UseConversationEvents, 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 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})},G=(s,e,t,i)=>{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:!(i=B(e,d))||i.enumerable});return s};var L=s=>G(x({},"__esModule",{value:!0}),s);var z={};$(z,{AIClient:()=>A,BaseModelProvider:()=>S,ErrorType:()=>U,FinalStatus:()=>F,GeneratingStatus:()=>q,LocalStorageStrategy:()=>E,OpenAIProvider:()=>R,STATUS:()=>K,StreamEventType:()=>D,extractTextFromResponse:()=>k,formatMessages:()=>_,handleSSEStream:()=>y,useConversation:()=>J,useMessage:()=>O});module.exports=L(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=(i=>(i.DATA="data",i.ERROR="error",i.DONE="done",i))(D||{});function v(s){return{type:s.type||"unknown_error",message:s.message||"\u672A\u77E5\u9519\u8BEF",statusCode:s.statusCode,originalError:s.originalError}}function w(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 i=s.body?.getReader();if(!i)throw new Error("Response body is null");let d=new TextDecoder,n="";t&&t.addEventListener("abort",()=>{i.cancel().catch(o=>console.error("Error cancelling reader:",o))},{once:!0});try{for(;;){if(t?.aborted){await i.cancel();break}let{done:o,value:p}=await i.read();if(o)break;let u=d.decode(p,{stream:!0});n+=u;let c=n.split(`
1
+ "use strict";var T=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var W=(r,e)=>{for(var t in e)T(r,t,{get:e[t],enumerable:!0})},J=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let u of $(e))!G.call(r,u)&&u!==t&&T(r,u,{get:()=>e[u],enumerable:!(i=L(e,u))||i.enumerable});return r};var z=r=>J(T({},"__esModule",{value:!0}),r);var Y={};W(Y,{AIClient:()=>b,BaseModelProvider:()=>E,ErrorType:()=>q,FinalStatus:()=>V,GeneratingStatus:()=>P,LocalStorageStrategy:()=>x,OpenAIProvider:()=>S,STATUS:()=>F,StreamEventType:()=>B,extractTextFromResponse:()=>j,formatMessages:()=>H,handleSSEStream:()=>I,useConversation:()=>X,useMessage:()=>U});module.exports=z(Y);var E=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 q=(d=>(d.NETWORK_ERROR="network_error",d.AUTHENTICATION_ERROR="authentication_error",d.RATE_LIMIT_ERROR="rate_limit_error",d.SERVER_ERROR="server_error",d.MODEL_ERROR="model_error",d.TIMEOUT_ERROR="timeout_error",d.UNKNOWN_ERROR="unknown_error",d))(q||{}),B=(i=>(i.DATA="data",i.ERROR="error",i.DONE="done",i))(B||{});function y(r){return{type:r.type||"unknown_error",message:r.message||"\u672A\u77E5\u9519\u8BEF",statusCode:r.statusCode,originalError:r.originalError}}function D(r){if(!r.response)return y({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:t}=r.response;return e===401||e===403?y({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:e,originalError:r}):e===429?y({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:r}):e>=500?y({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:r}):y({type:"unknown_error",message:t?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:r})}return r.code==="ECONNABORTED"?y({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:r}):y({type:"unknown_error",message:r.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:r})}async function I(r,e,t){let i=r.body?.getReader();if(!i)throw new Error("Response body is null");let u=new TextDecoder,a="",c,d;t&&t.addEventListener("abort",()=>{i.cancel().catch(o=>console.error("Error cancelling reader:",o))},{once:!0});try{for(;;){if(t?.aborted){await i.cancel();break}let{done:o,value:p}=await i.read();if(o)break;let m=u.decode(p,{stream:!0});a+=m;let A=a.split(`
2
2
 
3
- `);n=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 M=JSON.parse(m[1]);e.onData(M)}catch(m){console.error("Error parsing SSE message:",m)}}}(n.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 i={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(i)};this.apiKey&&Object.assign(d.headers,{Authorization:`Bearer ${this.apiKey}`});let n=await fetch(`${this.baseURL}/chat/completions`,d);if(!n.ok){let o=await n.text();throw new Error(`HTTP error! status: ${n.status}, details: ${o}`)}return await n.json()}catch(i){throw w(i)}}async chatStream(t,i){let{signal:d,...n}=t.options||{};try{this.validateRequest(t);let o={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...n,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,i,d)}catch(o){if(d?.aborted)return;i.onError(w(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 i={...e,options:{...e.options,stream:!0}};return this.provider.chatStream(i,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 h=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"],F=["finished","aborted","error"];function O(s){let{client:e,useStreamByDefault:t=!0,errorMessage:i="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:d=[]}=s,n=(0,h.ref)([...d]),o=(0,h.ref)(""),p=(0,h.ref)(t),u=null,c=(0,h.reactive)({status:"init",errorMsg:null}),C=async r=>{let g={role:"assistant",content:(await e.chat({messages:(0,h.toRaw)(n.value),options:{stream:!1,signal:r.signal}})).choices[0].message.content};n.value.push(g)},m=async r=>{await e.chatStream({messages:(0,h.toRaw)(n.value),options:{stream:!0,signal:r.signal}},{onData:a=>{c.status="streaming",n.value[n.value.length-1].role==="user"&&n.value.push({role:"assistant",content:""});let g=a.choices?.[0];g&&g.delta.content&&(n.value[n.value.length-1].content+=g.delta.content)},onMessage:a=>{c.status="streaming",n.value[n.value.length-1].role==="user"&&n.value.push({role:"assistant",content:""}),"type"in a&&(n.value[n.value.length-1].messages||(n.value[n.value.length-1].messages=[]),n.value[n.value.length-1].messages.push(a))},onError:a=>{c.status="error",c.errorMsg=i,console.error("Stream request error:",a)},onDone:()=>{c.status="finished"}})},M=async()=>{c.status="processing",c.errorMsg=null,u=new AbortController;try{p.value?await m(u):await C(u),c.status="finished"}catch(r){c.errorMsg=i,c.status="error",console.error("Send message error:",r)}finally{u=null}};return{messages:n,messageState:c,inputMessage:o,useStream:p,sendMessage:async(r=o.value,a=!0)=>{if(!r?.trim()||q.includes(c.status))return;let g={role:"user",content:r};n.value.push(g),a&&(o.value=""),await M()},clearMessages:()=>{n.value=[],c.errorMsg=null},addMessage:r=>{n.value.push(r)},abortRequest:()=>{u&&(u.abort(),u=null,c.status="aborted")},retryRequest:async r=>{r===0||!n.value[r]||n.value[r].role==="user"||(n.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:i=!0,useStreamByDefault:d=!0,errorMessage:n="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=s,o=(0,I.reactive)({conversations:[],currentId:null,loading:!1}),p=O({client:e,useStreamByDefault:d,errorMessage:n,initialMessages:[]});(0,I.watch)(()=>p.messages.value,l=>{if(o.currentId&&l.length>0){let r=o.conversations.findIndex(a=>a.id===o.currentId);r!==-1&&(o.conversations[r].messages=[...l],o.conversations[r].updatedAt=Date.now(),i&&f())}},{deep:!0});let u=(l="\u65B0\u4F1A\u8BDD",r={})=>{let a=W(),g={id:a,title:l,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:r};return o.conversations.unshift(g),c(a),i&&f(),a},c=l=>{let r=o.conversations.find(a=>a.id===l);r&&(o.currentId=l,p.clearMessages(),r.messages.length>0&&r.messages.forEach(a=>p.addMessage(a)))},C=l=>{let r=o.conversations.findIndex(a=>a.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())),i&&f())},m=(l,r)=>{let a=o.conversations.find(g=>g.id===l);a&&(a.title=r,a.updatedAt=Date.now(),i&&f())},M=(l,r)=>{let a=o.conversations.find(g=>g.id===l);a&&(a.metadata={...a.metadata,...r},a.updatedAt=Date.now(),i&&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(a=>a.id===l);if(!r||r.messages.length<2)return r?.title||"\u65B0\u4F1A\u8BDD";try{let a={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:[a,...g],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return m(l,N),N}catch(a){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",a),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:C,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});
3
+ `);a=A.pop()||"";for(let f of A)if(f.trim()!==""){if(f.trim()==="data: [DONE]"){d&&(c=d),e.onDone(c);continue}try{let R=f.match(/^data: (.+)$/m);if(!R)continue;let h=JSON.parse(R[1]);e.onData(h),d=h.choices?.[0]?.finish_reason||void 0}catch(R){console.error("Error parsing SSE message:",R)}}}(a.trim()==="data: [DONE]"||t?.aborted)&&(t?.aborted&&(c="aborted"),e.onDone(c))}catch(o){if(t?.aborted)return;throw o}}function H(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 j(r){return!r.choices||!r.choices.length?"":r.choices[0].message?.content||""}var S=class extends E{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 i={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...t.options,stream:!1},u={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)};this.apiKey&&Object.assign(u.headers,{Authorization:`Bearer ${this.apiKey}`});let a=await fetch(`${this.baseURL}/chat/completions`,u);if(!a.ok){let c=await a.text();throw new Error(`HTTP error! status: ${a.status}, details: ${c}`)}return await a.json()}catch(i){throw D(i)}}async chatStream(t,i){let{signal:u,...a}=t.options||{};try{this.validateRequest(t);let c={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...a,stream:!0},d={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(c),signal:u};this.apiKey&&Object.assign(d.headers,{Authorization:`Bearer ${this.apiKey}`});let o=await fetch(`${this.baseURL}/chat/completions`,d);if(!o.ok){let p=await o.text();throw new Error(`HTTP error! status: ${o.status}, details: ${p}`)}await I(o,i,u)}catch(c){if(u?.aborted)return;i.onError(D(c))}}updateConfig(t){super.updateConfig(t),t.apiUrl&&(this.baseURL=t.apiUrl),t.apiKey&&(this.apiKey=t.apiKey),t.defaultModel&&(this.defaultModel=t.defaultModel)}};var b=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 S({...t,...e});case"openai":default:return new S(e)}}async chat(e){return this.provider.chat(e)}async chatStream(e,t){let i={...e,options:{...e.options,stream:!0}};return this.provider.chatStream(i,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 v=require("vue"),F=(c=>(c.INIT="init",c.PROCESSING="processing",c.STREAMING="streaming",c.FINISHED="finished",c.ABORTED="aborted",c.ERROR="error",c))(F||{}),P=["processing","streaming"],V=["finished","aborted","error"];function U(r){let{client:e,useStreamByDefault:t=!0,errorMessage:i="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:u=[]}=r,a=(0,v.ref)([...u]),c=(0,v.ref)(""),d=(0,v.ref)(t),o=null,p=(0,v.reactive)({status:"init",errorMsg:null}),m=s=>{let n=r.events?.onReceiveData,g=!1;if(n&&n(s,a,()=>{g=!0}),!g){let C={role:"assistant",content:s.choices[0].message.content};a.value.push(C)}},A=async s=>{let n=await e.chat({messages:(0,v.toRaw)(a.value),options:{stream:!1,signal:s.signal}});m(n)},f=s=>{let n=r.events?.onReceiveData,g=!1;if(n&&n(s,a,()=>{g=!0}),!g){a.value[a.value.length-1].role==="user"&&a.value.push({role:"assistant",content:""});let C=s.choices?.[0];C&&C.delta.content&&(a.value[a.value.length-1].content+=C.delta.content)}},R=async s=>{await e.chatStream({messages:(0,v.toRaw)(a.value),options:{stream:!0,signal:s.signal}},{onData:n=>{p.status="streaming",f(n)},onError:n=>{p.status="error",p.errorMsg=i,console.error("Stream request error:",n)},onDone:n=>{let g=r.events?.onFinish,C=!1;if(g&&g(n,{messages:a,messageState:p},()=>{C=!0}),!C){if(n==="aborted"||p.status==="aborted")return;p.status="finished"}}})},h=async()=>{p.status="processing",p.errorMsg=null,o=new AbortController;try{d.value?await R(o):await A(o)}catch(s){p.errorMsg=i,p.status="error",console.error("Send message error:",s)}finally{o=null}};return{messages:a,messageState:p,inputMessage:c,useStream:d,sendMessage:async(s=c.value,n=!0)=>{if(P.includes(p.status)||!s||typeof s=="string"&&!s.trim()||Array.isArray(s)&&s.length===0)return;let g={role:"user",content:s};a.value.push(g),n&&(c.value=""),await h()},send:async()=>{P.includes(p.status)||await h()},clearMessages:()=>{a.value=[],p.errorMsg=null},addMessage:s=>{Array.isArray(s)?a.value.push(...s):a.value.push(s)},abortRequest:()=>{o&&(o.abort(),o=null,p.status="aborted")},retryRequest:async s=>{s===0||!a.value[s]||a.value[s].role==="user"||(a.value.splice(s),await h())}}}var O=require("vue");var x=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 Q(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function X(r){let{client:e,storage:t=new x,autoSave:i=!0,allowEmpty:u=!1,useStreamByDefault:a=!0,errorMessage:c="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",events:d}=r,o=(0,O.reactive)({conversations:[],currentId:null,loading:!1}),p=!1,m=U({client:e,useStreamByDefault:a,errorMessage:c,initialMessages:[],events:{onReceiveData:d?.onReceiveData,onFinish:d?.onFinish}});(0,O.watch)(()=>m.messages.value,l=>{if(o.currentId&&l.length>0){let s=o.conversations.findIndex(n=>n.id===o.currentId);s!==-1&&(o.conversations[s].messages=[...l],o.conversations[s].updatedAt=Date.now(),i&&M())}},{deep:!0});let A=(l="\u65B0\u4F1A\u8BDD",s={})=>{if(!u&&m.messages.value.length===0&&o.currentId)return o.currentId;let n=Q(),g={id:n,title:l,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:s};return o.conversations.unshift(g),f(n),i&&M(),n},f=l=>{let s=o.conversations.find(n=>n.id===l);s&&(o.currentId=l,m.clearMessages(),s.messages.length>0&&s.messages.forEach(n=>m.addMessage(n)))},R=l=>{let s=o.conversations.findIndex(n=>n.id===l);s!==-1&&(o.conversations.splice(s,1),o.currentId===l&&(o.conversations.length>0?f(o.conversations[0].id):(o.currentId=null,m.clearMessages())),i&&M())},h=(l,s)=>{let n=o.conversations.find(g=>g.id===l);n&&(n.title=s,n.updatedAt=Date.now(),i&&M())},N=(l,s)=>{let n=o.conversations.find(g=>g.id===l);n&&(n.metadata={...n.metadata,...s},n.updatedAt=Date.now(),i&&M())},M=async()=>{try{await t.saveConversations(o.conversations)}catch(l){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",l)}},w=async()=>{o.loading=!0;try{let l=await t.loadConversations();o.conversations=l,l.length>0&&!o.currentId&&f(l[0].id),!p&&d?.onLoaded&&(p=!0,d.onLoaded(l))}catch(l){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",l)}finally{o.loading=!1}},_=async l=>{let s=o.conversations.find(n=>n.id===l);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"},g=s.messages.slice(0,Math.min(4,s.messages.length)),K=(await e.chat({messages:[n,...g],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return h(l,K),K}catch(n){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",n),s.title}},k=()=>o.currentId&&o.conversations.find(l=>l.id===o.currentId)||null;return w(),{state:o,messageManager:m,createConversation:A,switchConversation:f,deleteConversation:R,updateTitle:h,updateMetadata:N,saveConversations:M,loadConversations:w,generateTitle:_,getCurrentConversation:k}}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 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(a){return{type:a.type||"unknown_error",message:a.message||"\u672A\u77E5\u9519\u8BEF",statusCode:a.statusCode,originalError:a.originalError}}function y(a){if(!a.response)return f({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:a});if(a.response){let{status:e,data:o}=a.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:a}):e===429?f({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:a}):e>=500?f({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:a}):f({type:"unknown_error",message:o?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:a})}return a.code==="ECONNABORTED"?f({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:a}):f({type:"unknown_error",message:a.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:a})}async function A(a,e,o){let l=a.body?.getReader();if(!l)throw new Error("Response body is null");let g=new TextDecoder,r="";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});r+=d;let c=r.split(`
1
+ var A=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 K=(d=>(d.NETWORK_ERROR="network_error",d.AUTHENTICATION_ERROR="authentication_error",d.RATE_LIMIT_ERROR="rate_limit_error",d.SERVER_ERROR="server_error",d.MODEL_ERROR="model_error",d.TIMEOUT_ERROR="timeout_error",d.UNKNOWN_ERROR="unknown_error",d))(K||{}),q=(l=>(l.DATA="data",l.ERROR="error",l.DONE="done",l))(q||{});function M(n){return{type:n.type||"unknown_error",message:n.message||"\u672A\u77E5\u9519\u8BEF",statusCode:n.statusCode,originalError:n.originalError}}function I(n){if(!n.response)return M({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:n});if(n.response){let{status:e,data:o}=n.response;return e===401||e===403?M({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:e,originalError:n}):e===429?M({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:n}):e>=500?M({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:n}):M({type:"unknown_error",message:o?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:n})}return n.code==="ECONNABORTED"?M({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:n}):M({type:"unknown_error",message:n.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:n})}async function b(n,e,o){let l=n.body?.getReader();if(!l)throw new Error("Response body is null");let g=new TextDecoder,a="",c,d;o&&o.addEventListener("abort",()=>{l.cancel().catch(s=>console.error("Error cancelling reader:",s))},{once:!0});try{for(;;){if(o?.aborted){await l.cancel();break}let{done:s,value:p}=await l.read();if(s)break;let m=g.decode(p,{stream:!0});a+=m;let y=a.split(`
2
2
 
3
- `);r=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 v=JSON.parse(m[1]);e.onData(v)}catch(m){console.error("Error parsing SSE message:",m)}}}(r.trim()==="data: [DONE]"||o?.aborted)&&e.onDone()}catch(t){if(o?.aborted)return;throw t}}function D(a){return a.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 _(a){return!a.choices||!a.choices.length?"":a.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 r=await fetch(`${this.baseURL}/chat/completions`,g);if(!r.ok){let t=await r.text();throw new Error(`HTTP error! status: ${r.status}, details: ${t}`)}return await r.json()}catch(l){throw y(l)}}async chatStream(o,l){let{signal:g,...r}=o.options||{};try{this.validateRequest(o);let t={model:o.options?.model||this.config.defaultModel||this.defaultModel,messages:o.messages,...r,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(a){let{client:e,useStreamByDefault:o=!0,errorMessage:l="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:g=[]}=a,r=I([...g]),t=I(""),p=I(o),d=null,c=k({status:"init",errorMsg:null}),h=async s=>{let u={role:"assistant",content:(await e.chat({messages:T(r.value),options:{stream:!1,signal:s.signal}})).choices[0].message.content};r.value.push(u)},m=async s=>{await e.chatStream({messages:T(r.value),options:{stream:!0,signal:s.signal}},{onData:n=>{c.status="streaming",r.value[r.value.length-1].role==="user"&&r.value.push({role:"assistant",content:""});let u=n.choices?.[0];u&&u.delta.content&&(r.value[r.value.length-1].content+=u.delta.content)},onMessage:n=>{c.status="streaming",r.value[r.value.length-1].role==="user"&&r.value.push({role:"assistant",content:""}),"type"in n&&(r.value[r.value.length-1].messages||(r.value[r.value.length-1].messages=[]),r.value[r.value.length-1].messages.push(n))},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 h(d),c.status="finished"}catch(s){c.errorMsg=l,c.status="error",console.error("Send message error:",s)}finally{d=null}};return{messages:r,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};r.value.push(u),n&&(t.value=""),await v()},clearMessages:()=>{r.value=[],c.errorMsg=null},addMessage:s=>{r.value.push(s)},abortRequest:()=>{d&&(d.abort(),d=null,c.status="aborted")},retryRequest:async s=>{s===0||!r.value[s]||r.value[s].role==="user"||(r.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(a){let{client:e,storage:o=new b,autoSave:l=!0,useStreamByDefault:g=!0,errorMessage:r="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=a,t=B({conversations:[],currentId:null,loading:!1}),p=P({client:e,useStreamByDefault:g,errorMessage:r,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&&C())}},{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&&C(),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)))},h=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&&C())},m=(i,s)=>{let n=t.conversations.find(u=>u.id===i);n&&(n.title=s,n.updatedAt=Date.now(),l&&C())},v=(i,s)=>{let n=t.conversations.find(u=>u.id===i);n&&(n.metadata={...n.metadata,...s},n.updatedAt=Date.now(),l&&C())},C=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)),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}},w=()=>t.currentId&&t.conversations.find(i=>i.id===t.currentId)||null;return S(),{state:t,messageManager:p,createConversation:d,switchConversation:c,deleteConversation:h,updateTitle:m,updateMetadata:v,saveConversations:C,loadConversations:S,generateTitle:x,getCurrentConversation:w}}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};
3
+ `);a=y.pop()||"";for(let f of y)if(f.trim()!==""){if(f.trim()==="data: [DONE]"){d&&(c=d),e.onDone(c);continue}try{let v=f.match(/^data: (.+)$/m);if(!v)continue;let h=JSON.parse(v[1]);e.onData(h),d=h.choices?.[0]?.finish_reason||void 0}catch(v){console.error("Error parsing SSE message:",v)}}}(a.trim()==="data: [DONE]"||o?.aborted)&&(o?.aborted&&(c="aborted"),e.onDone(c))}catch(s){if(o?.aborted)return;throw s}}function B(n){return n.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 H(n){return!n.choices||!n.choices.length?"":n.choices[0].message?.content||""}var S=class extends A{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 c=await a.text();throw new Error(`HTTP error! status: ${a.status}, details: ${c}`)}return await a.json()}catch(l){throw I(l)}}async chatStream(o,l){let{signal:g,...a}=o.options||{};try{this.validateRequest(o);let c={model:o.options?.model||this.config.defaultModel||this.defaultModel,messages:o.messages,...a,stream:!0},d={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(c),signal:g};this.apiKey&&Object.assign(d.headers,{Authorization:`Bearer ${this.apiKey}`});let s=await fetch(`${this.baseURL}/chat/completions`,d);if(!s.ok){let p=await s.text();throw new Error(`HTTP error! status: ${s.status}, details: ${p}`)}await b(s,l,g)}catch(c){if(g?.aborted)return;l.onError(I(c))}}updateConfig(o){super.updateConfig(o),o.apiUrl&&(this.baseURL=o.apiUrl),o.apiKey&&(this.apiKey=o.apiKey),o.defaultModel&&(this.defaultModel=o.defaultModel)}};var x=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 S({...o,...e});case"openai":default:return new S(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 j,ref as O,toRaw as N}from"vue";var F=(c=>(c.INIT="init",c.PROCESSING="processing",c.STREAMING="streaming",c.FINISHED="finished",c.ABORTED="aborted",c.ERROR="error",c))(F||{}),_=["processing","streaming"],re=["finished","aborted","error"];function k(n){let{client:e,useStreamByDefault:o=!0,errorMessage:l="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:g=[]}=n,a=O([...g]),c=O(""),d=O(o),s=null,p=j({status:"init",errorMsg:null}),m=t=>{let r=n.events?.onReceiveData,u=!1;if(r&&r(t,a,()=>{u=!0}),!u){let C={role:"assistant",content:t.choices[0].message.content};a.value.push(C)}},y=async t=>{let r=await e.chat({messages:N(a.value),options:{stream:!1,signal:t.signal}});m(r)},f=t=>{let r=n.events?.onReceiveData,u=!1;if(r&&r(t,a,()=>{u=!0}),!u){a.value[a.value.length-1].role==="user"&&a.value.push({role:"assistant",content:""});let C=t.choices?.[0];C&&C.delta.content&&(a.value[a.value.length-1].content+=C.delta.content)}},v=async t=>{await e.chatStream({messages:N(a.value),options:{stream:!0,signal:t.signal}},{onData:r=>{p.status="streaming",f(r)},onError:r=>{p.status="error",p.errorMsg=l,console.error("Stream request error:",r)},onDone:r=>{let u=n.events?.onFinish,C=!1;if(u&&u(r,{messages:a,messageState:p},()=>{C=!0}),!C){if(r==="aborted"||p.status==="aborted")return;p.status="finished"}}})},h=async()=>{p.status="processing",p.errorMsg=null,s=new AbortController;try{d.value?await v(s):await y(s)}catch(t){p.errorMsg=l,p.status="error",console.error("Send message error:",t)}finally{s=null}};return{messages:a,messageState:p,inputMessage:c,useStream:d,sendMessage:async(t=c.value,r=!0)=>{if(_.includes(p.status)||!t||typeof t=="string"&&!t.trim()||Array.isArray(t)&&t.length===0)return;let u={role:"user",content:t};a.value.push(u),r&&(c.value=""),await h()},send:async()=>{_.includes(p.status)||await h()},clearMessages:()=>{a.value=[],p.errorMsg=null},addMessage:t=>{Array.isArray(t)?a.value.push(...t):a.value.push(t)},abortRequest:()=>{s&&(s.abort(),s=null,p.status="aborted")},retryRequest:async t=>{t===0||!a.value[t]||a.value[t].role==="user"||(a.value.splice(t),await h())}}}import{reactive as L,watch as $}from"vue";var w=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 G(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function le(n){let{client:e,storage:o=new w,autoSave:l=!0,allowEmpty:g=!1,useStreamByDefault:a=!0,errorMessage:c="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",events:d}=n,s=L({conversations:[],currentId:null,loading:!1}),p=!1,m=k({client:e,useStreamByDefault:a,errorMessage:c,initialMessages:[],events:{onReceiveData:d?.onReceiveData,onFinish:d?.onFinish}});$(()=>m.messages.value,i=>{if(s.currentId&&i.length>0){let t=s.conversations.findIndex(r=>r.id===s.currentId);t!==-1&&(s.conversations[t].messages=[...i],s.conversations[t].updatedAt=Date.now(),l&&R())}},{deep:!0});let y=(i="\u65B0\u4F1A\u8BDD",t={})=>{if(!g&&m.messages.value.length===0&&s.currentId)return s.currentId;let r=G(),u={id:r,title:i,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:t};return s.conversations.unshift(u),f(r),l&&R(),r},f=i=>{let t=s.conversations.find(r=>r.id===i);t&&(s.currentId=i,m.clearMessages(),t.messages.length>0&&t.messages.forEach(r=>m.addMessage(r)))},v=i=>{let t=s.conversations.findIndex(r=>r.id===i);t!==-1&&(s.conversations.splice(t,1),s.currentId===i&&(s.conversations.length>0?f(s.conversations[0].id):(s.currentId=null,m.clearMessages())),l&&R())},h=(i,t)=>{let r=s.conversations.find(u=>u.id===i);r&&(r.title=t,r.updatedAt=Date.now(),l&&R())},T=(i,t)=>{let r=s.conversations.find(u=>u.id===i);r&&(r.metadata={...r.metadata,...t},r.updatedAt=Date.now(),l&&R())},R=async()=>{try{await o.saveConversations(s.conversations)}catch(i){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",i)}},E=async()=>{s.loading=!0;try{let i=await o.loadConversations();s.conversations=i,i.length>0&&!s.currentId&&f(i[0].id),!p&&d?.onLoaded&&(p=!0,d.onLoaded(i))}catch(i){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",i)}finally{s.loading=!1}},D=async i=>{let t=s.conversations.find(r=>r.id===i);if(!t||t.messages.length<2)return t?.title||"\u65B0\u4F1A\u8BDD";try{let r={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=t.messages.slice(0,Math.min(4,t.messages.length)),U=(await e.chat({messages:[r,...u],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return h(i,U),U}catch(r){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",r),t.title}},P=()=>s.currentId&&s.conversations.find(i=>i.id===s.currentId)||null;return E(),{state:s,messageManager:m,createConversation:y,switchConversation:f,deleteConversation:v,updateTitle:h,updateMetadata:T,saveConversations:R,loadConversations:E,generateTitle:D,getCurrentConversation:P}}export{x as AIClient,A as BaseModelProvider,K as ErrorType,re as FinalStatus,_ as GeneratingStatus,w as LocalStorageStrategy,S as OpenAIProvider,F as STATUS,q as StreamEventType,H as extractTextFromResponse,B as formatMessages,b as handleSSEStream,le as useConversation,k as useMessage};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentiny/tiny-robot-kit",
3
- "version": "0.3.0-alpha.3",
3
+ "version": "0.3.0-alpha.30",
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": "f7a3d3bb307d48e5d5a677e4eed65ec0de4abd05"
29
+ "gitHead": "4eb76a9a50402e78053bce47f255043f9d995618"
30
30
  }