@opentiny/tiny-robot-kit 0.4.0-alpha.1 → 0.4.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +59 -262
- package/dist/index.d.mts +427 -49
- package/dist/index.d.ts +427 -49
- package/dist/index.js +4 -2
- package/dist/index.mjs +4 -2
- package/package.json +31 -2
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
`);a=A.pop()||"";for(let w of A)if(w.trim()!==""&&w.startsWith("data: ")){let v=w.slice(6);if(v==="[DONE]")return;try{yield JSON.parse(v)}catch(T){console.warn("Failed to parse SSE data:",v,T)}}}}finally{s?.removeEventListener("abort",i),t.releaseLock()}}import{computed as ye,ref as te,watch as Ce}from"vue";import{computed as ce,reactive as ue,ref as j,watch as ge}from"vue";var K=(e={})=>{let{fallbackRole:n="assistant",...t}=e;return{name:"fallbackRole",...t,onBeforeRequest(s){let{requestBody:r,messages:a}=s;return r.messages=a.map(i=>({...i,role:i.role||n})),t.onBeforeRequest?.(s)}}};var z=(e={})=>{let{continueContent:n="Please continue with your previous answer.",...t}=e;return{name:"length",...t,onAfterRequest:async s=>{let{lastChoice:r,appendMessage:a,requestNext:i}=s;return r?.finish_reason==="length"&&(a({role:"user",content:n}),i()),t.onAfterRequest?.(s)}}};var J=(e={})=>({name:"thinking",...e,onCompletionChunk(n){let{choice:t,currentMessage:s}=n,a=typeof(t?.message?.reasoning_content||t?.delta?.reasoning_content)=="string";return s.state?s.state.thinking=a:s.state={thinking:a},e.onCompletionChunk?.(n)},onTurnEnd(n){let t=n.currentTurn.slice(-1)[0];return t?.state&&(t.state.thinking=void 0),e.onTurnEnd?.(n)}});import{reactive as re}from"vue";var I=class extends Error{constructor(n){super(n),this.name="AbortError"}};function oe(e){if(e.aborted)return{promise:Promise.reject(new I(String(e.reason??"Aborted"))),cleanup:()=>{}};let n=null;return{promise:new Promise((r,a)=>{n=()=>{a(new I(String(e.reason??"Aborted")))},e.addEventListener("abort",n,{once:!0})}),cleanup:()=>{n&&(e.removeEventListener("abort",n),n=null)}}}function Q(e,n){let{promise:t,cleanup:s}=oe(n);return Promise.race([e,t]).finally(s)}function Y(e,n){let t={};for(let s of n)s in e&&(t[s]=e[s]);return t}async function*G(e){if(X(e)){yield*e;return}let n=await e;if(X(n)){yield*n;return}yield n}function X(e){return e&&typeof e=="object"&&typeof e[Symbol.asyncIterator]=="function"}var H=e=>typeof e=="object"&&e!==null,$=e=>H(e)&&typeof e.index=="number",N=(e,n)=>{for(let[t,s]of Object.entries(n)){let r=e[t];if(r)if(typeof r=="string"&&typeof s=="string")t==="type"&&r||(e[t]=r+s);else if(Array.isArray(r)&&Array.isArray(s))if(r.every(a=>$(a))&&s.every(a=>$(a))){let a=new Map(r.map(d=>[d.index,d])),i=new Map(s.map(d=>[d.index,d]));for(let[d,M]of i)if(a.has(d)){let A=a.get(d);a.set(d,N(A,M))}else a.set(d,M);let u=Math.max(...Array.from(a.keys()),-1)+1,y=u>r.length?Array.from({length:u}):r;for(let[d,M]of a)y[d]=M;e[t]=y}else e[t]=[...r,...s];else H(r)&&H(s)&&(e[t]=N(r,s));else e[t]=s}return e};function ae(e,n){let t=[];for(let s=0;s<e.length;s++){let r=e[s];if(r.role==="assistant"&&r.tool_calls&&r.tool_calls.length>0){let a=new Set(r.tool_calls.map(y=>y.id)),i=new Set;for(let y=s+1;y<e.length;y++){let d=e[y];d.role==="tool"&&d.tool_call_id&&a.has(d.tool_call_id)&&i.add(d.tool_call_id)}let u=r.tool_calls.map(y=>y.id).filter(y=>!i.has(y));u.length>0&&t.push({insertAfterIndex:s,missingToolCallIds:u})}}for(let s=t.length-1;s>=0;s--){let{insertAfterIndex:r,missingToolCallIds:a}=t[s],i=a.map(u=>({role:"tool",tool_call_id:u,content:n}));e.splice(r+1,0,...i)}}var ie="remove";function le(e,n,t,s){let r=e.filter(i=>i[t]),a=new Set(r.flatMap(i=>i.tool_calls?.map(u=>u.id)??[]));if(n===ie)for(let i=e.length-1;i>=0;i--){let u=e[i];(u[t]||u[s]||u.tool_call_id&&a.has(u.tool_call_id))&&e.splice(i,1)}else if(n===!0)for(let i of e)(i[t]||i.tool_call_id&&a.has(i.tool_call_id))&&(i[s]=!0,delete i[t])}var Re=e=>{let{getTools:n,beforeCallTools:t,callTool:s,onToolCallStart:r,onToolCallEnd:a,toolCallCancelledContent:i="Tool call cancelled.",toolCallFailedContent:u="Tool call failed.",autoFillMissingToolMessages:y=!1,excludeToolMessagesNextTurn:d=!1,...M}=e,A=Symbol("doNotSendNextTurn"),w=Symbol("doNotSend"),v=(...C)=>{let[p,{primaryMessage:o}]=C;o.state.toolCall[p.id].status="running",r?.(...C)},T=(...C)=>{let[p,{status:o,primaryMessage:l}]=C;l.state.toolCall[p.id].status=o,a?.(...C)};return{name:"tool",...M,onTurnStart:C=>{let{messages:p}=C;return y&&ae(p,i),d&&le(p,d,A,w),M.onTurnStart?.(C)},onBeforeRequest:async C=>{let{messages:p,requestBody:o}=C;d===!0&&(o.messages=p.filter(g=>!g[w]));let l=await n?.();return l&&l.length>0&&(o.tools=l),M.onBeforeRequest?.(C)},onAfterRequest:async C=>{let{currentMessage:p,lastChoice:o,appendMessage:l,abortSignal:g,setRequestState:f,requestNext:x}=C;if(o?.finish_reason!=="tool_calls"||!p.tool_calls?.length)return;d&&(p[A]=!0),f("processing","calling-tools"),await t?.(p.tool_calls,{...C,currentMessage:p});let E=p.tool_calls.map(async S=>{let q=Math.floor(Date.now()/1e3),O=re({role:"tool",tool_call_id:S.id,content:"",metadata:{createdAt:q,updatedAt:q}});l(O);let c={...C,primaryMessage:p,toolMessage:O};v(S,c);try{let h=s(S,c),b=G(h);for await(let _ of b){if(typeof _=="string")O.content+=_;else{let m={};try{m=JSON.parse(O.content||"{}")}catch(R){console.warn(R)}O.content=JSON.stringify(N(m,_))}O.metadata.updatedAt=Math.floor(Date.now()/1e3)}T(S,{...c,status:"success"})}catch(h){let b=h instanceof Error?h:new Error(String(h));if(g.aborted){T(S,{...c,status:"cancelled",error:b});return}console.error(h),O.content.length===0&&(O.content=u),T(S,{...c,status:"failed",error:b})}});return await Promise.all(E),x(),M.onAfterRequest?.(C)},onCompletionChunk:C=>{var o,l,g;let{currentMessage:p}=C;if(Array.isArray(p.tool_calls))for(let f of p.tool_calls)p.state?.toolCall?.[f.id]?.status||(p.state??(p.state={}),(o=p.state).toolCall??(o.toolCall={}),(l=p.state.toolCall)[g=f.id]??(l[g]={}));return M.onCompletionChunk?.(C)}}};var fe=e=>{let n=[];for(let t of e){if(t.name){let s=n.findIndex(r=>r.name===t.name);s!==-1&&n.splice(s,1)}n.push(t)}return n},V=e=>{let{initialMessages:n=[],requestMessageFields:t=["role","content","tool_calls","tool_call_id"],plugins:s=[],onCompletionChunk:r}=e,a=j("idle"),i=j(void 0),u=j(n),y=j(e.responseProvider),d=null,M=[],A={},w=[K(),J(),z()],v=fe(w.concat(s)),T=ce(()=>a.value==="processing"),C=async c=>{if(!c||!c.trim()){console.warn("Cannot send empty message");return}if(T.value){console.warn("Cannot send message while processing is in progress");return}let h=Math.floor(Date.now()/1e3);u.value.push({role:"user",content:c.trim(),metadata:{createdAt:h,updatedAt:h}}),M.push(u.value[u.value.length-1]),await E()},p=async(...c)=>{if(T.value){console.warn("Cannot send message while processing is in progress");return}u.value.push(...c),M.push(...c),await E()},o=c=>c.map(h=>Y(h,t)),l=(c,h)=>{a.value=c,c==="processing"?i.value=h||"requesting":i.value=void 0},g=c=>{Object.assign(A,c)},f=()=>({messages:u.value,currentTurn:M,requestState:a.value,processingState:i.value,requestMessageFields:t,plugins:v,setRequestState:l,customContext:A,setCustomContext:g}),x=async(c,h)=>{l("processing","requesting");let b=new Proxy({messages:o(u.value)},{set(k,P,U){return P==="messages"?(k.messages=o(U),!0):(k[P]=U,!0)}}),_=f();for(let k of v.filter(P=>!P.disabled))await k.onBeforeRequest?.({..._,abortSignal:h,requestBody:b});let m=ue({role:"",content:"",loading:!0});O(m);let R,W=c(b,h),D=G(W);for await(let k of D){l("processing","completing"),m.loading&&(m.loading=void 0);let P=k.choices?.find(F=>F.index===0);if(P){R=P;let F=()=>{m.metadata||(m.metadata={});let{created:B,...ne}=k;m.metadata.createdAt=B,m.metadata.updatedAt=Math.floor(Date.now()/1e3),Object.assign(m.metadata,ne),N(m,P.message||P.delta)};if(r){let B=f();r({...B,abortSignal:h,chunk:k,currentMessage:m},F)}else F()}let U=f();for(let F of v.filter(B=>!B.disabled))F.onCompletionChunk?.({...U,abortSignal:h,chunk:k,choice:P,currentMessage:m})}await q(m,c,h,R)},E=async()=>{let c=new AbortController;d=c;let h=y.value;A={};try{l("processing","requesting");let b=f();for(let m of v.filter(R=>!R.disabled))await m.onTurnStart?.({...b,abortSignal:c.signal});try{await x(h,c.signal),l("completed")}catch(m){if(c.signal.aborted||m instanceof I||m instanceof Error&&m.name==="AbortError")l("aborted");else throw m}let _=f();for(let m of v.filter(R=>!R.disabled))await m.onTurnEnd?.({..._,abortSignal:c.signal})}catch(b){l("error");let _=f();for(let m of v.filter(R=>!R.disabled))m.onError?.({..._,abortSignal:c.signal,error:b});throw b}finally{d=null,M.slice(-1)[0]&&(M.slice(-1)[0].loading=void 0),M=[]}},S=async()=>{d?.abort(),T.value&&await new Promise(c=>{let h=ge(T,b=>{b||(h(),c())},{immediate:!0})})},q=async(c,h,b,_)=>{let m=!1,R=f(),W=v.filter(D=>!D.disabled).map(D=>{if(!D.onAfterRequest)return null;let k=U=>{O(U)},P=()=>{m=!0};return D.onAfterRequest({...R,abortSignal:b,currentMessage:c,lastChoice:_,appendMessage:k,requestNext:P})}).filter(D=>D!==null);await Q(Promise.all(W),b),m&&await x(h,b)},O=c=>{let h=Array.isArray(c)?c:[c];u.value.push(...h),M.push(...h)};return{requestState:a,processingState:i,messages:u,responseProvider:y,isProcessing:T,sendMessage:C,send:p,abortRequest:S}};import{isRef as de,toValue as pe}from"vue";function ee(e,n=200,t=!1,s=!0,r=!1){return me(he(n,t,s,r),e)}function me(e,n){function t(...s){return new Promise((r,a)=>{Promise.resolve(e(()=>n.apply(this,s),{fn:n,thisArg:this,args:s})).then(r).catch(a)})}return t}var Z=()=>{};function he(...e){let n=0,t,s=!0,r=Z,a,i,u,y,d;!de(e[0])&&typeof e[0]=="object"?{delay:i,trailing:u=!0,leading:y=!0,rejectOnCancel:d=!1}=e[0]:[i,u=!0,y=!0,d=!1]=e;let M=()=>{t&&(clearTimeout(t),t=void 0,r(),r=Z)};return w=>{let v=pe(i),T=Date.now()-n,C=()=>a=w();return M(),v<=0?(n=Date.now(),C()):(T>v?(n=Date.now(),(y||!s)&&C()):u&&(a=new Promise((p,o)=>{r=d?o:p,t=setTimeout(()=>{n=Date.now(),s=!0,p(C()),M()},Math.max(0,v-T))})),!y&&!t&&(t=setTimeout(()=>s=!0,v)),s=!1,a)}}var Be=e=>{let n=te([]),t=new Map,s=new Map,r=te(null),a=ye(()=>{let o=r.value;if(!o)return null;let l=n.value.find(f=>f.id===o);if(!l)return null;let g=t.get(o);return g?{...l,engine:g}:null}),i=o=>{if(!e.storage?.saveMessages)return;let l=o||r.value,g=n.value.find(x=>x.id===l);if(!g)return;g.updatedAt=Date.now(),e.storage?.saveConversation?.(g);let f=t.get(g.id);f&&e.storage.saveMessages(g.id,f.messages.value)},u=(o,l)=>{if(!e.autoSaveMessages||!e.storage?.saveMessages)return;let g=s.get(o);g&&g();let f=e.autoSaveThrottle??1e3,x=ee(()=>{i(o)},f,!0,!0),E=Ce(l.messages,x,{deep:!0});s.set(o,E)},y=o=>{let l=s.get(o);l&&(l(),s.delete(o))};e.storage?.loadConversations&&Promise.resolve(e.storage.loadConversations()).then(o=>{n.value=o}).catch(o=>{console.error("[useConversation] loadConversations failed:",o)});let d=async(o,l)=>{let g=t.get(o);if(g)return g;let f=l?.initialMessages??e.useMessageOptions.initialMessages??[];if(e.storage?.loadMessages)try{f=await e.storage.loadMessages(o)}catch(E){console.error("[useConversation] loadMessages failed:",E)}let x=V({...e.useMessageOptions,...l,initialMessages:f});return t.set(o,x),u(o,x),x};function M(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}let A=o=>{let{id:l=M(),title:g,metadata:f,useMessageOptions:x}=o||{},E=Date.now(),S={id:l,title:g,createdAt:E,updatedAt:E,metadata:f};n.value.unshift(S);let q=V({...e.useMessageOptions,...x});return t.set(l,q),u(l,q),e.storage?.saveConversation?.(S),e.storage?.saveMessages?.(l,q.messages.value),r.value=l,a.value},w=async o=>o?r.value===o?a.value:n.value.find(g=>g.id===o)?(await d(o),t.forEach((g,f)=>{if(f===o)return;g.isProcessing?.value||(y(f),t.delete(f))}),r.value=o,a.value):null:null;return{conversations:n,activeConversationId:r,activeConversation:a,createConversation:A,switchConversation:w,deleteConversation:async o=>{let l=n.value.findIndex(f=>f.id===o);if(l===-1)return;if(await t.get(o)?.abortRequest(),y(o),t.delete(o),n.value.splice(l,1),e.storage?.deleteConversation?.(o),r.value===o){let f=n.value[0];f?await w(f.id):r.value=null}},updateConversationTitle:(o,l)=>{let g=n.value.find(f=>f.id===o);g&&(g.title=l,g.updatedAt=Date.now(),e.storage?.saveConversation?.(g))},saveMessages:i,sendMessage:o=>{a.value?.engine.sendMessage(o)},abortActiveRequest:async()=>{await a.value?.engine.abortRequest()}}};export{ie as EXCLUDE_MODE_REMOVE,se as createSSEStreamGenerator,K as fallbackRolePlugin,z as lengthPlugin,J as thinkingPlugin,Re as toolPlugin,Be as useConversation,V as useMessage};
|
|
1
|
+
var G=class{constructor(t){this.config=t}updateConfig(t){this.config={...this.config,...t}}getConfig(){return{...this.config}}validateRequest(t){if(!t.messages||!Array.isArray(t.messages)||t.messages.length===0)throw new Error("\u8BF7\u6C42\u5FC5\u987B\u5305\u542B\u81F3\u5C11\u4E00\u6761\u6D88\u606F");for(let e of t.messages)if(!e.role||!e.content)throw new Error("\u6BCF\u6761\u6D88\u606F\u5FC5\u987B\u5305\u542B\u89D2\u8272\u548C\u5185\u5BB9")}};var Me=(c=>(c.NETWORK_ERROR="network_error",c.AUTHENTICATION_ERROR="authentication_error",c.RATE_LIMIT_ERROR="rate_limit_error",c.SERVER_ERROR="server_error",c.MODEL_ERROR="model_error",c.TIMEOUT_ERROR="timeout_error",c.UNKNOWN_ERROR="unknown_error",c))(Me||{}),be=(n=>(n.DATA="data",n.ERROR="error",n.DONE="done",n))(be||{});function F(o){return{type:o.type||"unknown_error",message:o.message||"\u672A\u77E5\u9519\u8BEF",statusCode:o.statusCode,originalError:o.originalError}}function te(o){if(!o.response)return F({type:"network_error",message:"\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5",originalError:o});if(o.response){let{status:t,data:e}=o.response;return t===401||t===403?F({type:"authentication_error",message:"\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684API\u5BC6\u94A5",statusCode:t,originalError:o}):t===429?F({type:"rate_limit_error",message:"\u8D85\u51FAAPI\u8C03\u7528\u9650\u5236\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:t,originalError:o}):t>=500?F({type:"server_error",message:"\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",statusCode:t,originalError:o}):F({type:"unknown_error",message:e?.error?.message||`\u8BF7\u6C42\u5931\u8D25\uFF0C\u72B6\u6001\u7801: ${t}`,statusCode:t,originalError:o})}return o.code==="ECONNABORTED"?F({type:"timeout_error",message:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",originalError:o}):F({type:"unknown_error",message:o.message||"\u53D1\u751F\u672A\u77E5\u9519\u8BEF",originalError:o})}async function ne(o,t,e){let n=o.body?.getReader();if(!n)throw new Error("Response body is null");let s=new TextDecoder,r="",a,c;e&&e.addEventListener("abort",()=>{n.cancel().catch(d=>console.error("Error cancelling reader:",d))},{once:!0});try{for(;;){if(e?.aborted){await n.cancel();break}let{done:d,value:f}=await n.read();if(d)break;let v=s.decode(f,{stream:!0});r+=v;let R=r.split(`
|
|
2
|
+
|
|
3
|
+
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""){if(x.trim()==="data: [DONE]"){c&&(a=c),t.onDone(a);continue}try{let A=x.match(/^data: (.+)$/m);if(!A)continue;let M=JSON.parse(A[1]);t.onData(M),c=M.choices?.[0]?.finish_reason||void 0}catch(A){console.error("Error parsing SSE message:",A)}}}(r.trim()==="data: [DONE]"||e?.aborted)&&(e?.aborted&&(a="aborted"),t.onDone(a))}catch(d){if(e?.aborted)return;throw d}}function Re(o){return o.map(t=>typeof t=="object"&&"role"in t&&"content"in t?{role:t.role,content:String(t.content),...t.name?{name:t.name}:{}}:typeof t=="string"?{role:"user",content:t}:{role:"user",content:String(t)})}function xe(o){return!o.choices||!o.choices.length?"":o.choices[0].message?.content||""}function oe(o="The operation was aborted"){let t=new Error(o);return t.name="AbortError",t}async function*Ae(o,t={}){let e=o.body?.getReader();if(!e)throw new Error("ReadableStream not supported");let{signal:n}=t,s=new TextDecoder,r="",a=()=>{e.cancel()};n?.addEventListener("abort",a);try{for(;;){if(n?.aborted)throw oe();let c;try{c=await e.read()}catch(x){throw n?.aborted?oe():x}let{done:d,value:f}=c;if(d){if(n?.aborted)throw oe();return}let v=s.decode(f,{stream:!0});r+=v;let R=r.split(`
|
|
4
|
+
`);r=R.pop()||"";for(let x of R)if(x.trim()!==""&&x.startsWith("data: ")){let A=x.slice(6);if(A==="[DONE]")return;try{yield JSON.parse(A)}catch(M){console.warn("Failed to parse SSE data:",A,M)}}}}finally{n?.removeEventListener("abort",a),e.releaseLock()}}var j=class extends G{constructor(e){super(e);this.defaultModel="gpt-3.5-turbo";this.baseURL=e.apiUrl||"https://api.openai.com/v1",this.apiKey=e.apiKey||"",e.defaultModel&&(this.defaultModel=e.defaultModel),this.apiKey||console.warn("API key is not provided. Authentication will likely fail.")}async chat(e){try{this.validateRequest(e);let n={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...e.options,stream:!1},s={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)};this.apiKey&&Object.assign(s.headers,{Authorization:`Bearer ${this.apiKey}`});let r=await fetch(`${this.baseURL}/chat/completions`,s);if(!r.ok){let a=await r.text();throw new Error(`HTTP error! status: ${r.status}, details: ${a}`)}return await r.json()}catch(n){throw te(n)}}async chatStream(e,n){let{signal:s,...r}=e.options||{};try{this.validateRequest(e);let a={model:e.options?.model||this.config.defaultModel||this.defaultModel,messages:e.messages,...r,stream:!0},c={method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream"},body:JSON.stringify(a),signal:s};this.apiKey&&Object.assign(c.headers,{Authorization:`Bearer ${this.apiKey}`});let d=await fetch(`${this.baseURL}/chat/completions`,c);if(!d.ok){let f=await d.text();throw new Error(`HTTP error! status: ${d.status}, details: ${f}`)}await ne(d,n,s)}catch(a){if(s?.aborted)return;n.onError(te(a))}}updateConfig(e){super.updateConfig(e),e.apiUrl&&(this.baseURL=e.apiUrl),e.apiKey&&(this.apiKey=e.apiKey),e.defaultModel&&(this.defaultModel=e.defaultModel)}};var se=class{constructor(t){this.config=t,this.provider=this.createProvider(t)}createProvider(t){if(t.provider==="custom"&&"providerImplementation"in t)return t.providerImplementation;if(t.provider==="deepseek"){let e={defaultModel:"deepseek-chat",apiUrl:"https://api.deepseek.com/v1"};return new j({...e,...t})}else return new j(t)}async chat(t){return this.provider.chat(t)}async chatStream(t,e){let n={...t,options:{...t.options,stream:!0}};return this.provider.chatStream(n,e)}getConfig(){return{...this.config}}updateConfig(t){this.config={...this.config,...t},t.provider&&t.provider!==this.config.provider?this.provider=this.createProvider(this.config):this.provider.updateConfig(this.config)}};import{toRaw as we}from"vue";function V(o,t=new WeakMap){if(o==null||typeof o!="object")return o;try{let e=we(o);if(t.has(e))return t.get(e);if(Array.isArray(e)){let s=[];return t.set(e,s),s.push(...e.map(r=>V(r,t))),s}if(e instanceof Date||e instanceof RegExp||e instanceof ArrayBuffer||e instanceof Blob)return e;let n={};t.set(e,n);for(let s of Object.keys(e)){let r=Object.getOwnPropertyDescriptor(e,s);if(!r||r.get||r.set)continue;let a=e[s];typeof a!="function"&&typeof a!="symbol"&&(n[s]=V(a,t))}return n}catch(e){return console.warn("unwrapProxy error:",e),Array.isArray(o)?[]:{}}}var X=o=>o.map(t=>{let{renderContent:e,...n}=t;if(!Array.isArray(e))return t;let s=e.filter(a=>a.type==="collapsible-text"),r=e.filter(a=>a.type==="markdown"||a.type==="text");return s.length>0&&(n.reasoning_content=s.map(a=>a.content).join("")),r.length>0&&(n.content=r.map(a=>a.content).join("")),n});var $=o=>{let t=localStorage.getItem(o);return t?JSON.parse(t):[]},J=class{constructor(t="tiny-robot-ai-conversations"){this.storageKey=t}saveConversation(t){try{let e=$(this.storageKey),n=e.findIndex(s=>s.id===t.id);n!==-1?Object.assign(e[n],t):e.unshift({...t,messages:[]}),localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(e){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e)}}loadConversations(){try{return $(this.storageKey).map(e=>({id:e.id,title:e.title,createdAt:e.createdAt,updatedAt:e.updatedAt,metadata:e.metadata}))}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}saveMessages(t,e){try{let n=$(this.storageKey),s=n.findIndex(r=>r.id===t);s!==-1&&(n[s].messages=e),localStorage.setItem(this.storageKey,JSON.stringify(n))}catch(n){console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n)}}loadMessages(t){try{let n=$(this.storageKey).find(r=>r.id===t);return X(n?.messages||[])}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}deleteConversation(t){let e=$(this.storageKey),n=e.findIndex(s=>s.id===t);n!==-1&&e.splice(n,1),localStorage.setItem(this.storageKey,JSON.stringify(e))}};import{openDB as Te}from"idb";var z=class{constructor(t="tiny-robot-ai-db",e=3){this.db=null;this.dbName=t,this.dbVersion=e}async getDB(){return this.db||(this.db=await Te(this.dbName,this.dbVersion,{upgrade(t){t.objectStoreNames.contains("conversations")||t.createObjectStore("conversations",{keyPath:"id"}).createIndex("by-updated","updatedAt"),t.objectStoreNames.contains("messages")||t.createObjectStore("messages",{keyPath:"conversationId"})}})),this.db}async loadConversations(){try{return(await(await this.getDB()).getAllFromIndex("conversations","by-updated")).reverse()}catch(t){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u5931\u8D25:",t),[]}}async loadMessages(t){try{let n=await(await this.getDB()).get("messages",t);return n?X(n.messages):[]}catch(e){return console.error("\u52A0\u8F7D\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",e),[]}}async saveConversation(t){try{let e=await this.getDB(),n=V(t);await e.put("conversations",n)}catch(e){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u5931\u8D25:",e),e}}async saveMessages(t,e){try{let n=await this.getDB(),s=V(e);await n.put("messages",{conversationId:t,messages:s})}catch(n){throw console.error("\u4FDD\u5B58\u4F1A\u8BDD\u6D88\u606F\u5931\u8D25:",n),n}}async deleteConversation(t){try{let e=await this.getDB();await e.delete("conversations",t),await e.delete("messages",t)}catch(e){throw console.error("\u5220\u9664\u4F1A\u8BDD\u5931\u8D25:",e),e}}};function re(o={}){return new J(o.key||"tiny-robot-ai-conversations")}function Se(o={}){return new z(o.dbName||"tiny-robot-ai-db",o.dbVersion||1)}import{computed as je,ref as Ce,watch as Le}from"vue";import{computed as _e,reactive as De,ref as Y,watch as Ue}from"vue";var le=(o={})=>{let{fallbackRole:t="assistant",...e}=o;return{name:"fallbackRole",...e,onBeforeRequest(n){let{requestBody:s}=n;return s.messages=s.messages.map(r=>({...r,role:r.role||t})),e.onBeforeRequest?.(n)}}};var ce=(o={})=>{let{continueContent:t="Please continue with your previous answer.",...e}=o;return{name:"length",...e,onAfterRequest:async n=>{let{lastChoice:s,appendMessage:r,requestNext:a}=n;return s?.finish_reason==="length"&&(r({role:"user",content:t}),a()),e.onAfterRequest?.(n)}}};var ue=(o={})=>({name:"thinking",...o,onCompletionChunk(t){let{choice:e,currentMessage:n}=t,r=typeof(e?.message?.reasoning_content||e?.delta?.reasoning_content)=="string";return n.state?n.state.thinking=r:n.state={thinking:r},o.onCompletionChunk?.(t)},onTurnEnd(t){let e=t.currentTurn.slice(-1)[0];return e?.state&&(e.state.thinking=void 0),o.onTurnEnd?.(t)}});import{reactive as Ee}from"vue";var L=class extends Error{constructor(t){super(t),this.name="AbortError"}};function Pe(o){if(o.aborted)return{promise:Promise.reject(new L(String(o.reason??"Aborted"))),cleanup:()=>{}};let t=null;return{promise:new Promise((s,r)=>{t=()=>{r(new L(String(o.reason??"Aborted")))},o.addEventListener("abort",t,{once:!0})}),cleanup:()=>{t&&(o.removeEventListener("abort",t),t=null)}}}function pe(o,t){let{promise:e,cleanup:n}=Pe(t);return Promise.race([o,e]).finally(n)}function fe(o,t){let e={};for(let n in o)t.includes(n)&&(e[n]=o[n]);return e}function me(o,t){let e={};for(let n in o)t.includes(n)||(e[n]=o[n]);return e}async function*Q(o){if(de(o)){yield*o;return}let t=await o;if(de(t)){yield*t;return}yield t}function de(o){return o&&typeof o=="object"&&typeof o[Symbol.asyncIterator]=="function"}var ae=o=>typeof o=="object"&&o!==null,ge=o=>ae(o)&&typeof o.index=="number",W=(o,t)=>{for(let[e,n]of Object.entries(t)){let s=o[e];if(s)if(typeof s=="string"&&typeof n=="string")e==="type"&&s||(o[e]=s+n);else if(Array.isArray(s)&&Array.isArray(n))if(s.every(r=>ge(r))&&n.every(r=>ge(r))){let r=new Map(s.map(f=>[f.index,f])),a=new Map(n.map(f=>[f.index,f]));for(let[f,v]of a)if(r.has(f)){let R=r.get(f);r.set(f,W(R,v))}else r.set(f,v);let c=Math.max(...Array.from(r.keys()),-1)+1,d=c>s.length?Array.from({length:c}):s;for(let[f,v]of r)d[f]=v;o[e]=d}else o[e]=[...s,...n];else ae(s)&&ae(n)&&(o[e]=W(s,n));else o[e]=n}return o};function Oe(o,t){let e=[];for(let n=0;n<o.length;n++){let s=o[n];if(s.role==="assistant"&&s.tool_calls&&s.tool_calls.length>0){let r=new Set(s.tool_calls.map(d=>d.id)),a=new Set;for(let d=n+1;d<o.length;d++){let f=o[d];f.role==="tool"&&f.tool_call_id&&r.has(f.tool_call_id)&&a.add(f.tool_call_id)}let c=s.tool_calls.map(d=>d.id).filter(d=>!a.has(d));c.length>0&&e.push({insertAfterIndex:n,missingToolCallIds:c})}}for(let n=e.length-1;n>=0;n--){let{insertAfterIndex:s,missingToolCallIds:r}=e[n],a=r.map(c=>({role:"tool",tool_call_id:c,content:t}));o.splice(s+1,0,...a)}}var Ie="remove";function ke(o,t,e,n){let s=o.filter(a=>a[e]),r=new Set(s.flatMap(a=>a.tool_calls?.map(c=>c.id)??[]));if(t===Ie)for(let a=o.length-1;a>=0;a--){let c=o[a];(c[e]||c[n]||c.tool_call_id&&r.has(c.tool_call_id))&&o.splice(a,1)}else if(t===!0)for(let a of o)(a[e]||a.tool_call_id&&r.has(a.tool_call_id))&&(a[n]=!0,delete a[e])}var vt=o=>{let{getTools:t,beforeCallTools:e,callTool:n,onToolCallStart:s,onToolCallEnd:r,toolCallCancelledContent:a="Tool call cancelled.",toolCallFailedContent:c="Tool call failed.",autoFillMissingToolMessages:d=!1,excludeToolMessagesNextTurn:f=!1,...v}=o,R=Symbol("doNotSendNextTurn"),x=Symbol("doNotSend"),A=(...m)=>{let[h,{primaryMessage:T}]=m;T.state.toolCall[h.id].status="running",s?.(...m)},M=(...m)=>{let[h,{status:T,primaryMessage:O}]=m;O.state.toolCall[h.id].status=T,r?.(...m)};return{name:"tool",...v,onTurnStart:m=>{let{messages:h}=m;return d&&Oe(h,a),f&&ke(h,f,R,x),v.onTurnStart?.(m)},onBeforeRequest:async m=>{let{messages:h,requestBody:T}=m;f===!0&&(T.messages=h.filter(E=>!E[x]));let O=await t?.();return O&&O.length>0&&(T.tools=O),v.onBeforeRequest?.(m)},onAfterRequest:async m=>{let{currentMessage:h,lastChoice:T,appendMessage:O,abortSignal:E,setRequestState:i,requestNext:l}=m;if(T?.finish_reason!=="tool_calls"||!h.tool_calls?.length)return;f&&(h[R]=!0),i("processing","calling-tools"),await e?.(h.tool_calls,{...m,currentMessage:h});let g=h.tool_calls.map(async y=>{let S=Math.floor(Date.now()/1e3),w=Ee({role:"tool",tool_call_id:y.id,content:"",metadata:{createdAt:S,updatedAt:S}});O(w);let U={...m,primaryMessage:h,toolMessage:w};A(y,U);try{let k=n(y,U),B=Q(k);for await(let u of B){if(typeof u=="string")w.content+=u;else{let p={};try{p=JSON.parse(w.content||"{}")}catch(b){console.warn(b)}w.content=JSON.stringify(W(p,u))}w.metadata.updatedAt=Math.floor(Date.now()/1e3)}M(y,{...U,status:"success"})}catch(k){let B=k instanceof Error?k:new Error(String(k));if(E.aborted){M(y,{...U,status:"cancelled",error:B});return}console.error(k),w.content.length===0&&(w.content=c),M(y,{...U,status:"failed",error:B})}});return await Promise.all(g),l(),v.onAfterRequest?.(m)},onCompletionChunk:m=>{var T,O,E;let{currentMessage:h}=m;if(Array.isArray(h.tool_calls))for(let i of h.tool_calls)h.state?.toolCall?.[i.id]?.status||(h.state??(h.state={}),(T=h.state).toolCall??(T.toolCall={}),(O=h.state.toolCall)[E=i.id]??(O[E]={}));return v.onCompletionChunk?.(m)}}};var qe=o=>{let t=[];for(let e of o){if(e.name){let n=t.findIndex(s=>s.name===e.name);n!==-1&&t.splice(n,1)}t.push(e)}return t},ie=o=>{let{initialMessages:t=[],requestMessageFields:e=[],requestMessageFieldsExclude:n=["state","metadata","loading"],plugins:s=[],onCompletionChunk:r}=o,a=Y("idle"),c=Y(void 0),d=Y(t),f=Y(o.responseProvider),v=null,R=[],x={},A=[le(),ue(),ce()],M=qe(A.concat(s)),m=_e(()=>a.value==="processing"),h=async u=>{if(!u||!u.trim()){console.warn("Cannot send empty message");return}if(m.value){console.warn("Cannot send message while processing is in progress");return}let p=Math.floor(Date.now()/1e3);d.value.push({role:"user",content:u.trim(),metadata:{createdAt:p,updatedAt:p}}),R.push(d.value[d.value.length-1]),await w()},T=async(...u)=>{if(m.value){console.warn("Cannot send message while processing is in progress");return}d.value.push(...u),R.push(...u),await w()},O=u=>{let p=u;return e.length&&(p=p.map(b=>fe(b,e))),n.length&&(p=p.map(b=>me(b,n))),p},E=(u,p)=>{a.value=u,u==="processing"?c.value=p||"requesting":c.value=void 0},i=u=>{Object.assign(x,u)},l=u=>({messages:d.value,currentTurn:R,requestState:a.value,processingState:c.value,plugins:M,abortSignal:u,setRequestState:E,customContext:x,setCustomContext:i}),g=(u,p)=>typeof u.disabled=="function"?u.disabled(p):!!u.disabled,y=u=>!u||Object.keys(u).length===0?!1:Object.values(u).some(p=>!!p),S=async(u,p)=>{E("processing","requesting");let b=new Proxy({messages:O(d.value)},{set(D,P,N){return P==="messages"?(D.messages=O(N),!0):(D[P]=N,!0)}}),I=l(p);for(let D of M.filter(P=>!g(P,I)))await D.onBeforeRequest?.({...I,requestBody:b});let C=De({role:"",content:"",loading:!0});B(C);let _,Z=u(b,p),q=Q(Z);for await(let D of q){E("processing","completing"),C.loading&&(C.loading=void 0);let P=D.choices?.find(K=>K.index===0);if(P){_=P;let K=()=>{C.metadata||(C.metadata={});let{created:H,...ve}=D;C.metadata.createdAt=H,C.metadata.updatedAt=Math.floor(Date.now()/1e3),Object.assign(C.metadata,ve);let ee=y(P.delta)?P.delta:P.message;ee||(ee=P.delta||P.message||{}),W(C,ee)};if(r){let H=l(p);r({...H,chunk:D,choice:P,currentMessage:C},K)}else K()}let N=l(p);for(let K of M.filter(H=>!g(H,N)))K.onCompletionChunk?.({...N,abortSignal:p,chunk:D,choice:P,currentMessage:C})}await k(C,u,p,_)},w=async()=>{let u=new AbortController;v=u,x={};try{E("processing","requesting");let p=l(u.signal);for(let C of M.filter(_=>!g(_,p)))await C.onTurnStart?.(p);let b=f.value;try{await S(b,u.signal),E("completed")}catch(C){if(u.signal.aborted||C instanceof L||C instanceof Error&&C.name==="AbortError")E("aborted");else throw C}let I=l(u.signal);for(let C of M.filter(_=>!g(_,I)))await C.onTurnEnd?.(I)}catch(p){E("error");let b=!1,I=l(u.signal);for(let C of M.filter(_=>!g(_,I)))C.onError&&(b=!0,C.onError({...I,error:p}));if(!b)throw p}finally{let p=l(u.signal);for(let b of M.filter(I=>!g(I,p)))try{b.onFinally?.(p)}catch(I){console.error(`Error in onFinally hook for plugin ${b.name||"Anonymous"}:`,I)}v=null,R.slice(-1)[0]&&(R.slice(-1)[0].loading=void 0),R=[]}},U=async()=>{v?.abort(),m.value&&await new Promise(u=>{let p=Ue(m,b=>{b||(p(),u())},{immediate:!0})})},k=async(u,p,b,I)=>{let C=!1,_=l(b),Z=M.filter(q=>!g(q,_)).map(q=>{if(!q.onAfterRequest)return null;let D=N=>{B(N)},P=()=>{C=!0};return q.onAfterRequest({..._,currentMessage:u,lastChoice:I,appendMessage:D,requestNext:P})}).filter(q=>q!==null);await pe(Promise.all(Z),b),C&&await S(p,b)},B=u=>{let p=Array.isArray(u)?u:[u];d.value.push(...p),R.push(...p)};return{requestState:a,processingState:c,messages:d,responseProvider:f,isProcessing:m,sendMessage:h,send:T,abortRequest:U}};import{isRef as Be,toValue as Ne}from"vue";function ye(o,t=200,e=!1,n=!0,s=!1){return Fe(Ke(t,e,n,s),o)}function Fe(o,t){function e(...n){return new Promise((s,r)=>{Promise.resolve(o(()=>t.apply(this,n),{fn:t,thisArg:this,args:n})).then(s).catch(r)})}return e}var he=()=>{};function Ke(...o){let t=0,e,n=!0,s=he,r,a,c,d,f;!Be(o[0])&&typeof o[0]=="object"?{delay:a,trailing:c=!0,leading:d=!0,rejectOnCancel:f=!1}=o[0]:[a,c=!0,d=!0,f=!1]=o;let v=()=>{e&&(clearTimeout(e),e=void 0,s(),s=he)};return x=>{let A=Ne(a),M=Date.now()-t,m=()=>r=x();return v(),A<=0?(t=Date.now(),m()):(M>A?(t=Date.now(),(d||!n)&&m()):c&&(r=new Promise((h,T)=>{s=f?T:h,e=setTimeout(()=>{t=Date.now(),n=!0,h(m()),v()},Math.max(0,A-M))})),!d&&!e&&(e=setTimeout(()=>n=!0,A)),n=!1,r)}}var _t=o=>{let t=o.storage||re(),e=Ce([]),n=new Map,s=new Map,r=Ce(null),a=je(()=>{let i=r.value;if(!i)return null;let l=e.value.find(y=>y.id===i);if(!l)return null;let g=n.get(i);return g?{...l,engine:g}:null}),c=i=>{if(!t?.saveMessages)return;let l=i||r.value,g=e.value.find(S=>S.id===l);if(!g)return;g.updatedAt=Date.now(),t?.saveConversation?.(g);let y=n.get(g.id);y&&t.saveMessages(g.id,y.messages.value)},d=(i,l)=>{if(!o.autoSaveMessages||!t?.saveMessages)return;let g=s.get(i);g&&g();let y=o.autoSaveThrottle??1e3,S=ye(()=>{c(i)},y,!0,!0),w=Le(l.messages,S,{deep:!0});s.set(i,w)},f=i=>{let l=s.get(i);l&&(l(),s.delete(i))};t?.loadConversations&&Promise.resolve(t.loadConversations()).then(i=>{if(!i?.length)return[];if(e.value.length===0)return e.value=i,e.value;let l=new Map(e.value.map(g=>[g.id,g]));return i.forEach(g=>{l.has(g.id)||l.set(g.id,g)}),e.value=Array.from(l.values()),e.value}).then(i=>{o.onLoad?.(i)}).catch(i=>{console.error("[useConversation] loadConversations failed:",i)});let v=async(i,l)=>{let g=n.get(i);if(g)return g;let y=l?.initialMessages??o.useMessageOptions.initialMessages??[];if(t?.loadMessages)try{y=await t.loadMessages(i)}catch(w){console.error("[useConversation] loadMessages failed:",w)}let S=ie({...o.useMessageOptions,...l,initialMessages:y});return n.set(i,S),d(i,S),S};function R(){return Date.now().toString(36)+Math.random().toString(36).substring(2,9)}let x=i=>{let{id:l=R(),title:g,metadata:y,useMessageOptions:S}=i||{},w=Date.now(),U={id:l,title:g,createdAt:w,updatedAt:w,metadata:y};e.value.unshift(U);let k=ie({...o.useMessageOptions,...S});return n.set(l,k),d(l,k),t?.saveConversation?.(U),t?.saveMessages?.(l,k.messages.value),r.value=l,a.value},A=i=>{let{excludeId:l}=i||{};n.forEach((g,y)=>{if(l&&y===l)return;g.isProcessing?.value||(f(y),n.delete(y))})};return{conversations:e,activeConversationId:r,activeConversation:a,createConversation:x,switchConversation:async i=>i?r.value===i?a.value:e.value.find(g=>g.id===i)?(await v(i),A({excludeId:i}),r.value=i,a.value):null:null,deleteConversation:async i=>{let l=e.value.findIndex(y=>y.id===i);if(l===-1)return;await n.get(i)?.abortRequest(),f(i),n.delete(i),e.value.splice(l,1),t?.deleteConversation?.(i),r.value===i&&(r.value=null,A())},clear:()=>{e.value.map(l=>l.id).forEach(l=>{t?.deleteConversation?.(l)}),n.forEach(l=>{l.abortRequest()}),s.forEach(l=>{l()}),e.value=[],n.clear(),s.clear(),r.value=null},updateConversationTitle:(i,l)=>{let g=e.value.find(y=>y.id===i);g&&(g.title=l,g.updatedAt=Date.now(),t?.saveConversation?.(g))},saveMessages:c,sendMessage:i=>{a.value?.engine.sendMessage(i)},abortActiveRequest:async()=>{await a.value?.engine.abortRequest()}}};export{se as AIClient,G as BaseModelProvider,Ie as EXCLUDE_MODE_REMOVE,Me as ErrorType,z as IndexedDBStrategy,J as LocalStorageStrategy,j as OpenAIProvider,be as StreamEventType,xe as extractTextFromResponse,le as fallbackRolePlugin,Re as formatMessages,ne as handleSSEStream,Se as indexedDBStorageStrategyFactory,ce as lengthPlugin,re as localStorageStrategyFactory,Ae as sseStreamToGenerator,ue as thinkingPlugin,vt as toolPlugin,_t as useConversation,ie as useMessage};
|
package/package.json
CHANGED
|
@@ -1,10 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opentiny/tiny-robot-kit",
|
|
3
|
-
"version": "0.4.0-alpha.
|
|
3
|
+
"version": "0.4.0-alpha.11",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/opentiny/tiny-robot.git",
|
|
7
|
+
"homepage": "https://docs.opentiny.design/tiny-robot/"
|
|
8
|
+
},
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/opentiny/tiny-robot/issues"
|
|
11
|
+
},
|
|
4
12
|
"publishConfig": {
|
|
5
13
|
"access": "public"
|
|
6
14
|
},
|
|
7
15
|
"description": "AI大模型请求与数据处理工具包",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"vue",
|
|
18
|
+
"vue3",
|
|
19
|
+
"ai",
|
|
20
|
+
"ai-client",
|
|
21
|
+
"ai-sdk",
|
|
22
|
+
"chat",
|
|
23
|
+
"chatbot",
|
|
24
|
+
"llm",
|
|
25
|
+
"openai",
|
|
26
|
+
"assistant",
|
|
27
|
+
"streaming",
|
|
28
|
+
"composables",
|
|
29
|
+
"conversation",
|
|
30
|
+
"model-provider",
|
|
31
|
+
"tiny-robot",
|
|
32
|
+
"opentiny"
|
|
33
|
+
],
|
|
8
34
|
"main": "dist/index.js",
|
|
9
35
|
"module": "dist/index.mjs",
|
|
10
36
|
"types": "dist/index.d.ts",
|
|
@@ -26,5 +52,8 @@
|
|
|
26
52
|
"peerDependencies": {
|
|
27
53
|
"vue": ">=3.0.0"
|
|
28
54
|
},
|
|
29
|
-
"
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"idb": "^8.0.3"
|
|
57
|
+
},
|
|
58
|
+
"gitHead": "b2a08019209d5d6966c3527fb1576ad903f984fa"
|
|
30
59
|
}
|