@opentiny/tiny-robot-kit 0.3.0-rc.4 → 0.3.0-rc.6

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
@@ -189,7 +189,7 @@ declare enum StreamEventType {
189
189
  interface StreamHandler {
190
190
  onData: (data: ChatCompletionStreamResponse) => void;
191
191
  onError: (error: AIAdapterError) => void;
192
- onDone: () => void;
192
+ onDone: (finishReason?: string) => void;
193
193
  }
194
194
 
195
195
  /**
@@ -331,6 +331,10 @@ interface UseMessageOptions {
331
331
  initialMessages?: ChatMessage[];
332
332
  events?: {
333
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;
334
338
  };
335
339
  }
336
340
  /**
@@ -417,6 +421,9 @@ interface ConversationState {
417
421
  /** 是否正在加载 */
418
422
  loading: boolean;
419
423
  }
424
+ type UseConversationEvents = UseMessageOptions['events'] & {
425
+ onLoaded?: (conversations: Conversation[]) => void;
426
+ };
420
427
  /**
421
428
  * useConversation选项接口
422
429
  */
@@ -433,7 +440,8 @@ interface UseConversationOptions {
433
440
  useStreamByDefault?: boolean;
434
441
  /** 错误消息模板 */
435
442
  errorMessage?: string;
436
- events?: UseMessageOptions['events'];
443
+ /** 事件回调 */
444
+ events?: UseConversationEvents;
437
445
  }
438
446
  /**
439
447
  * useConversation返回值接口
@@ -471,4 +479,4 @@ interface UseConversationReturn {
471
479
  */
472
480
  declare function useConversation(options: UseConversationOptions): UseConversationReturn;
473
481
 
474
- 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
@@ -189,7 +189,7 @@ declare enum StreamEventType {
189
189
  interface StreamHandler {
190
190
  onData: (data: ChatCompletionStreamResponse) => void;
191
191
  onError: (error: AIAdapterError) => void;
192
- onDone: () => void;
192
+ onDone: (finishReason?: string) => void;
193
193
  }
194
194
 
195
195
  /**
@@ -331,6 +331,10 @@ interface UseMessageOptions {
331
331
  initialMessages?: ChatMessage[];
332
332
  events?: {
333
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;
334
338
  };
335
339
  }
336
340
  /**
@@ -417,6 +421,9 @@ interface ConversationState {
417
421
  /** 是否正在加载 */
418
422
  loading: boolean;
419
423
  }
424
+ type UseConversationEvents = UseMessageOptions['events'] & {
425
+ onLoaded?: (conversations: Conversation[]) => void;
426
+ };
420
427
  /**
421
428
  * useConversation选项接口
422
429
  */
@@ -433,7 +440,8 @@ interface UseConversationOptions {
433
440
  useStreamByDefault?: boolean;
434
441
  /** 错误消息模板 */
435
442
  errorMessage?: string;
436
- events?: UseMessageOptions['events'];
443
+ /** 事件回调 */
444
+ events?: UseConversationEvents;
437
445
  }
438
446
  /**
439
447
  * useConversation返回值接口
@@ -471,4 +479,4 @@ interface UseConversationReturn {
471
479
  */
472
480
  declare function useConversation(options: UseConversationOptions): UseConversationReturn;
473
481
 
474
- 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 P=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var G=(o,e)=>{for(var t in e)P(o,t,{get:e[t],enumerable:!0})},W=(o,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let g of L(e))!F.call(o,g)&&g!==t&&P(o,g,{get:()=>e[g],enumerable:!(a=$(e,g))||a.enumerable});return o};var J=o=>W(P({},"__esModule",{value:!0}),o);var X={};G(X,{AIClient:()=>b,BaseModelProvider:()=>A,ErrorType:()=>K,FinalStatus:()=>z,GeneratingStatus:()=>N,LocalStorageStrategy:()=>x,OpenAIProvider:()=>y,STATUS:()=>j,StreamEventType:()=>q,extractTextFromResponse:()=>H,formatMessages:()=>B,handleSSEStream:()=>I,useConversation:()=>Q,useMessage:()=>U});module.exports=J(X);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 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 K=(s=>(s.NETWORK_ERROR="network_error",s.AUTHENTICATION_ERROR="authentication_error",s.RATE_LIMIT_ERROR="rate_limit_error",s.SERVER_ERROR="server_error",s.MODEL_ERROR="model_error",s.TIMEOUT_ERROR="timeout_error",s.UNKNOWN_ERROR="unknown_error",s))(K||{}),q=(a=>(a.DATA="data",a.ERROR="error",a.DONE="done",a))(q||{});function M(o){return{type:o.type||"unknown_error",message:o.message||"\u672A\u77E5\u9519\u8BEF",statusCode:o.statusCode,originalError:o.originalError}}function D(o){if(!o.response)return M({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:o});if(o.response){let{status:e,data:t}=o.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:o}):e===429?M({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:o}):e>=500?M({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:o}):M({type:"unknown_error",message:t?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:o})}return o.code==="ECONNABORTED"?M({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:o}):M({type:"unknown_error",message:o.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:o})}async function I(o,e,t){let a=o.body?.getReader();if(!a)throw new Error("Response body is null");let g=new TextDecoder,n="";t&&t.addEventListener("abort",()=>{a.cancel().catch(c=>console.error("Error cancelling reader:",c))},{once:!0});try{for(;;){if(t?.aborted){await a.cancel();break}let{done:c,value:s}=await a.read();if(c)break;let d=g.decode(s,{stream:!0});n+=d;let u=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=u.pop()||"";for(let C of u)if(C.trim()!==""){if(C.trim()==="data: [DONE]"){e.onDone();continue}try{let R=C.match(/^data: (.+)$/m);if(!R)continue;let S=JSON.parse(R[1]);e.onData(S)}catch(R){console.error("Error parsing SSE message:",R)}}}(n.trim()==="data: [DONE]"||t?.aborted)&&e.onDone()}catch(c){if(t?.aborted)return;throw c}}function B(o){return o.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(o){return!o.choices||!o.choices.length?"":o.choices[0].message?.content||""}var y=class extends A{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},g={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)};this.apiKey&&Object.assign(g.headers,{Authorization:`Bearer ${this.apiKey}`});let n=await fetch(`${this.baseURL}/chat/completions`,g);if(!n.ok){let c=await n.text();throw new Error(`HTTP error! status: ${n.status}, details: ${c}`)}return await n.json()}catch(a){throw D(a)}}async chatStream(t,a){let{signal:g,...n}=t.options||{};try{this.validateRequest(t);let c={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...n,stream:!0},s={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(s.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,s);if(!d.ok){let u=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${u}`)}await I(d,a,g)}catch(c){if(g?.aborted)return;a.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 y({...t,...e});case"openai":default:return new y(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 v=require("vue"),j=(c=>(c.INIT="init",c.PROCESSING="processing",c.STREAMING="streaming",c.FINISHED="finished",c.ABORTED="aborted",c.ERROR="error",c))(j||{}),N=["processing","streaming"],z=["finished","aborted","error"];function U(o){let{client:e,useStreamByDefault:t=!0,errorMessage:a="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:g=[]}=o,n=(0,v.ref)([...g]),c=(0,v.ref)(""),s=(0,v.ref)(t),d=null,u=(0,v.reactive)({status:"init",errorMsg:null}),C=r=>{let m=o.events?.onReceiveData,h=!1;if(m&&m(r,n,()=>{h=!0}),!h){let E={role:"assistant",content:r.choices[0].message.content};n.value.push(E)}},R=async r=>{let m=await e.chat({messages:(0,v.toRaw)(n.value),options:{stream:!1,signal:r.signal}});C(m)},S=r=>{let m=o.events?.onReceiveData,h=!1;if(m&&m(r,n,()=>{h=!0}),!h){n.value[n.value.length-1].role==="user"&&n.value.push({role:"assistant",content:""});let E=r.choices?.[0];E&&E.delta.content&&(n.value[n.value.length-1].content+=E.delta.content)}},O=async r=>{await e.chatStream({messages:(0,v.toRaw)(n.value),options:{stream:!0,signal:r.signal}},{onData:m=>{u.status="streaming",S(m)},onError:m=>{u.status="error",u.errorMsg=a,console.error("Stream request error:",m)},onDone:()=>{u.status="finished"}})},f=async()=>{u.status="processing",u.errorMsg=null,d=new AbortController;try{s.value?await O(d):await R(d),u.status="finished"}catch(r){u.errorMsg=a,u.status="error",console.error("Send message error:",r)}finally{d=null}};return{messages:n,messageState:u,inputMessage:c,useStream:s,sendMessage:async(r=c.value,m=!0)=>{if(N.includes(u.status)||!r||typeof r=="string"&&!r.trim()||Array.isArray(r)&&r.length===0)return;let h={role:"user",content:r};n.value.push(h),m&&(c.value=""),await f()},send:async()=>{N.includes(u.status)||await f()},clearMessages:()=>{n.value=[],u.errorMsg=null},addMessage:r=>{Array.isArray(r)?n.value.push(...r):n.value.push(r)},abortRequest:()=>{d&&(d.abort(),d=null,u.status="aborted")},retryRequest:async r=>{r===0||!n.value[r]||n.value[r].role==="user"||(n.value.splice(r),await f())}}}var w=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 V(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function Q(o){let{client:e,storage:t=new x,autoSave:a=!0,allowEmpty:g=!1,useStreamByDefault:n=!0,errorMessage:c="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=o,s=(0,w.reactive)({conversations:[],currentId:null,loading:!1}),d=U({client:e,useStreamByDefault:n,errorMessage:c,initialMessages:[],events:o.events});(0,w.watch)(()=>d.messages.value,i=>{if(s.currentId&&i.length>0){let p=s.conversations.findIndex(l=>l.id===s.currentId);p!==-1&&(s.conversations[p].messages=[...i],s.conversations[p].updatedAt=Date.now(),a&&f())}},{deep:!0});let u=(i="\u65B0\u4F1A\u8BDD",p={})=>{if(!g&&d.messages.value.length===0&&s.currentId)return s.currentId;let l=V(),r={id:l,title:i,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:p};return s.conversations.unshift(r),C(l),a&&f(),l},C=i=>{let p=s.conversations.find(l=>l.id===i);p&&(s.currentId=i,d.clearMessages(),p.messages.length>0&&p.messages.forEach(l=>d.addMessage(l)))},R=i=>{let p=s.conversations.findIndex(l=>l.id===i);p!==-1&&(s.conversations.splice(p,1),s.currentId===i&&(s.conversations.length>0?C(s.conversations[0].id):(s.currentId=null,d.clearMessages())),a&&f())},S=(i,p)=>{let l=s.conversations.find(r=>r.id===i);l&&(l.title=p,l.updatedAt=Date.now(),a&&f())},O=(i,p)=>{let l=s.conversations.find(r=>r.id===i);l&&(l.metadata={...l.metadata,...p},l.updatedAt=Date.now(),a&&f())},f=async()=>{try{await t.saveConversations(s.conversations)}catch(i){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",i)}},T=async()=>{s.loading=!0;try{let i=await t.loadConversations();s.conversations=i,i.length>0&&!s.currentId&&C(i[0].id)}catch(i){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",i)}finally{s.loading=!1}},_=async i=>{let p=s.conversations.find(l=>l.id===i);if(!p||p.messages.length<2)return p?.title||"\u65B0\u4F1A\u8BDD";try{let l={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"},r=p.messages.slice(0,Math.min(4,p.messages.length)),h=(await e.chat({messages:[l,...r],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return S(i,h),h}catch(l){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",l),p.title}},k=()=>s.currentId&&s.conversations.find(i=>i.id===s.currentId)||null;return T(),{state:s,messageManager:d,createConversation:u,switchConversation:C,deleteConversation:R,updateTitle:S,updateMetadata:O,saveConversations:f,loadConversations:T,generateTitle:_,getCurrentConversation:k}}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 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 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 k=(o=>(o.NETWORK_ERROR="network_error",o.AUTHENTICATION_ERROR="authentication_error",o.RATE_LIMIT_ERROR="rate_limit_error",o.SERVER_ERROR="server_error",o.MODEL_ERROR="model_error",o.TIMEOUT_ERROR="timeout_error",o.UNKNOWN_ERROR="unknown_error",o))(k||{}),K=(l=>(l.DATA="data",l.ERROR="error",l.DONE="done",l))(K||{});function R(s){return{type:s.type||"unknown_error",message:s.message||"\u672A\u77E5\u9519\u8BEF",statusCode:s.statusCode,originalError:s.originalError}}function b(s){if(!s.response)return R({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?R({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:e,originalError:s}):e===429?R({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:s}):e>=500?R({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:e,originalError:s}):R({type:"unknown_error",message:t?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${e}`,statusCode:e,originalError:s})}return s.code==="ECONNABORTED"?R({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:s}):R({type:"unknown_error",message:s.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:s})}async function x(s,e,t){let l=s.body?.getReader();if(!l)throw new Error("Response body is null");let m=new TextDecoder,n="";t&&t.addEventListener("abort",()=>{l.cancel().catch(c=>console.error("Error cancelling reader:",c))},{once:!0});try{for(;;){if(t?.aborted){await l.cancel();break}let{done:c,value:o}=await l.read();if(c)break;let d=m.decode(o,{stream:!0});n+=d;let u=n.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
- `);n=u.pop()||"";for(let C of u)if(C.trim()!==""){if(C.trim()==="data: [DONE]"){e.onDone();continue}try{let v=C.match(/^data: (.+)$/m);if(!v)continue;let M=JSON.parse(v[1]);e.onData(M)}catch(v){console.error("Error parsing SSE message:",v)}}}(n.trim()==="data: [DONE]"||t?.aborted)&&e.onDone()}catch(c){if(t?.aborted)return;throw c}}function q(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 B(s){return!s.choices||!s.choices.length?"":s.choices[0].message?.content||""}var y=class extends A{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 l={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...t.options,stream:!1},m={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)};this.apiKey&&Object.assign(m.headers,{Authorization:`Bearer ${this.apiKey}`});let n=await fetch(`${this.baseURL}/chat/completions`,m);if(!n.ok){let c=await n.text();throw new Error(`HTTP error! status: ${n.status}, details: ${c}`)}return await n.json()}catch(l){throw b(l)}}async chatStream(t,l){let{signal:m,...n}=t.options||{};try{this.validateRequest(t);let c={model:t.options?.model||this.config.defaultModel||this.defaultModel,messages:t.messages,...n,stream:!0},o={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(c),signal:m};this.apiKey&&Object.assign(o.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,o);if(!d.ok){let u=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${u}`)}await x(d,l,m)}catch(c){if(m?.aborted)return;l.onError(b(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 w=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 y({...t,...e});case"openai":default:return new y(e)}}async chat(e){return this.provider.chat(e)}async chatStream(e,t){let l={...e,options:{...e.options,stream:!0}};return this.provider.chatStream(l,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)}};import{reactive as H,ref as O,toRaw as N}from"vue";var j=(c=>(c.INIT="init",c.PROCESSING="processing",c.STREAMING="streaming",c.FINISHED="finished",c.ABORTED="aborted",c.ERROR="error",c))(j||{}),U=["processing","streaming"],se=["finished","aborted","error"];function _(s){let{client:e,useStreamByDefault:t=!0,errorMessage:l="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",initialMessages:m=[]}=s,n=O([...m]),c=O(""),o=O(t),d=null,u=H({status:"init",errorMsg:null}),C=r=>{let g=s.events?.onReceiveData,h=!1;if(g&&g(r,n,()=>{h=!0}),!h){let S={role:"assistant",content:r.choices[0].message.content};n.value.push(S)}},v=async r=>{let g=await e.chat({messages:N(n.value),options:{stream:!1,signal:r.signal}});C(g)},M=r=>{let g=s.events?.onReceiveData,h=!1;if(g&&g(r,n,()=>{h=!0}),!h){n.value[n.value.length-1].role==="user"&&n.value.push({role:"assistant",content:""});let S=r.choices?.[0];S&&S.delta.content&&(n.value[n.value.length-1].content+=S.delta.content)}},E=async r=>{await e.chatStream({messages:N(n.value),options:{stream:!0,signal:r.signal}},{onData:g=>{u.status="streaming",M(g)},onError:g=>{u.status="error",u.errorMsg=l,console.error("Stream request error:",g)},onDone:()=>{u.status="finished"}})},f=async()=>{u.status="processing",u.errorMsg=null,d=new AbortController;try{o.value?await E(d):await v(d),u.status="finished"}catch(r){u.errorMsg=l,u.status="error",console.error("Send message error:",r)}finally{d=null}};return{messages:n,messageState:u,inputMessage:c,useStream:o,sendMessage:async(r=c.value,g=!0)=>{if(U.includes(u.status)||!r||typeof r=="string"&&!r.trim()||Array.isArray(r)&&r.length===0)return;let h={role:"user",content:r};n.value.push(h),g&&(c.value=""),await f()},send:async()=>{U.includes(u.status)||await f()},clearMessages:()=>{n.value=[],u.errorMsg=null},addMessage:r=>{Array.isArray(r)?n.value.push(...r):n.value.push(r)},abortRequest:()=>{d&&(d.abort(),d=null,u.status="aborted")},retryRequest:async r=>{r===0||!n.value[r]||n.value[r].role==="user"||(n.value.splice(r),await f())}}}import{reactive as $,watch as L}from"vue";var T=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 F(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}function ie(s){let{client:e,storage:t=new T,autoSave:l=!0,allowEmpty:m=!1,useStreamByDefault:n=!0,errorMessage:c="\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"}=s,o=$({conversations:[],currentId:null,loading:!1}),d=_({client:e,useStreamByDefault:n,errorMessage:c,initialMessages:[],events:s.events});L(()=>d.messages.value,a=>{if(o.currentId&&a.length>0){let p=o.conversations.findIndex(i=>i.id===o.currentId);p!==-1&&(o.conversations[p].messages=[...a],o.conversations[p].updatedAt=Date.now(),l&&f())}},{deep:!0});let u=(a="\u65B0\u4F1A\u8BDD",p={})=>{if(!m&&d.messages.value.length===0&&o.currentId)return o.currentId;let i=F(),r={id:i,title:a,createdAt:Date.now(),updatedAt:Date.now(),messages:[],metadata:p};return o.conversations.unshift(r),C(i),l&&f(),i},C=a=>{let p=o.conversations.find(i=>i.id===a);p&&(o.currentId=a,d.clearMessages(),p.messages.length>0&&p.messages.forEach(i=>d.addMessage(i)))},v=a=>{let p=o.conversations.findIndex(i=>i.id===a);p!==-1&&(o.conversations.splice(p,1),o.currentId===a&&(o.conversations.length>0?C(o.conversations[0].id):(o.currentId=null,d.clearMessages())),l&&f())},M=(a,p)=>{let i=o.conversations.find(r=>r.id===a);i&&(i.title=p,i.updatedAt=Date.now(),l&&f())},E=(a,p)=>{let i=o.conversations.find(r=>r.id===a);i&&(i.metadata={...i.metadata,...p},i.updatedAt=Date.now(),l&&f())},f=async()=>{try{await t.saveConversations(o.conversations)}catch(a){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",a)}},I=async()=>{o.loading=!0;try{let a=await t.loadConversations();o.conversations=a,a.length>0&&!o.currentId&&C(a[0].id)}catch(a){console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",a)}finally{o.loading=!1}},P=async a=>{let p=o.conversations.find(i=>i.id===a);if(!p||p.messages.length<2)return p?.title||"\u65B0\u4F1A\u8BDD";try{let i={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"},r=p.messages.slice(0,Math.min(4,p.messages.length)),h=(await e.chat({messages:[i,...r],options:{stream:!1,max_tokens:30}})).choices[0].message.content.trim();return M(a,h),h}catch(i){return console.error("\u751F\u6210\u6807\u9898\u5931\u8D25:",i),p.title}},D=()=>o.currentId&&o.conversations.find(a=>a.id===o.currentId)||null;return I(),{state:o,messageManager:d,createConversation:u,switchConversation:C,deleteConversation:v,updateTitle:M,updateMetadata:E,saveConversations:f,loadConversations:I,generateTitle:P,getCurrentConversation:D}}export{w as AIClient,A as BaseModelProvider,k as ErrorType,se as FinalStatus,U as GeneratingStatus,T as LocalStorageStrategy,y as OpenAIProvider,j as STATUS,K as StreamEventType,B as extractTextFromResponse,q as formatMessages,x as handleSSEStream,ie as useConversation,_ 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-rc.4",
3
+ "version": "0.3.0-rc.6",
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": "ee2327d3e05d22d854986231fe97b3274dc75439"
29
+ "gitHead": "33faba113d39072692e56743771e5d97ccbba15c"
30
30
  }