@ztimson/ai-utils 0.8.6 → 0.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const U=require("node:os"),g=require("@ztimson/utils"),D=require("@anthropic-ai/sdk"),H=require("openai"),I=require("url"),$=require("path"),b=require("node:child_process"),G=require("node:fs"),k=require("node:fs/promises"),_=require("node:path"),B=require("tesseract.js"),K=require("cheerio"),q=require("@ztimson/node-utils");var T=typeof document<"u"?document.currentScript:null;function E(h){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(h){for(const e in h)if(e!=="default"){const t=Object.getOwnPropertyDescriptor(h,e);Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:()=>h[e]})}}return n.default=h,Object.freeze(n)}const N=E(U),R=E(_),V=E(K);class P{}class z extends P{constructor(n,e,t){super(),this.ai=n,this.apiToken=e,this.model=t,this.client=new D.Anthropic({apiKey:e})}client;toStandard(n){const e=Date.now(),t=[];for(let a of n)if(typeof a.content=="string")t.push({timestamp:e,...a});else{const s=a.content?.filter(r=>r.type=="text").map(r=>r.text).join(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const U=require("node:os"),g=require("@ztimson/utils"),D=require("@anthropic-ai/sdk"),H=require("openai"),I=require("url"),A=require("path"),b=require("node:child_process"),G=require("node:fs"),k=require("node:fs/promises"),_=require("node:path"),B=require("tesseract.js"),K=require("cheerio"),q=require("@ztimson/node-utils");var T=typeof document<"u"?document.currentScript:null;function E(h){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(h){for(const e in h)if(e!=="default"){const t=Object.getOwnPropertyDescriptor(h,e);Object.defineProperty(n,e,t.get?t:{enumerable:!0,get:()=>h[e]})}}return n.default=h,Object.freeze(n)}const N=E(U),R=E(_),V=E(K);class P{}class z extends P{constructor(n,e,t){super(),this.ai=n,this.apiToken=e,this.model=t,this.client=new D.Anthropic({apiKey:e})}client;toStandard(n){const e=Date.now(),t=[];for(let a of n)if(typeof a.content=="string")t.push({timestamp:e,...a});else{const s=a.content?.filter(r=>r.type=="text").map(r=>r.text).join(`
2
2
 
3
3
  `);s&&t.push({timestamp:e,role:a.role,content:s}),a.content.forEach(r=>{if(r.type=="tool_use")t.push({timestamp:e,role:"tool",id:r.id,name:r.name,args:r.input,content:void 0});else if(r.type=="tool_result"){const c=t.findLast(m=>m.id==r.tool_use_id);c&&(c[r.is_error?"error":"content"]=r.content)}})}return t}fromStandard(n){for(let e=0;e<n.length;e++)if(n[e].role=="tool"){const t=n[e];n.splice(e,1,{role:"assistant",content:[{type:"tool_use",id:t.id,name:t.name,input:t.args}]},{role:"user",content:[{type:"tool_result",tool_use_id:t.id,is_error:!!t.error,content:t.error||t.content}]}),e++}return n.map(({timestamp:e,...t})=>t)}ask(n,e={}){const t=new AbortController;return Object.assign(new Promise(async a=>{let s=this.fromStandard([...e.history||[],{role:"user",content:n,timestamp:Date.now()}]);const r=e.tools||this.ai.options.llm?.tools||[],c={model:e.model||this.model,max_tokens:e.max_tokens||this.ai.options.llm?.max_tokens||4096,system:e.system||this.ai.options.llm?.system||"",temperature:e.temperature||this.ai.options.llm?.temperature||.7,tools:r.map(u=>({name:u.name,description:u.description,input_schema:{type:"object",properties:u.args?g.objectMap(u.args,(o,l)=>({...l,required:void 0})):{},required:u.args?Object.entries(u.args).filter(o=>o[1].required).map(o=>o[0]):[]},fn:void 0})),messages:s,stream:!!e.stream};let m,i=!0;do{if(m=await this.client.messages.create(c).catch(o=>{throw o.message+=`
4
4
 
@@ -23,7 +23,7 @@ You have RAG memory and will be given the top_k closest memories regarding the u
23
23
  `)).flatMap(m=>[...m.split(/\s+/).filter(Boolean),`
24
24
  `]),c=[];for(let m=0;m<r.length;){let i="",u=m;for(;u<r.length;){const l=i+(i?" ":"")+r[u];if(this.estimateTokens(l.replace(/\s*\n\s*/g,`
25
25
  `))>e&&i)break;i=l,u++}const o=i.replace(/\s*\n\s*/g,`
26
- `).trim();o&&c.push(o),m=Math.max(u-t,u===m?m+1:u)}return c}embedding(n,e={}){let{maxTokens:t=500,overlapTokens:a=50}=e,s=!1;const r=()=>{s=!0},c=i=>new Promise((u,o)=>{if(s)return o(new Error("Aborted"));const l=[$.join($.dirname(I.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:T&&T.tagName.toUpperCase()==="SCRIPT"&&T.src||new URL("index.js",document.baseURI).href)),"embedder.js"),this.ai.options.path,this.ai.options?.embedder||"bge-small-en-v1.5"],d=b.spawn("node",l,{stdio:["pipe","pipe","ignore"]});d.stdin.write(i),d.stdin.end();let p="";d.stdout.on("data",f=>p+=f.toString()),d.on("close",f=>{if(s)return o(new Error("Aborted"));if(f===0)try{const y=JSON.parse(p);u(y.embedding)}catch{o(new Error("Failed to parse embedding output"))}else o(new Error(`Embedder process exited with code ${f}`))}),d.on("error",o)}),m=(async()=>{const i=this.chunk(n,t,a),u=[];for(let o=0;o<i.length&&!s;o++){const l=i[o],d=await c(l);u.push({index:o,embedding:d,text:l,tokens:this.estimateTokens(l)})}return u})();return Object.assign(m,{abort:r})}estimateTokens(n){const e=JSON.stringify(n);return Math.ceil(e.length/4*1.2)}fuzzyMatch(n,...e){if(e.length<2)throw new Error("Requires at least 2 strings to compare");const t=(r,c=10)=>r.toLowerCase().split("").map((m,i)=>m.charCodeAt(0)*(i+1)%c/c).slice(0,c),a=t(n),s=e.map(r=>t(r)).map(r=>this.cosineSimilarity(a,r));return{avg:s.reduce((r,c)=>r+c,0)/s.length,max:Math.max(...s),similarities:s}}async json(n,e,t){const a=await this.code(n,{...t,system:[t?.system,`Only respond using JSON matching this schema:
26
+ `).trim();o&&c.push(o),m=Math.max(u-t,u===m?m+1:u)}return c}embedding(n,e={}){let{maxTokens:t=500,overlapTokens:a=50}=e,s=!1;const r=()=>{s=!0},c=i=>new Promise((u,o)=>{if(s)return o(new Error("Aborted"));const l=[A.join(A.dirname(I.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:T&&T.tagName.toUpperCase()==="SCRIPT"&&T.src||new URL("index.js",document.baseURI).href)),"embedder.js"),this.ai.options.path,this.ai.options?.embedder||"bge-small-en-v1.5"],d=b.spawn("node",l,{stdio:["pipe","pipe","ignore"]});d.stdin.write(i),d.stdin.end();let p="";d.stdout.on("data",f=>p+=f.toString()),d.on("close",f=>{if(s)return o(new Error("Aborted"));if(f===0)try{const y=JSON.parse(p);u(y.embedding)}catch{o(new Error("Failed to parse embedding output"))}else o(new Error(`Embedder process exited with code ${f}`))}),d.on("error",o)}),m=(async()=>{const i=this.chunk(n,t,a),u=[];for(let o=0;o<i.length&&!s;o++){const l=i[o],d=await c(l);u.push({index:o,embedding:d,text:l,tokens:this.estimateTokens(l)})}return u})();return Object.assign(m,{abort:r})}estimateTokens(n){const e=JSON.stringify(n);return Math.ceil(e.length/4*1.2)}fuzzyMatch(n,...e){if(e.length<2)throw new Error("Requires at least 2 strings to compare");const t=(r,c=10)=>r.toLowerCase().split("").map((m,i)=>m.charCodeAt(0)*(i+1)%c/c).slice(0,c),a=t(n),s=e.map(r=>t(r)).map(r=>this.cosineSimilarity(a,r));return{avg:s.reduce((r,c)=>r+c,0)/s.length,max:Math.max(...s),similarities:s}}async json(n,e,t){const a=await this.code(n,{...t,system:[t?.system,`Only respond using JSON matching this schema:
27
27
  \`\`\`json
28
28
  ${e}
29
29
  \`\`\``].filter(s=>!!s).join(`
@@ -42,9 +42,9 @@ for turn, speaker in output.speaker_diarization:
42
42
  segments.append({"start": turn.start, "end": turn.end, "speaker": speaker})
43
43
 
44
44
  print(json.dumps(segments))
45
- `}downloads={};pyannote;whisperModel;async addPunctuation(n,e,t=150){const a=r=>{if(r=r.toLowerCase().replace(/[^a-z]/g,""),r.length<=3)return 1;const c=r.match(/[aeiouy]+/g);let m=c?c.length:1;return r.endsWith("e")&&m--,Math.max(1,m)};let s="";return n.transcription.filter((r,c)=>{let m=!1;const i=n.transcription[c-1],u=n.transcription[c+1];return!r.text&&u?(u.offsets.from=r.offsets.from,u.timestamps.from=r.offsets.from):r.text&&r.text[0]!=" "&&i&&(i.offsets.to=r.offsets.to,i.timestamps.to=r.timestamps.to,i.text+=r.text,m=!0),!!r.text&&!m}).forEach(r=>{const c=/^[A-Z]/.test(r.text.trim()),m=r.offsets.to-r.offsets.from,u=a(r.text.trim())*t;c&&m>u*2&&r.text[0]==" "&&(s+="."),s+=r.text}),e?this.ai.language.ask(s,{system:"Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo",temperature:.1,tools:[{name:"replace",description:"Use find and replace to fix errors",args:{find:{type:"string",description:"Text to find",required:!0},replace:{type:"string",description:"Text to replace",required:!0}},fn:r=>s=s.replace(r.find,r.replace)}]}).then(()=>s):s.trim()}async diarizeTranscript(n,e,t){const a=new Map;let s=0;e.forEach(p=>{a.has(p.speaker)||a.set(p.speaker,++s)});const r=await this.addPunctuation(n,t),c=r.match(/[^.!?]+[.!?]+/g)||[r],m=n.transcription.filter(p=>p.text.trim()),i=c.map(p=>{if(p=p.trim(),!p)return null;const f=p.toLowerCase().replace(/[^\w\s]/g,"").split(/\s+/),y=new Map;f.forEach(x=>{const S=m.find(w=>x===w.text.trim().toLowerCase().replace(/[^\w]/g,""));if(!S)return;const M=S.offsets.from/1e3,A=e.find(w=>M>=w.start&&M<=w.end);if(A){const w=a.get(A.speaker);y.set(w,(y.get(w)||0)+1)}});let O=1,v=0;return y.forEach((x,S)=>{x>v&&(v=x,O=S)}),{speaker:O,text:p}}).filter(p=>p!==null),u=[];i.forEach(p=>{const f=u[u.length-1];f&&f.speaker===p.speaker?f.text+=" "+p.text:u.push({...p})});let o=u.map(p=>`[Speaker ${p.speaker}]: ${p.text}`).join(`
45
+ `}downloads={};pyannote;whisperModel;async addPunctuation(n,e,t=150){const a=r=>{if(r=r.toLowerCase().replace(/[^a-z]/g,""),r.length<=3)return 1;const c=r.match(/[aeiouy]+/g);let m=c?c.length:1;return r.endsWith("e")&&m--,Math.max(1,m)};let s="";return n.transcription.filter((r,c)=>{let m=!1;const i=n.transcription[c-1],u=n.transcription[c+1];return!r.text&&u?(u.offsets.from=r.offsets.from,u.timestamps.from=r.offsets.from):r.text&&r.text[0]!=" "&&i&&(i.offsets.to=r.offsets.to,i.timestamps.to=r.timestamps.to,i.text+=r.text,m=!0),!!r.text&&!m}).forEach(r=>{const c=/^[A-Z]/.test(r.text.trim()),m=r.offsets.to-r.offsets.from,u=a(r.text.trim())*t;c&&m>u*2&&r.text[0]==" "&&(s+="."),s+=r.text}),e?this.ai.language.ask(s,{system:"Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo",temperature:.1,tools:[{name:"replace",description:"Use find and replace to fix errors",args:{find:{type:"string",description:"Text to find",required:!0},replace:{type:"string",description:"Text to replace",required:!0}},fn:r=>s=s.replace(r.find,r.replace)}]}).then(()=>s):s.trim()}async diarizeTranscript(n,e,t){const a=new Map;let s=0;e.forEach(p=>{a.has(p.speaker)||a.set(p.speaker,++s)});const r=await this.addPunctuation(n,t),c=r.match(/[^.!?]+[.!?]+/g)||[r],m=n.transcription.filter(p=>p.text.trim()),i=c.map(p=>{if(p=p.trim(),!p)return null;const f=p.toLowerCase().replace(/[^\w\s]/g,"").split(/\s+/),y=new Map;f.forEach(x=>{const S=m.find(w=>x===w.text.trim().toLowerCase().replace(/[^\w]/g,""));if(!S)return;const M=S.offsets.from/1e3,$=e.find(w=>M>=w.start&&M<=w.end);if($){const w=a.get($.speaker);y.set(w,(y.get(w)||0)+1)}});let O=1,v=0;return y.forEach((x,S)=>{x>v&&(v=x,O=S)}),{speaker:O,text:p}}).filter(p=>p!==null),u=[];i.forEach(p=>{const f=u[u.length-1];f&&f.speaker===p.speaker?f.text+=" "+p.text:u.push({...p})});let o=u.map(p=>`[Speaker ${p.speaker}]: ${p.text}`).join(`
46
46
  `).trim();if(!t)return o;let l=this.ai.language.chunk(o,500,0);l.length>4&&(l=[...l.slice(0,3),l.at(-1)]);const d=await this.ai.language.json(l.join(`
47
47
  `),'{1: "Detected Name", 2: "Second Name"}',{system:"Use the following transcript to identify speakers. Only identify speakers you are positive about, dont mention speakers you are unsure about in your response",temperature:.1});return Object.entries(d).forEach(([p,f])=>o=o.replaceAll(`[Speaker ${p}]`,`[${f}]`)),o}runAsr(n,e={}){let t;const a=new Promise((s,r)=>{this.downloadAsrModel(e.model).then(c=>{if(e.diarization){let m=R.join(R.dirname(n),"transcript");t=b.spawn(this.ai.options.whisper,["-m",c,"-f",n,"-np","-ml","1","-oj","-of",m],{stdio:["ignore","ignore","pipe"]}),t.on("error",i=>r(i)),t.on("close",async i=>{if(i===0){m=await k.readFile(m+".json","utf-8"),k.rm(m+".json").catch(()=>{});try{s(JSON.parse(m))}catch{r(new Error("Failed to parse whisper JSON"))}}else r(new Error(`Exit code ${i}`))})}else{let m="";t=b.spawn(this.ai.options.whisper,["-m",c,"-f",n,"-np","-nt"]),t.on("error",i=>r(i)),t.stdout.on("data",i=>m+=i.toString()),t.on("close",async i=>{i===0?s(m.trim()||null):r(new Error(`Exit code ${i}`))})}})});return Object.assign(a,{abort:()=>t?.kill("SIGTERM")})}runDiarization(n){let e=!1,t=()=>{e=!0};const a=r=>new Promise(c=>{const m=b.spawn(r,["-W","ignore","-c","import pyannote.audio"]);m.on("close",i=>c(i===0)),m.on("error",()=>c(!1))}),s=Promise.all([a("python"),a("python3")]).then((async([r,c])=>{if(e)return;if(!r&&!c)throw new Error("Pyannote is not installed: pip install pyannote.audio");const m=c?"python3":"python";return new Promise((i,u)=>{if(e)return;let o="";const l=b.spawn(m,["-W","ignore","-c",this.pyannote,n]);l.stdout.on("data",d=>o+=d.toString()),l.stderr.on("data",d=>console.error(d.toString())),l.on("close",d=>{if(d===0)try{i(JSON.parse(o))}catch{u(new Error("Failed to parse diarization output"))}else u(new Error(`Python process exited with code ${d}`))}),l.on("error",u),t=()=>l.kill("SIGTERM")})}));return Object.assign(s,{abort:t})}asr(n,e={}){if(!this.ai.options.whisper)throw new Error("Whisper not configured");const t=_.join(G.mkdtempSync(_.join(U.tmpdir(),"audio-")),"converted.wav");b.execSync(`ffmpeg -i "${n}" -ar 16000 -ac 1 -f wav "${t}"`,{stdio:"ignore"});const a=()=>k.rm(_.dirname(t),{recursive:!0,force:!0}).catch(()=>{});if(!e.diarization)return this.runAsr(t,{model:e.model});const s=this.runAsr(t,{model:e.model,diarization:!0}),r=this.runDiarization(t);let c=!1,m=()=>{c=!0,s.abort(),r.abort(),a()};const i=Promise.allSettled([s,r]).then(async([u,o])=>{if(u.status=="rejected")throw new Error(`Whisper.cpp timestamps:
48
48
  `+u.reason);if(o.status=="rejected")throw new Error(`Pyannote:
49
- `+o.reason);return c||!e.diarization?u.value:this.diarizeTranscript(u.value,o.value,e.diarization=="llm")}).finally(()=>a());return Object.assign(i,{abort:m})}async downloadAsrModel(n=this.whisperModel){if(!this.ai.options.whisper)throw new Error("Whisper not configured");n.endsWith(".bin")||(n+=".bin");const e=_.join(this.ai.options.path,n);return await k.stat(e).then(()=>!0).catch(()=>!1)?e:this.downloads[n]?this.downloads[n]:(this.downloads[n]=fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${n}`).then(t=>t.arrayBuffer()).then(t=>Buffer.from(t)).then(async t=>(await k.writeFile(e,t),delete this.downloads[n],e)),this.downloads[n])}}class W{constructor(n){this.ai=n}ocr(n){let e;const t=new Promise(async a=>{e=await B.createWorker(this.ai.options.ocr||"eng",2,{cachePath:this.ai.options.path});const{data:s}=await e.recognize(n);await e.terminate(),a(s.text.trim()||null)});return Object.assign(t,{abort:()=>e?.terminate()})}}class Z{constructor(n){this.options=n,n.path||(n.path=N.tmpdir()),process.env.TRANSFORMERS_CACHE=n.path,this.audio=new L(this),this.language=new Y(this),this.vision=new W(this)}audio;language;vision}const Q=()=>N.platform()=="win32"?"cmd":q.$Sync`echo $SHELL`?.split("/").pop()||"bash",C={name:"cli",description:"Use the command line interface, returns any output",args:{command:{type:"string",description:"Command to run",required:!0}},fn:h=>q.$Sync`${h.command}`},X={name:"get_datetime",description:"Get current UTC date / time",args:{},fn:async()=>new Date().toUTCString()},ee={name:"exec",description:"Run code/scripts",args:{language:{type:"string",description:`Execution language (CLI: ${Q()})`,enum:["cli","node","python"],required:!0},code:{type:"string",description:"Code to execute",required:!0}},fn:async(h,n,e)=>{try{switch(h.type){case"cli":return await C.fn({command:h.code},n,e);case"node":return await J.fn({code:h.code},n,e);case"python":return await F.fn({code:h.code},n,e)}}catch(t){return{error:t?.message||t.toString()}}}},te={name:"fetch",description:"Make HTTP request to URL",args:{url:{type:"string",description:"URL to fetch",required:!0},method:{type:"string",description:"HTTP method to use",enum:["GET","POST","PUT","DELETE"],default:"GET"},headers:{type:"object",description:"HTTP headers to send",default:{}},body:{type:"object",description:"HTTP body to send"}},fn:h=>new g.Http({url:h.url,headers:h.headers}).request({method:h.method||"GET",body:h.body})},J={name:"exec_javascript",description:"Execute commonjs javascript",args:{code:{type:"string",description:"CommonJS javascript",required:!0}},fn:async h=>{const n=g.consoleInterceptor(null),e=await g.fn({console:n},h.code,!0).catch(t=>n.output.error.push(t));return{...n.output,return:e,stdout:void 0,stderr:void 0}}},F={name:"exec_javascript",description:"Execute commonjs javascript",args:{code:{type:"string",description:"CommonJS javascript",required:!0}},fn:async h=>({result:q.$Sync`python -c "${h.code}"`})},ne={name:"read_webpage",description:"Extract clean, structured content from a webpage. Use after web_search to read specific URLs",args:{url:{type:"string",description:"URL to extract content from",required:!0},focus:{type:"string",description:'Optional: What aspect to focus on (e.g., "pricing", "features", "contact info")'}},fn:async h=>{const n=await fetch(h.url,{headers:{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}}).then(r=>r.text()).catch(r=>{throw new Error(`Failed to fetch: ${r.message}`)}),e=V.load(n);e('script, style, nav, footer, header, aside, iframe, noscript, [role="navigation"], [role="banner"], .ad, .ads, .cookie, .popup').remove();const t={title:e('meta[property="og:title"]').attr("content")||e("title").text()||"",description:e('meta[name="description"]').attr("content")||e('meta[property="og:description"]').attr("content")||""};let a="";const s=["article","main",'[role="main"]',".content",".post",".entry","body"];for(const r of s){const c=e(r).first();if(c.length&&c.text().trim().length>200){a=c.text();break}}return a||(a=e("body").text()),a=a.replace(/\s+/g," ").trim().slice(0,8e3),{url:h.url,title:t.title.trim(),description:t.description.trim(),content:a,focus:h.focus}}},re={name:"web_search",description:"Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool",args:{query:{type:"string",description:"Search string",required:!0},length:{type:"string",description:"Number of results to return",default:5}},fn:async h=>{const n=await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(h.query)}`,{headers:{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)","Accept-Language":"en-US,en;q=0.9"}}).then(s=>s.text());let e,t=/<a .*?href="(.+?)".+?<\/a>/g;const a=new g.ASet;for(;(e=t.exec(n))!==null;){let s=/uddg=(.+)&amp?/.exec(decodeURIComponent(e[1]))?.[1];if(s&&(s=decodeURIComponent(s)),s&&a.add(s),a.size>=(h.length||5))break}return a}};exports.Ai=Z;exports.Anthropic=z;exports.Audio=L;exports.CliTool=C;exports.DateTimeTool=X;exports.ExecTool=ee;exports.FetchTool=te;exports.JSTool=J;exports.LLMProvider=P;exports.OpenAi=j;exports.PythonTool=F;exports.ReadWebpageTool=ne;exports.Vision=W;exports.WebSearchTool=re;
49
+ `+o.reason);return c||!e.diarization?u.value:this.diarizeTranscript(u.value,o.value,e.diarization=="llm")}).finally(()=>a());return Object.assign(i,{abort:m})}async downloadAsrModel(n=this.whisperModel){if(!this.ai.options.whisper)throw new Error("Whisper not configured");n.endsWith(".bin")||(n+=".bin");const e=_.join(this.ai.options.path,n);return await k.stat(e).then(()=>!0).catch(()=>!1)?e:this.downloads[n]?this.downloads[n]:(this.downloads[n]=fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${n}`).then(t=>t.arrayBuffer()).then(t=>Buffer.from(t)).then(async t=>(await k.writeFile(e,t),delete this.downloads[n],e)),this.downloads[n])}}class W{constructor(n){this.ai=n}ocr(n){let e;const t=new Promise(async a=>{e=await B.createWorker(this.ai.options.ocr||"eng",2,{cachePath:this.ai.options.path});const{data:s}=await e.recognize(n);await e.terminate(),a(s.text.trim()||null)});return Object.assign(t,{abort:()=>e?.terminate()})}}class Z{constructor(n){this.options=n,n.path||(n.path=N.tmpdir()),process.env.TRANSFORMERS_CACHE=n.path,this.audio=new L(this),this.language=new Y(this),this.vision=new W(this)}audio;language;vision}const Q=()=>N.platform()=="win32"?"cmd":q.$Sync`echo $SHELL`?.split("/").pop()||"bash",C={name:"cli",description:"Use the command line interface, returns any output",args:{command:{type:"string",description:"Command to run",required:!0}},fn:h=>q.$Sync`${h.command}`},X={name:"get_datetime",description:"Get current UTC date / time",args:{},fn:async()=>new Date().toUTCString()},ee={name:"exec",description:"Run code/scripts",args:{language:{type:"string",description:`Execution language (CLI: ${Q()})`,enum:["cli","node","python"],required:!0},code:{type:"string",description:"Code to execute",required:!0}},fn:async(h,n,e)=>{try{switch(h.language){case"cli":return await C.fn({command:h.code},n,e);case"node":return await J.fn({code:h.code},n,e);case"python":return await F.fn({code:h.code},n,e);default:throw new Error(`Unsupported language: ${h.language}`)}}catch(t){return{error:t?.message||t.toString()}}}},te={name:"fetch",description:"Make HTTP request to URL",args:{url:{type:"string",description:"URL to fetch",required:!0},method:{type:"string",description:"HTTP method to use",enum:["GET","POST","PUT","DELETE"],default:"GET"},headers:{type:"object",description:"HTTP headers to send",default:{}},body:{type:"object",description:"HTTP body to send"}},fn:h=>new g.Http({url:h.url,headers:h.headers}).request({method:h.method||"GET",body:h.body})},J={name:"exec_javascript",description:"Execute commonjs javascript",args:{code:{type:"string",description:"CommonJS javascript",required:!0}},fn:async h=>{const n=g.consoleInterceptor(null),e=await g.fn({console:n},h.code,!0).catch(t=>n.output.error.push(t));return{...n.output,return:e,stdout:void 0,stderr:void 0}}},F={name:"exec_javascript",description:"Execute commonjs javascript",args:{code:{type:"string",description:"CommonJS javascript",required:!0}},fn:async h=>({result:q.$Sync`python -c "${h.code}"`})},ne={name:"read_webpage",description:"Extract clean, structured content from a webpage. Use after web_search to read specific URLs",args:{url:{type:"string",description:"URL to extract content from",required:!0},focus:{type:"string",description:'Optional: What aspect to focus on (e.g., "pricing", "features", "contact info")'}},fn:async h=>{const n=await fetch(h.url,{headers:{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}}).then(r=>r.text()).catch(r=>{throw new Error(`Failed to fetch: ${r.message}`)}),e=V.load(n);e('script, style, nav, footer, header, aside, iframe, noscript, [role="navigation"], [role="banner"], .ad, .ads, .cookie, .popup').remove();const t={title:e('meta[property="og:title"]').attr("content")||e("title").text()||"",description:e('meta[name="description"]').attr("content")||e('meta[property="og:description"]').attr("content")||""};let a="";const s=["article","main",'[role="main"]',".content",".post",".entry","body"];for(const r of s){const c=e(r).first();if(c.length&&c.text().trim().length>200){a=c.text();break}}return a||(a=e("body").text()),a=a.replace(/\s+/g," ").trim().slice(0,8e3),{url:h.url,title:t.title.trim(),description:t.description.trim(),content:a,focus:h.focus}}},re={name:"web_search",description:"Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool",args:{query:{type:"string",description:"Search string",required:!0},length:{type:"string",description:"Number of results to return",default:5}},fn:async h=>{const n=await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(h.query)}`,{headers:{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)","Accept-Language":"en-US,en;q=0.9"}}).then(s=>s.text());let e,t=/<a .*?href="(.+?)".+?<\/a>/g;const a=new g.ASet;for(;(e=t.exec(n))!==null;){let s=/uddg=(.+)&amp?/.exec(decodeURIComponent(e[1]))?.[1];if(s&&(s=decodeURIComponent(s)),s&&a.add(s),a.size>=(h.length||5))break}return a}};exports.Ai=Z;exports.Anthropic=z;exports.Audio=L;exports.CliTool=C;exports.DateTimeTool=X;exports.ExecTool=ee;exports.FetchTool=te;exports.JSTool=J;exports.LLMProvider=P;exports.OpenAi=j;exports.PythonTool=F;exports.ReadWebpageTool=ne;exports.Vision=W;exports.WebSearchTool=re;
50
50
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/provider.ts","../src/antrhopic.ts","../src/open-ai.ts","../src/llm.ts","../src/audio.ts","../src/vision.ts","../src/ai.ts","../src/tools.ts"],"sourcesContent":["import {AbortablePromise} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\n\nexport abstract class LLMProvider {\n\tabstract ask(message: string, options: LLMRequest): AbortablePromise<string>;\n}\n","import {Anthropic as anthropic} from '@anthropic-ai/sdk';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class Anthropic extends LLMProvider {\n\tclient!: anthropic;\n\n\tconstructor(public readonly ai: Ai, public readonly apiToken: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new anthropic({apiKey: apiToken});\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tconst timestamp = Date.now();\n\t\tconst messages: LLMMessage[] = [];\n\t\tfor(let h of history) {\n\t\t\tif(typeof h.content == 'string') {\n\t\t\t\tmessages.push(<any>{timestamp, ...h});\n\t\t\t} else {\n\t\t\t\tconst textContent = h.content?.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n');\n\t\t\t\tif(textContent) messages.push({timestamp, role: h.role, content: textContent});\n\t\t\t\th.content.forEach((c: any) => {\n\t\t\t\t\tif(c.type == 'tool_use') {\n\t\t\t\t\t\tmessages.push({timestamp, role: 'tool', id: c.id, name: c.name, args: c.input, content: undefined});\n\t\t\t\t\t} else if(c.type == 'tool_result') {\n\t\t\t\t\t\tconst m: any = messages.findLast(m => (<any>m).id == c.tool_use_id);\n\t\t\t\t\t\tif(m) m[c.is_error ? 'error' : 'content'] = c.content;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn messages;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tif(history[i].role == 'tool') {\n\t\t\t\tconst h: any = history[i];\n\t\t\t\thistory.splice(i, 1,\n\t\t\t\t\t{role: 'assistant', content: [{type: 'tool_use', id: h.id, name: h.name, input: h.args}]},\n\t\t\t\t\t{role: 'user', content: [{type: 'tool_result', tool_use_id: h.id, is_error: !!h.error, content: h.error || h.content}]}\n\t\t\t\t)\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\treturn history.map(({timestamp, ...h}) => h);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res) => {\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\tsystem: options.system || this.ai.options.llm?.system || '',\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\tname: t.name,\n\t\t\t\t\tdescription: t.description,\n\t\t\t\t\tinput_schema: {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t},\n\t\t\t\t\tfn: undefined\n\t\t\t\t})),\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.messages.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\t// Streaming mode\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.content = [];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.type === 'content_block_start') {\n\t\t\t\t\t\t\tif(chunk.content_block.type === 'text') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'text', text: ''});\n\t\t\t\t\t\t\t} else if(chunk.content_block.type === 'tool_use') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'tool_use', id: chunk.content_block.id, name: chunk.content_block.name, input: <any>''});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_delta') {\n\t\t\t\t\t\t\tif(chunk.delta.type === 'text_delta') {\n\t\t\t\t\t\t\t\tconst text = chunk.delta.text;\n\t\t\t\t\t\t\t\tresp.content.at(-1).text += text;\n\t\t\t\t\t\t\t\toptions.stream({text});\n\t\t\t\t\t\t\t} else if(chunk.delta.type === 'input_json_delta') {\n\t\t\t\t\t\t\t\tresp.content.at(-1).input += chunk.delta.partial_json;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_stop') {\n\t\t\t\t\t\t\tconst last = resp.content.at(-1);\n\t\t\t\t\t\t\tif(last.input != null) last.input = last.input ? JSONAttemptParse(last.input, {}) : {};\n\t\t\t\t\t\t} else if(chunk.type === 'message_stop') {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Run tools\n\t\t\t\tconst toolCalls = resp.content.filter((c: any) => c.type === 'tool_use');\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push({role: 'assistant', content: resp.content});\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools.find(findByProp('name', toolCall.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.name});\n\t\t\t\t\t\tif(!tool) return {tool_use_id: toolCall.id, is_error: true, content: 'Tool not found'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await tool.fn(toolCall.input, options?.stream, this.ai);\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, is_error: true, content: err?.message || err?.toString() || 'Unknown'};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push({role: 'user', content: results});\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.content.some((c: any) => c.type === 'tool_use'));\n\t\t\thistory.push({role: 'assistant', content: resp.content.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n')});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {OpenAI as openAI} from 'openai';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse, clean} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class OpenAi extends LLMProvider {\n\tclient!: openAI;\n\n\tconstructor(public readonly ai: Ai, public readonly host: string | null, public readonly token: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new openAI(clean({\n\t\t\tbaseURL: host,\n\t\t\tapiKey: token || host ? 'ignored' : undefined\n\t\t}));\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tconst h = history[i];\n\t\t\tif(h.role === 'assistant' && h.tool_calls) {\n\t\t\t\tconst tools = h.tool_calls.map((tc: any) => ({\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\tname: tc.function.name,\n\t\t\t\t\targs: JSONAttemptParse(tc.function.arguments, {}),\n\t\t\t\t\ttimestamp: h.timestamp\n\t\t\t\t}));\n\t\t\t\thistory.splice(i, 1, ...tools);\n\t\t\t\ti += tools.length - 1;\n\t\t\t} else if(h.role === 'tool' && h.content) {\n\t\t\t\tconst record = history.find(h2 => h.tool_call_id == h2.id);\n\t\t\t\tif(record) {\n\t\t\t\t\tif(h.content.includes('\"error\":')) record.error = h.content;\n\t\t\t\t\telse record.content = h.content;\n\t\t\t\t}\n\t\t\t\thistory.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t\tif(!history[i]?.timestamp) history[i].timestamp = Date.now();\n\t\t}\n\t\treturn history;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\treturn history.reduce((result, h) => {\n\t\t\tif(h.role === 'tool') {\n\t\t\t\tresult.push({\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: null,\n\t\t\t\t\ttool_calls: [{ id: h.id, type: 'function', function: { name: h.name, arguments: JSON.stringify(h.args) } }],\n\t\t\t\t\trefusal: null,\n\t\t\t\t\tannotations: []\n\t\t\t\t}, {\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\ttool_call_id: h.id,\n\t\t\t\t\tcontent: h.error || h.content\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst {timestamp, ...rest} = h;\n\t\t\t\tresult.push(rest);\n\t\t\t}\n\t\t\treturn result;\n\t\t}, [] as any[]);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res, rej) => {\n\t\t\tif(options.system) {\n\t\t\t\tif(options.history?.[0]?.role != 'system') options.history?.splice(0, 0, {role: 'system', content: options.system, timestamp: Date.now()});\n\t\t\t\telse options.history[0].content = options.system;\n\t\t\t}\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\ttype: 'function',\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: t.name,\n\t\t\t\t\t\tdescription: t.description,\n\t\t\t\t\t\tparameters: {\n\t\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.chat.completions.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.choices = [{message: {role: 'assistant', content: '', tool_calls: []}}];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.choices[0].delta.content) {\n\t\t\t\t\t\t\tresp.choices[0].message.content += chunk.choices[0].delta.content;\n\t\t\t\t\t\t\toptions.stream({text: chunk.choices[0].delta.content});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\tfor(const deltaTC of chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\t\tconst existing = resp.choices[0].message.tool_calls.find(tc => tc.index === deltaTC.index);\n\t\t\t\t\t\t\t\tif(existing) {\n\t\t\t\t\t\t\t\t\tif(deltaTC.id) existing.id = deltaTC.id;\n\t\t\t\t\t\t\t\t\tif(deltaTC.type) existing.type = deltaTC.type;\n\t\t\t\t\t\t\t\t\tif(deltaTC.function) {\n\t\t\t\t\t\t\t\t\t\tif(!existing.function) existing.function = {};\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.name) existing.function.name = deltaTC.function.name;\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.arguments) existing.function.arguments = (existing.function.arguments || '') + deltaTC.function.arguments;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tresp.choices[0].message.tool_calls.push({\n\t\t\t\t\t\t\t\t\t\tindex: deltaTC.index,\n\t\t\t\t\t\t\t\t\t\tid: deltaTC.id || '',\n\t\t\t\t\t\t\t\t\t\ttype: deltaTC.type || 'function',\n\t\t\t\t\t\t\t\t\t\tfunction: {\n\t\t\t\t\t\t\t\t\t\t\tname: deltaTC.function?.name || '',\n\t\t\t\t\t\t\t\t\t\t\targuments: deltaTC.function?.arguments || ''\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst toolCalls = resp.choices[0].message.tool_calls || [];\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push(resp.choices[0].message);\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools?.find(findByProp('name', toolCall.function.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.function.name});\n\t\t\t\t\t\tif(!tool) return {role: 'tool', tool_call_id: toolCall.id, content: '{\"error\": \"Tool not found\"}'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst args = JSONAttemptParse(toolCall.function.arguments, {});\n\t\t\t\t\t\t\tconst result = await tool.fn(args, options.stream, this.ai);\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'})};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push(...results);\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.choices?.[0]?.message?.tool_calls?.length);\n\t\t\thistory.push({role: 'assistant', content: resp.choices[0].message.content || ''});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {Anthropic} from './antrhopic.ts';\nimport {OpenAi} from './open-ai.ts';\nimport {LLMProvider} from './provider.ts';\nimport {AiTool} from './tools.ts';\nimport {fileURLToPath} from 'url';\nimport {dirname, join} from 'path';\nimport { spawn } from 'node:child_process';\n\nexport type AnthropicConfig = {proto: 'anthropic', token: string};\nexport type OllamaConfig = {proto: 'ollama', host: string};\nexport type OpenAiConfig = {proto: 'openai', host?: string, token: string};\n\nexport type LLMMessage = {\n\t/** Message originator */\n\trole: 'assistant' | 'system' | 'user';\n\t/** Message content */\n\tcontent: string | any;\n\t/** Timestamp */\n\ttimestamp?: number;\n} | {\n\t/** Tool call */\n\trole: 'tool';\n\t/** Unique ID for call */\n\tid: string;\n\t/** Tool that was run */\n\tname: string;\n\t/** Tool arguments */\n\targs: any;\n\t/** Tool result */\n\tcontent: undefined | string;\n\t/** Tool error */\n\terror?: undefined | string;\n\t/** Timestamp */\n\ttimestamp?: number;\n}\n\n/** Background information the AI will be fed */\nexport type LLMMemory = {\n\t/** What entity is this fact about */\n\towner: string;\n\t/** The information that will be remembered */\n\tfact: string;\n\t/** Owner and fact embedding vector */\n\tembeddings: [number[], number[]];\n}\n\nexport type LLMRequest = {\n\t/** System prompt */\n\tsystem?: string;\n\t/** Message history */\n\thistory?: LLMMessage[];\n\t/** Max tokens for request */\n\tmax_tokens?: number;\n\t/** 0 = Rigid Logic, 1 = Balanced, 2 = Hyper Creative **/\n\ttemperature?: number;\n\t/** Available tools */\n\ttools?: AiTool[];\n\t/** LLM model */\n\tmodel?: string;\n\t/** Stream response */\n\tstream?: (chunk: {text?: string, tool?: string, done?: true}) => any;\n\t/** Compress old messages in the chat to free up context */\n\tcompress?: {\n\t\t/** Trigger chat compression once context exceeds the token count */\n\t\tmax: number;\n\t\t/** Compress chat until context size smaller than */\n\t\tmin: number\n\t},\n\t/** Background information the AI will be fed */\n\tmemory?: LLMMemory[],\n}\n\nclass LLM {\n\tdefaultModel!: string;\n\tmodels: {[model: string]: LLMProvider} = {};\n\n\tconstructor(public readonly ai: Ai) {\n\t\tif(!ai.options.llm?.models) return;\n\t\tObject.entries(ai.options.llm.models).forEach(([model, config]) => {\n\t\t\tif(!this.defaultModel) this.defaultModel = model;\n\t\t\tif(config.proto == 'anthropic') this.models[model] = new Anthropic(this.ai, config.token, model);\n\t\t\telse if(config.proto == 'ollama') this.models[model] = new OpenAi(this.ai, config.host, 'not-needed', model);\n\t\t\telse if(config.proto == 'openai') this.models[model] = new OpenAi(this.ai, config.host || null, config.token, model);\n\t\t});\n\t}\n\n\t/**\n\t * Chat with LLM\n\t * @param {string} message Question\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {{abort: () => void, response: Promise<string>}} Function to abort response and chat history\n\t */\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\toptions = <any>{\n\t\t\tsystem: '',\n\t\t\ttemperature: 0.8,\n\t\t\t...this.ai.options.llm,\n\t\t\tmodels: undefined,\n\t\t\thistory: [],\n\t\t\t...options,\n\t\t}\n\t\tconst m = options.model || this.defaultModel;\n\t\tif(!this.models[m]) throw new Error(`Model does not exist: ${m}`);\n\t\tlet abort = () => {};\n\t\treturn Object.assign(new Promise<string>(async res => {\n\t\t\tif(!options.history) options.history = [];\n\t\t\t// If memories were passed, find any relevant ones and add a tool for ADHOC lookups\n\t\t\tif(options.memory) {\n\t\t\t\tconst search = async (query?: string | null, subject?: string | null, limit = 10) => {\n\t\t\t\t\tconst [o, q] = await Promise.all([\n\t\t\t\t\t\tsubject ? this.embedding(subject) : Promise.resolve(null),\n\t\t\t\t\t\tquery ? this.embedding(query) : Promise.resolve(null),\n\t\t\t\t\t]);\n\t\t\t\t\treturn (options.memory || []).map(m => {\n\t\t\t\t\t\tconst score = (o ? this.cosineSimilarity(m.embeddings[0], o[0].embedding) : 0)\n\t\t\t\t\t\t\t+ (q ? this.cosineSimilarity(m.embeddings[1], q[0].embedding) : 0);\n\t\t\t\t\t\treturn {...m, score};\n\t\t\t\t\t}).toSorted((a: any, b: any) => a.score - b.score).slice(0, limit);\n\t\t\t\t}\n\n\t\t\t\toptions.system += '\\nYou have RAG memory and will be given the top_k closest memories regarding the users query. Save anything new you have learned worth remembering from the user message using the remember tool and feel free to recall memories manually.\\n';\n\t\t\t\tconst relevant = await search(message);\n\t\t\t\tif(relevant.length) options.history.push({role: 'tool', name: 'recall', id: 'auto_recall_' + Math.random().toString(), args: {}, content: 'Things I remembered:\\n' + relevant.map(m => `${m.owner}: ${m.fact}`).join('\\n')});\n\t\t\t\toptions.tools = [{\n\t\t\t\t\tname: 'recall',\n\t\t\t\t\tdescription: 'Recall the closest memories you have regarding a query using RAG',\n\t\t\t\t\targs: {\n\t\t\t\t\t\tsubject: {type: 'string', description: 'Find information by a subject topic, can be used with or without query argument'},\n\t\t\t\t\t\tquery: {type: 'string', description: 'Search memory based on a query, can be used with or without subject argument'},\n\t\t\t\t\t\ttopK: {type: 'number', description: 'Result limit, default 5'},\n\t\t\t\t\t},\n\t\t\t\t\tfn: (args) => {\n\t\t\t\t\t\tif(!args.subject && !args.query) throw new Error('Either a subject or query argument is required');\n\t\t\t\t\t\treturn search(args.query, args.subject, args.topK);\n\t\t\t\t\t}\n\t\t\t\t}, {\n\t\t\t\t\tname: 'remember',\n\t\t\t\t\tdescription: 'Store important facts user shares for future recall',\n\t\t\t\t\targs: {\n\t\t\t\t\t\towner: {type: 'string', description: 'Subject/person this fact is about'},\n\t\t\t\t\t\tfact: {type: 'string', description: 'The information to remember'}\n\t\t\t\t\t},\n\t\t\t\t\tfn: async (args) => {\n\t\t\t\t\t\tif(!options.memory) return;\n\t\t\t\t\t\tconst e = await Promise.all([\n\t\t\t\t\t\t\tthis.embedding(args.owner),\n\t\t\t\t\t\t\tthis.embedding(`${args.owner}: ${args.fact}`)\n\t\t\t\t\t\t]);\n\t\t\t\t\t\tconst newMem = {owner: args.owner, fact: args.fact, embeddings: <any>[e[0][0].embedding, e[1][0].embedding]};\n\t\t\t\t\t\toptions.memory.splice(0, options.memory.length, ...[\n\t\t\t\t\t\t\t...options.memory.filter(m => {\n\t\t\t\t\t\t\t\treturn !(this.cosineSimilarity(newMem.embeddings[0], m.embeddings[0]) >= 0.9 && this.cosineSimilarity(newMem.embeddings[1], m.embeddings[1]) >= 0.8);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tnewMem\n\t\t\t\t\t\t]);\n\t\t\t\t\t\treturn 'Remembered!';\n\t\t\t\t\t}\n\t\t\t\t}, ...options.tools || []];\n\t\t\t}\n\n\t\t\t// Ask\n\t\t\tconst resp = await this.models[m].ask(message, options);\n\n\t\t\t// Remove any memory calls from history\n\t\t\tif(options.memory) options.history.splice(0, options.history.length, ...options.history.filter(h => h.role != 'tool' || (h.name != 'recall' && h.name != 'remember')));\n\n\t\t\t// Compress message history\n\t\t\tif(options.compress) {\n\t\t\t\tconst compressed = await this.ai.language.compressHistory(options.history, options.compress.max, options.compress.min, options);\n\t\t\t\toptions.history.splice(0, options.history.length, ...compressed);\n\t\t\t}\n\n\t\t\treturn res(resp);\n\t\t}), {abort});\n\t}\n\n\tasync code(message: string, options?: LLMRequest): Promise<any> {\n\t\tconst resp = await this.ask(message, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t'Return your response in a code block'\n\t\t].filter(t => !!t).join(('\\n'))});\n\t\tconst codeBlock = /```(?:.+)?\\s*([\\s\\S]*?)```/.exec(resp);\n\t\treturn codeBlock ? codeBlock[1].trim() : null;\n\t}\n\n\t/**\n\t * Compress chat history to reduce context size\n\t * @param {LLMMessage[]} history Chatlog that will be compressed\n\t * @param max Trigger compression once context is larger than max\n\t * @param min Leave messages less than the token minimum, summarize the rest\n\t * @param {LLMRequest} options LLM options\n\t * @returns {Promise<LLMMessage[]>} New chat history will summary at index 0\n\t */\n\tasync compressHistory(history: LLMMessage[], max: number, min: number, options?: LLMRequest): Promise<LLMMessage[]> {\n\t\tif(this.estimateTokens(history) < max) return history;\n\t\tlet keep = 0, tokens = 0;\n\t\tfor(let m of history.toReversed()) {\n\t\t\ttokens += this.estimateTokens(m.content);\n\t\t\tif(tokens < min) keep++;\n\t\t\telse break;\n\t\t}\n\t\tif(history.length <= keep) return history;\n\t\tconst system = history[0].role == 'system' ? history[0] : null,\n\t\t\trecent = keep == 0 ? [] : history.slice(-keep),\n\t\t\tprocess = (keep == 0 ? history : history.slice(0, -keep)).filter(h => h.role === 'assistant' || h.role === 'user');\n\n\t\tconst summary: any = await this.summarize(process.map(m => `[${m.role}]: ${m.content}`).join('\\n\\n'), 500, options);\n\t\tconst d = Date.now();\n\t\tconst h = [{role: <any>'tool', name: 'summary', id: `summary_` + d, args: {}, content: `Conversation Summary: ${summary?.summary}`, timestamp: d}, ...recent];\n\t\tif(system) h.splice(0, 0, system);\n\t\treturn h;\n\t}\n\n\t/**\n\t * Compare the difference between embeddings (calculates the angle between two vectors)\n\t * @param {number[]} v1 First embedding / vector comparison\n\t * @param {number[]} v2 Second embedding / vector for comparison\n\t * @returns {number} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tcosineSimilarity(v1: number[], v2: number[]): number {\n\t\tif (v1.length !== v2.length) throw new Error('Vectors must be same length');\n\t\tlet dotProduct = 0, normA = 0, normB = 0;\n\t\tfor (let i = 0; i < v1.length; i++) {\n\t\t\tdotProduct += v1[i] * v2[i];\n\t\t\tnormA += v1[i] * v1[i];\n\t\t\tnormB += v2[i] * v2[i];\n\t\t}\n\t\tconst denominator = Math.sqrt(normA) * Math.sqrt(normB);\n\t\treturn denominator === 0 ? 0 : dotProduct / denominator;\n\t}\n\n\t/**\n\t * Chunk text into parts for AI digestion\n\t * @param {object | string} target Item that will be chunked (objects get converted)\n\t * @param {number} maxTokens Chunking size. More = better context, less = more specific (Search by paragraphs or lines)\n\t * @param {number} overlapTokens Includes previous X tokens to provide continuity to AI (In addition to max tokens)\n\t * @returns {string[]} Chunked strings\n\t */\n\tchunk(target: object | string, maxTokens = 500, overlapTokens = 50): string[] {\n\t\tconst objString = (obj: any, path = ''): string[] => {\n\t\t\tif(!obj) return [];\n\t\t\treturn Object.entries(obj).flatMap(([key, value]) => {\n\t\t\t\tconst p = path ? `${path}${isNaN(+key) ? `.${key}` : `[${key}]`}` : key;\n\t\t\t\tif(typeof value === 'object' && !Array.isArray(value)) return objString(value, p);\n\t\t\t\treturn `${p}: ${Array.isArray(value) ? value.join(', ') : value}`;\n\t\t\t});\n\t\t};\n\t\tconst lines = typeof target === 'object' ? objString(target) : target.toString().split('\\n');\n\t\tconst tokens = lines.flatMap(l => [...l.split(/\\s+/).filter(Boolean), '\\n']);\n\t\tconst chunks: string[] = [];\n\t\tfor(let i = 0; i < tokens.length;) {\n\t\t\tlet text = '', j = i;\n\t\t\twhile(j < tokens.length) {\n\t\t\t\tconst next = text + (text ? ' ' : '') + tokens[j];\n\t\t\t\tif(this.estimateTokens(next.replace(/\\s*\\n\\s*/g, '\\n')) > maxTokens && text) break;\n\t\t\t\ttext = next;\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tconst clean = text.replace(/\\s*\\n\\s*/g, '\\n').trim();\n\t\t\tif(clean) chunks.push(clean);\n\t\t\ti = Math.max(j - overlapTokens, j === i ? i + 1 : j);\n\t\t}\n\t\treturn chunks;\n\t}\n\n\t/**\n\t * Create a vector representation of a string\n\t * @param {object | string} target Item that will be embedded (objects get converted)\n\t * @param {maxTokens?: number, overlapTokens?: number} opts Options for embedding such as chunk sizes\n\t * @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings\n\t */\n\tembedding(target: object | string, opts: {maxTokens?: number, overlapTokens?: number} = {}): AbortablePromise<any[]> {\n\t\tlet {maxTokens = 500, overlapTokens = 50} = opts;\n\t\tlet aborted = false;\n\t\tconst abort = () => { aborted = true; };\n\n\t\tconst embed = (text: string): Promise<number[]> => {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\n\t\t\t\tconst args: string[] = [\n\t\t\t\t\tjoin(dirname(fileURLToPath(import.meta.url)), 'embedder.js'),\n\t\t\t\t\t<string>this.ai.options.path,\n\t\t\t\t\tthis.ai.options?.embedder || 'bge-small-en-v1.5'\n\t\t\t\t];\n\t\t\t\tconst proc = spawn('node', args, {stdio: ['pipe', 'pipe', 'ignore']});\n\t\t\t\tproc.stdin.write(text);\n\t\t\t\tproc.stdin.end();\n\n\t\t\t\tlet output = '';\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = JSON.parse(output);\n\t\t\t\t\t\t\tresolve(result.embedding);\n\t\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t\treject(new Error('Failed to parse embedding output'));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Embedder process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t});\n\t\t};\n\n\t\tconst p = (async () => {\n\t\t\tconst chunks = this.chunk(target, maxTokens, overlapTokens), results: any[] = [];\n\t\t\tfor(let i = 0; i < chunks.length; i++) {\n\t\t\t\tif(aborted) break;\n\t\t\t\tconst text = chunks[i];\n\t\t\t\tconst embedding = await embed(text);\n\t\t\t\tresults.push({index: i, embedding, text, tokens: this.estimateTokens(text)});\n\t\t\t}\n\t\t\treturn results;\n\t\t})();\n\t\treturn Object.assign(p, { abort });\n\t}\n\n\t/**\n\t * Estimate variable as tokens\n\t * @param history Object to size\n\t * @returns {number} Rough token count\n\t */\n\testimateTokens(history: any): number {\n\t\tconst text = JSON.stringify(history);\n\t\treturn Math.ceil((text.length / 4) * 1.2);\n\t}\n\n\t/**\n\t * Compare the difference between two strings using tensor math\n\t * @param target Text that will be checked\n\t * @param {string} searchTerms Multiple search terms to check against target\n\t * @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tfuzzyMatch(target: string, ...searchTerms: string[]) {\n\t\tif(searchTerms.length < 2) throw new Error('Requires at least 2 strings to compare');\n\t\tconst vector = (text: string, dimensions: number = 10): number[] => {\n\t\t\treturn text.toLowerCase().split('').map((char, index) =>\n\t\t\t\t(char.charCodeAt(0) * (index + 1)) % dimensions / dimensions).slice(0, dimensions);\n\t\t}\n\t\tconst v = vector(target);\n\t\tconst similarities = searchTerms.map(t => vector(t)).map(refVector => this.cosineSimilarity(v, refVector))\n\t\treturn {avg: similarities.reduce((acc, s) => acc + s, 0) / similarities.length, max: Math.max(...similarities), similarities}\n\t}\n\n\t/**\n\t * Ask a question with JSON response\n\t * @param {string} text Text to process\n\t * @param {string} schema JSON schema the AI should match\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {Promise<{} | {} | RegExpExecArray | null>}\n\t */\n\tasync json(text: string, schema: string, options?: LLMRequest): Promise<any> {\n\t\tconst code = await this.code(text, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t`Only respond using JSON matching this schema:\\n\\`\\`\\`json\\n${schema}\\n\\`\\`\\``\n\t\t].filter(t => !!t).join('\\n')});\n\t\treturn code ? JSONAttemptParse(code, {}) : null;\n\t}\n\n\t/**\n\t * Create a summary of some text\n\t * @param {string} text Text to summarize\n\t * @param {number} tokens Max number of tokens\n\t * @param options LLM request options\n\t * @returns {Promise<string>} Summary\n\t */\n\tsummarize(text: string, tokens: number = 500, options?: LLMRequest): Promise<string | null> {\n\t\treturn this.ask(text, {system: `Generate the shortest summary possible <= ${tokens} tokens. Output nothing else`, temperature: 0.3, ...options});\n\t}\n}\n\nexport default LLM;\n","import {execSync, spawn} from 'node:child_process';\nimport {mkdtempSync} from 'node:fs';\nimport fs from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport * as path from 'node:path';\nimport Path, {join} from 'node:path';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Audio {\n\tprivate downloads: {[key: string]: Promise<string>} = {};\n\tprivate pyannote!: string;\n\tprivate whisperModel!: string;\n\n\tconstructor(private ai: Ai) {\n\t\tif(ai.options.whisper) {\n\t\t\tthis.whisperModel = ai.options.asr || 'ggml-base.en.bin';\n\t\t\tthis.downloadAsrModel();\n\t\t}\n\n\t\tthis.pyannote = `\nimport sys\nimport json\nimport os\nfrom pyannote.audio import Pipeline\n\nos.environ['TORCH_HOME'] = r\"${ai.options.path}\"\npipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization-3.1\", token=\"${ai.options.hfToken}\")\noutput = pipeline(sys.argv[1])\n\nsegments = []\nfor turn, speaker in output.speaker_diarization:\n segments.append({\"start\": turn.start, \"end\": turn.end, \"speaker\": speaker})\n\nprint(json.dumps(segments))\n`;\n\t}\n\n\tprivate async addPunctuation(timestampData: any, llm?: boolean, cadence = 150): Promise<string> {\n\t\tconst countSyllables = (word: string): number => {\n\t\t\tword = word.toLowerCase().replace(/[^a-z]/g, '');\n\t\t\tif(word.length <= 3) return 1;\n\t\t\tconst matches = word.match(/[aeiouy]+/g);\n\t\t\tlet count = matches ? matches.length : 1;\n\t\t\tif(word.endsWith('e')) count--;\n\t\t\treturn Math.max(1, count);\n\t\t};\n\n\t\tlet result = '';\n\t\ttimestampData.transcription.filter((word, i) => {\n\t\t\tlet skip = false;\n\t\t\tconst prevWord = timestampData.transcription[i - 1];\n\t\t\tconst nextWord = timestampData.transcription[i + 1];\n\t\t\tif(!word.text && nextWord) {\n\t\t\t\tnextWord.offsets.from = word.offsets.from;\n\t\t\t\tnextWord.timestamps.from = word.offsets.from;\n\t\t\t} else if(word.text && word.text[0] != ' ' && prevWord) {\n\t\t\t\tprevWord.offsets.to = word.offsets.to;\n\t\t\t\tprevWord.timestamps.to = word.timestamps.to;\n\t\t\t\tprevWord.text += word.text;\n\t\t\t\tskip = true;\n\t\t\t}\n\t\t\treturn !!word.text && !skip;\n\t\t}).forEach((word: any) => {\n\t\t\tconst capital = /^[A-Z]/.test(word.text.trim());\n\t\t\tconst length = word.offsets.to - word.offsets.from;\n\t\t\tconst syllables = countSyllables(word.text.trim());\n\t\t\tconst expected = syllables * cadence;\n\t\t\tif(capital && length > expected * 2 && word.text[0] == ' ') result += '.';\n\t\t\tresult += word.text;\n\t\t});\n\t\tif(!llm) return result.trim();\n\t\treturn this.ai.language.ask(result, {\n\t\t\tsystem: 'Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo',\n\t\t\ttemperature: 0.1,\n\t\t\ttools: [{\n\t\t\t\tname: 'replace',\n\t\t\t\tdescription: 'Use find and replace to fix errors',\n\t\t\t\targs: {\n\t\t\t\t\tfind: {type: 'string', description: 'Text to find', required: true},\n\t\t\t\t\treplace: {type: 'string', description: 'Text to replace', required: true}\n\t\t\t\t},\n\t\t\t\tfn: (args) => result = result.replace(args.find, args.replace)\n\t\t\t}]\n\t\t}).then(() => result);\n\t}\n\n\tprivate async diarizeTranscript(timestampData: any, speakers: any[], llm: boolean): Promise<string> {\n\t\tconst speakerMap = new Map();\n\t\tlet speakerCount = 0;\n\t\tspeakers.forEach((seg: any) => {\n\t\t\tif(!speakerMap.has(seg.speaker)) speakerMap.set(seg.speaker, ++speakerCount);\n\t\t});\n\n\t\tconst punctuatedText = await this.addPunctuation(timestampData, llm);\n\t\tconst sentences = punctuatedText.match(/[^.!?]+[.!?]+/g) || [punctuatedText];\n\t\tconst words = timestampData.transcription.filter((w: any) => w.text.trim());\n\n\t\t// Assign speaker to each sentence\n\t\tconst sentencesWithSpeakers = sentences.map(sentence => {\n\t\t\tsentence = sentence.trim();\n\t\t\tif(!sentence) return null;\n\n\t\t\tconst sentenceWords = sentence.toLowerCase().replace(/[^\\w\\s]/g, '').split(/\\s+/);\n\t\t\tconst speakerWordCount = new Map<number, number>();\n\n\t\t\tsentenceWords.forEach(sw => {\n\t\t\t\tconst word = words.find((w: any) => sw === w.text.trim().toLowerCase().replace(/[^\\w]/g, ''));\n\t\t\t\tif(!word) return;\n\n\t\t\t\tconst wordTime = word.offsets.from / 1000;\n\t\t\t\tconst speaker = speakers.find((seg: any) => wordTime >= seg.start && wordTime <= seg.end);\n\t\t\t\tif(speaker) {\n\t\t\t\t\tconst spkNum = speakerMap.get(speaker.speaker);\n\t\t\t\t\tspeakerWordCount.set(spkNum, (speakerWordCount.get(spkNum) || 0) + 1);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tlet bestSpeaker = 1;\n\t\t\tlet maxWords = 0;\n\t\t\tspeakerWordCount.forEach((count, speaker) => {\n\t\t\t\tif(count > maxWords) {\n\t\t\t\t\tmaxWords = count;\n\t\t\t\t\tbestSpeaker = speaker;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn {speaker: bestSpeaker, text: sentence};\n\t\t}).filter(s => s !== null);\n\n\t\t// Merge adjacent sentences from same speaker\n\t\tconst merged: Array<{speaker: number, text: string}> = [];\n\t\tsentencesWithSpeakers.forEach(item => {\n\t\t\tconst last = merged[merged.length - 1];\n\t\t\tif(last && last.speaker === item.speaker) {\n\t\t\t\tlast.text += ' ' + item.text;\n\t\t\t} else {\n\t\t\t\tmerged.push({...item});\n\t\t\t}\n\t\t});\n\n\t\tlet transcript = merged.map(item => `[Speaker ${item.speaker}]: ${item.text}`).join('\\n').trim();\n\t\tif(!llm) return transcript;\n\t\tlet chunks = this.ai.language.chunk(transcript, 500, 0);\n\t\tif(chunks.length > 4) chunks = [...chunks.slice(0, 3), <string>chunks.at(-1)];\n\t\tconst names = await this.ai.language.json(chunks.join('\\n'), '{1: \"Detected Name\", 2: \"Second Name\"}', {\n\t\t\tsystem: 'Use the following transcript to identify speakers. Only identify speakers you are positive about, dont mention speakers you are unsure about in your response',\n\t\t\ttemperature: 0.1,\n\t\t});\n\t\tObject.entries(names).forEach(([speaker, name]) => transcript = transcript.replaceAll(`[Speaker ${speaker}]`, `[${name}]`));\n\t\treturn transcript;\n\t}\n\n\tprivate runAsr(file: string, opts: {model?: string, diarization?: boolean} = {}): AbortablePromise<any> {\n\t\tlet proc: any;\n\t\tconst p = new Promise<any>((resolve, reject) => {\n\t\t\tthis.downloadAsrModel(opts.model).then(m => {\n\t\t\t\tif(opts.diarization) {\n\t\t\t\t\tlet output = path.join(path.dirname(file), 'transcript');\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper,\n\t\t\t\t\t\t['-m', m, '-f', file, '-np', '-ml', '1', '-oj', '-of', output],\n\t\t\t\t\t\t{stdio: ['ignore', 'ignore', 'pipe']}\n\t\t\t\t\t);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\toutput = await fs.readFile(output + '.json', 'utf-8');\n\t\t\t\t\t\t\tfs.rm(output + '.json').catch(() => { });\n\t\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\t\tcatch(e) { reject(new Error('Failed to parse whisper JSON')); }\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlet output = '';\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper, ['-m', m, '-f', file, '-np', '-nt']);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\tresolve(output.trim() || null);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\treturn <any>Object.assign(p, {abort: () => proc?.kill('SIGTERM')});\n\t}\n\n\tprivate runDiarization(file: string): AbortablePromise<any> {\n\t\tlet aborted = false, abort = () => { aborted = true; };\n\t\tconst checkPython = (cmd: string) => {\n\t\t\treturn new Promise<boolean>((resolve) => {\n\t\t\t\tconst proc = spawn(cmd, ['-W', 'ignore', '-c', 'import pyannote.audio']);\n\t\t\t\tproc.on('close', (code: number) => resolve(code === 0));\n\t\t\t\tproc.on('error', () => resolve(false));\n\t\t\t});\n\t\t};\n\t\tconst p = Promise.all<any>([\n\t\t\tcheckPython('python'),\n\t\t\tcheckPython('python3'),\n\t\t]).then(<any>(async ([p, p3]: [boolean, boolean]) => {\n\t\t\tif(aborted) return;\n\t\t\tif(!p && !p3) throw new Error('Pyannote is not installed: pip install pyannote.audio');\n\t\t\tconst binary = p3 ? 'python3' : 'python';\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return;\n\t\t\t\tlet output = '';\n\t\t\t\tconst proc = spawn(binary, ['-W', 'ignore', '-c', this.pyannote, file]);\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.stderr.on('data', (data: Buffer) => console.error(data.toString()));\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\tcatch (err) { reject(new Error('Failed to parse diarization output')); }\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Python process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t\tabort = () => proc.kill('SIGTERM');\n\t\t\t});\n\t\t}));\n\t\treturn <any>Object.assign(p, {abort});\n\t}\n\n\tasr(file: string, options: { model?: string; diarization?: boolean | 'llm' } = {}): AbortablePromise<string | null> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\n\t\tconst tmp = join(mkdtempSync(join(tmpdir(), 'audio-')), 'converted.wav');\n\t\texecSync(`ffmpeg -i \"${file}\" -ar 16000 -ac 1 -f wav \"${tmp}\"`, { stdio: 'ignore' });\n\t\tconst clean = () => fs.rm(Path.dirname(tmp), {recursive: true, force: true}).catch(() => {});\n\n\t\tif(!options.diarization) return this.runAsr(tmp, {model: options.model});\n\t\tconst timestamps = this.runAsr(tmp, {model: options.model, diarization: true});\n\t\tconst diarization = this.runDiarization(tmp);\n\t\tlet aborted = false, abort = () => {\n\t\t\taborted = true;\n\t\t\ttimestamps.abort();\n\t\t\tdiarization.abort();\n\t\t\tclean();\n\t\t};\n\n\t\tconst response = Promise.allSettled([timestamps, diarization]).then(async ([ts, d]) => {\n\t\t\tif(ts.status == 'rejected') throw new Error('Whisper.cpp timestamps:\\n' + ts.reason);\n\t\t\tif(d.status == 'rejected') throw new Error('Pyannote:\\n' + d.reason);\n\t\t\tif(aborted || !options.diarization) return ts.value;\n\t\t\treturn this.diarizeTranscript(ts.value, d.value, options.diarization == 'llm');\n\t\t}).finally(() => clean());\n\t\treturn <any>Object.assign(response, {abort});\n\t}\n\n\tasync downloadAsrModel(model: string = this.whisperModel): Promise<string> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\t\tif(!model.endsWith('.bin')) model += '.bin';\n\t\tconst p = Path.join(<string>this.ai.options.path, model);\n\t\tif(await fs.stat(p).then(() => true).catch(() => false)) return p;\n\t\tif(!!this.downloads[model]) return this.downloads[model];\n\t\tthis.downloads[model] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${model}`)\n\t\t\t.then(resp => resp.arrayBuffer())\n\t\t\t.then(arr => Buffer.from(arr)).then(async buffer => {\n\t\t\t\tawait fs.writeFile(p, buffer);\n\t\t\t\tdelete this.downloads[model];\n\t\t\t\treturn p;\n\t\t\t});\n\t\treturn this.downloads[model];\n\t}\n}\n","import {createWorker} from 'tesseract.js';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Vision {\n\n\tconstructor(private ai: Ai) {}\n\n\t/**\n\t * Convert image to text using Optical Character Recognition\n\t * @param {string} path Path to image\n\t * @returns {AbortablePromise<string | null>} Promise of extracted text with abort method\n\t */\n\tocr(path: string): AbortablePromise<string | null> {\n\t\tlet worker: any;\n\t\tconst p = new Promise<string | null>(async res => {\n\t\t\tworker = await createWorker(this.ai.options.ocr || 'eng', 2, {cachePath: this.ai.options.path});\n\t\t\tconst {data} = await worker.recognize(path);\n\t\t\tawait worker.terminate();\n\t\t\tres(data.text.trim() || null);\n\t\t});\n\t\treturn Object.assign(p, {abort: () => worker?.terminate()});\n\t}\n}\n","import * as os from 'node:os';\nimport LLM, {AnthropicConfig, OllamaConfig, OpenAiConfig, LLMRequest} from './llm';\nimport { Audio } from './audio.ts';\nimport {Vision} from './vision.ts';\n\nexport type AbortablePromise<T> = Promise<T> & {\n\tabort: () => any\n};\n\nexport type AiOptions = {\n\t/** Token to pull models from hugging face */\n\thfToken?: string;\n\t/** Path to models */\n\tpath?: string;\n\t/** Whisper ASR model: ggml-tiny.en.bin, ggml-base.en.bin */\n\tasr?: string;\n\t/** Embedding model: all-MiniLM-L6-v2, bge-small-en-v1.5, bge-large-en-v1.5 */\n\tembedder?: string;\n\t/** Large language models, first is default */\n\tllm?: Omit<LLMRequest, 'model'> & {\n\t\tmodels: {[model: string]: AnthropicConfig | OllamaConfig | OpenAiConfig};\n\t}\n\t/** OCR model: eng, eng_best, eng_fast */\n\tocr?: string;\n\t/** Whisper binary */\n\twhisper?: string;\n}\n\nexport class Ai {\n\t/** Audio processing AI */\n\taudio!: Audio;\n\t/** Language processing AI */\n\tlanguage!: LLM;\n\t/** Vision processing AI */\n\tvision!: Vision;\n\n\tconstructor(public readonly options: AiOptions) {\n\t\tif(!options.path) options.path = os.tmpdir();\n\t\tprocess.env.TRANSFORMERS_CACHE = options.path;\n\t\tthis.audio = new Audio(this);\n\t\tthis.language = new LLM(this);\n\t\tthis.vision = new Vision(this);\n\t}\n}\n","import * as cheerio from 'cheerio';\nimport {$Sync} from '@ztimson/node-utils';\nimport {ASet, consoleInterceptor, Http, fn as Fn} from '@ztimson/utils';\nimport * as os from 'node:os';\nimport {Ai} from './ai.ts';\nimport {LLMRequest} from './llm.ts';\n\nconst getShell = () => {\n\tif(os.platform() == 'win32') return 'cmd';\n\treturn $Sync`echo $SHELL`?.split('/').pop() || 'bash';\n}\n\nexport type AiToolArg = {[key: string]: {\n\t/** Argument type */\n\ttype: 'array' | 'boolean' | 'number' | 'object' | 'string',\n\t/** Argument description */\n\tdescription: string,\n\t/** Required argument */\n\trequired?: boolean;\n\t/** Default value */\n\tdefault?: any,\n\t/** Options */\n\tenum?: string[],\n\t/** Minimum value or length */\n\tmin?: number,\n\t/** Maximum value or length */\n\tmax?: number,\n\t/** Match pattern */\n\tpattern?: string,\n\t/** Child arguments */\n\titems?: {[key: string]: AiToolArg}\n}}\n\nexport type AiTool = {\n\t/** Tool ID / Name - Must be snail_case */\n\tname: string,\n\t/** Tool description / prompt */\n\tdescription: string,\n\t/** Tool arguments */\n\targs?: AiToolArg,\n\t/** Callback function */\n\tfn: (args: any, stream: LLMRequest['stream'], ai: Ai) => any | Promise<any>,\n};\n\nexport const CliTool: AiTool = {\n\tname: 'cli',\n\tdescription: 'Use the command line interface, returns any output',\n\targs: {command: {type: 'string', description: 'Command to run', required: true}},\n\tfn: (args: {command: string}) => $Sync`${args.command}`\n}\n\nexport const DateTimeTool: AiTool = {\n\tname: 'get_datetime',\n\tdescription: 'Get current UTC date / time',\n\targs: {},\n\tfn: async () => new Date().toUTCString()\n}\n\nexport const ExecTool: AiTool = {\n\tname: 'exec',\n\tdescription: 'Run code/scripts',\n\targs: {\n\t\tlanguage: {type: 'string', description: `Execution language (CLI: ${getShell()})`, enum: ['cli', 'node', 'python'], required: true},\n\t\tcode: {type: 'string', description: 'Code to execute', required: true}\n\t},\n\tfn: async (args, stream, ai) => {\n\t\ttry {\n\t\t\tswitch(args.type) {\n\t\t\t\tcase 'cli':\n\t\t\t\t\treturn await CliTool.fn({command: args.code}, stream, ai);\n\t\t\t\tcase 'node':\n\t\t\t\t\treturn await JSTool.fn({code: args.code}, stream, ai);\n\t\t\t\tcase 'python': {\n\t\t\t\t\treturn await PythonTool.fn({code: args.code}, stream, ai);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch(err: any) {\n\t\t\treturn {error: err?.message || err.toString()};\n\t\t}\n\t}\n}\n\nexport const FetchTool: AiTool = {\n\tname: 'fetch',\n\tdescription: 'Make HTTP request to URL',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to fetch', required: true},\n\t\tmethod: {type: 'string', description: 'HTTP method to use', enum: ['GET', 'POST', 'PUT', 'DELETE'], default: 'GET'},\n\t\theaders: {type: 'object', description: 'HTTP headers to send', default: {}},\n\t\tbody: {type: 'object', description: 'HTTP body to send'},\n\t},\n\tfn: (args: {\n\t\turl: string;\n\t\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE';\n\t\theaders: {[key: string]: string};\n\t\tbody: any;\n\t}) => new Http({url: args.url, headers: args.headers}).request({method: args.method || 'GET', body: args.body})\n}\n\nexport const JSTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => {\n\t\tconst console = consoleInterceptor(null);\n\t\tconst resp = await Fn<any>({console}, args.code, true).catch((err: any) => console.output.error.push(err));\n\t\treturn {...console.output, return: resp, stdout: undefined, stderr: undefined};\n\t}\n}\n\nexport const PythonTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => ({result: $Sync`python -c \"${args.code}\"`})\n}\n\nexport const ReadWebpageTool: AiTool = {\n\tname: 'read_webpage',\n\tdescription: 'Extract clean, structured content from a webpage. Use after web_search to read specific URLs',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to extract content from', required: true},\n\t\tfocus: {type: 'string', description: 'Optional: What aspect to focus on (e.g., \"pricing\", \"features\", \"contact info\")'}\n\t},\n\tfn: async (args: {url: string; focus?: string}) => {\n\t\tconst html = await fetch(args.url, {headers: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"}})\n\t\t\t.then(r => r.text()).catch(err => {throw new Error(`Failed to fetch: ${err.message}`)});\n\n\t\tconst $ = cheerio.load(html);\n\t\t$('script, style, nav, footer, header, aside, iframe, noscript, [role=\"navigation\"], [role=\"banner\"], .ad, .ads, .cookie, .popup').remove();\n\t\tconst metadata = {\n\t\t\ttitle: $('meta[property=\"og:title\"]').attr('content') || $('title').text() || '',\n\t\t\tdescription: $('meta[name=\"description\"]').attr('content') || $('meta[property=\"og:description\"]').attr('content') || '',\n\t\t};\n\n\t\tlet content = '';\n\t\tconst contentSelectors = ['article', 'main', '[role=\"main\"]', '.content', '.post', '.entry', 'body'];\n\t\tfor (const selector of contentSelectors) {\n\t\t\tconst el = $(selector).first();\n\t\t\tif (el.length && el.text().trim().length > 200) {\n\t\t\t\tcontent = el.text();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!content) content = $('body').text();\n\t\tcontent = content.replace(/\\s+/g, ' ').trim().slice(0, 8000);\n\n\t\treturn {url: args.url, title: metadata.title.trim(), description: metadata.description.trim(), content, focus: args.focus};\n\t}\n}\n\nexport const WebSearchTool: AiTool = {\n\tname: 'web_search',\n\tdescription: 'Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool',\n\targs: {\n\t\tquery: {type: 'string', description: 'Search string', required: true},\n\t\tlength: {type: 'string', description: 'Number of results to return', default: 5},\n\t},\n\tfn: async (args: {\n\t\tquery: string;\n\t\tlength: number;\n\t}) => {\n\t\tconst html = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(args.query)}`, {\n\t\t\theaders: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\", \"Accept-Language\": \"en-US,en;q=0.9\"}\n\t\t}).then(resp => resp.text());\n\t\tlet match, regex = /<a .*?href=\"(.+?)\".+?<\\/a>/g;\n\t\tconst results = new ASet<string>();\n\t\twhile((match = regex.exec(html)) !== null) {\n\t\t\tlet url = /uddg=(.+)&amp?/.exec(decodeURIComponent(match[1]))?.[1];\n\t\t\tif(url) url = decodeURIComponent(url);\n\t\t\tif(url) results.add(url);\n\t\t\tif(results.size >= (args.length || 5)) break;\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"names":["LLMProvider","Anthropic","ai","apiToken","model","anthropic","history","timestamp","messages","h","textContent","c","m","i","message","options","controller","res","tools","requestParams","t","objectMap","key","value","resp","isFirstMessage","err","chunk","text","last","JSONAttemptParse","toolCalls","results","toolCall","tool","findByProp","result","JSONSanitize","OpenAi","host","token","openAI","clean","tc","record","h2","rest","rej","deltaTC","existing","args","LLM","config","abort","search","query","subject","limit","o","q","score","a","b","relevant","e","newMem","compressed","codeBlock","max","min","keep","tokens","system","recent","process","summary","d","v1","v2","dotProduct","normA","normB","denominator","target","maxTokens","overlapTokens","objString","obj","path","p","l","chunks","j","next","opts","aborted","embed","resolve","reject","join","dirname","fileURLToPath","_documentCurrentScript","proc","spawn","output","data","code","embedding","searchTerms","vector","dimensions","char","index","v","similarities","refVector","acc","s","schema","Audio","timestampData","llm","cadence","countSyllables","word","matches","count","skip","prevWord","nextWord","capital","length","expected","speakers","speakerMap","speakerCount","seg","punctuatedText","sentences","words","w","sentencesWithSpeakers","sentence","sentenceWords","speakerWordCount","sw","wordTime","speaker","spkNum","bestSpeaker","maxWords","merged","item","transcript","names","name","file","fs","checkPython","cmd","p3","binary","tmp","mkdtempSync","tmpdir","execSync","Path","timestamps","diarization","response","ts","arr","buffer","Vision","worker","createWorker","Ai","os","getShell","$Sync","CliTool","DateTimeTool","ExecTool","stream","JSTool","PythonTool","FetchTool","Http","console","consoleInterceptor","Fn","ReadWebpageTool","html","$","cheerio","metadata","content","contentSelectors","selector","el","WebSearchTool","match","regex","ASet","url"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/provider.ts","../src/antrhopic.ts","../src/open-ai.ts","../src/llm.ts","../src/audio.ts","../src/vision.ts","../src/ai.ts","../src/tools.ts"],"sourcesContent":["import {AbortablePromise} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\n\nexport abstract class LLMProvider {\n\tabstract ask(message: string, options: LLMRequest): AbortablePromise<string>;\n}\n","import {Anthropic as anthropic} from '@anthropic-ai/sdk';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class Anthropic extends LLMProvider {\n\tclient!: anthropic;\n\n\tconstructor(public readonly ai: Ai, public readonly apiToken: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new anthropic({apiKey: apiToken});\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tconst timestamp = Date.now();\n\t\tconst messages: LLMMessage[] = [];\n\t\tfor(let h of history) {\n\t\t\tif(typeof h.content == 'string') {\n\t\t\t\tmessages.push(<any>{timestamp, ...h});\n\t\t\t} else {\n\t\t\t\tconst textContent = h.content?.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n');\n\t\t\t\tif(textContent) messages.push({timestamp, role: h.role, content: textContent});\n\t\t\t\th.content.forEach((c: any) => {\n\t\t\t\t\tif(c.type == 'tool_use') {\n\t\t\t\t\t\tmessages.push({timestamp, role: 'tool', id: c.id, name: c.name, args: c.input, content: undefined});\n\t\t\t\t\t} else if(c.type == 'tool_result') {\n\t\t\t\t\t\tconst m: any = messages.findLast(m => (<any>m).id == c.tool_use_id);\n\t\t\t\t\t\tif(m) m[c.is_error ? 'error' : 'content'] = c.content;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn messages;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tif(history[i].role == 'tool') {\n\t\t\t\tconst h: any = history[i];\n\t\t\t\thistory.splice(i, 1,\n\t\t\t\t\t{role: 'assistant', content: [{type: 'tool_use', id: h.id, name: h.name, input: h.args}]},\n\t\t\t\t\t{role: 'user', content: [{type: 'tool_result', tool_use_id: h.id, is_error: !!h.error, content: h.error || h.content}]}\n\t\t\t\t)\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\treturn history.map(({timestamp, ...h}) => h);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res) => {\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\tsystem: options.system || this.ai.options.llm?.system || '',\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\tname: t.name,\n\t\t\t\t\tdescription: t.description,\n\t\t\t\t\tinput_schema: {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t},\n\t\t\t\t\tfn: undefined\n\t\t\t\t})),\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.messages.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\t// Streaming mode\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.content = [];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.type === 'content_block_start') {\n\t\t\t\t\t\t\tif(chunk.content_block.type === 'text') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'text', text: ''});\n\t\t\t\t\t\t\t} else if(chunk.content_block.type === 'tool_use') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'tool_use', id: chunk.content_block.id, name: chunk.content_block.name, input: <any>''});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_delta') {\n\t\t\t\t\t\t\tif(chunk.delta.type === 'text_delta') {\n\t\t\t\t\t\t\t\tconst text = chunk.delta.text;\n\t\t\t\t\t\t\t\tresp.content.at(-1).text += text;\n\t\t\t\t\t\t\t\toptions.stream({text});\n\t\t\t\t\t\t\t} else if(chunk.delta.type === 'input_json_delta') {\n\t\t\t\t\t\t\t\tresp.content.at(-1).input += chunk.delta.partial_json;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_stop') {\n\t\t\t\t\t\t\tconst last = resp.content.at(-1);\n\t\t\t\t\t\t\tif(last.input != null) last.input = last.input ? JSONAttemptParse(last.input, {}) : {};\n\t\t\t\t\t\t} else if(chunk.type === 'message_stop') {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Run tools\n\t\t\t\tconst toolCalls = resp.content.filter((c: any) => c.type === 'tool_use');\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push({role: 'assistant', content: resp.content});\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools.find(findByProp('name', toolCall.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.name});\n\t\t\t\t\t\tif(!tool) return {tool_use_id: toolCall.id, is_error: true, content: 'Tool not found'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await tool.fn(toolCall.input, options?.stream, this.ai);\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, is_error: true, content: err?.message || err?.toString() || 'Unknown'};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push({role: 'user', content: results});\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.content.some((c: any) => c.type === 'tool_use'));\n\t\t\thistory.push({role: 'assistant', content: resp.content.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n')});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {OpenAI as openAI} from 'openai';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse, clean} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class OpenAi extends LLMProvider {\n\tclient!: openAI;\n\n\tconstructor(public readonly ai: Ai, public readonly host: string | null, public readonly token: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new openAI(clean({\n\t\t\tbaseURL: host,\n\t\t\tapiKey: token || host ? 'ignored' : undefined\n\t\t}));\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tconst h = history[i];\n\t\t\tif(h.role === 'assistant' && h.tool_calls) {\n\t\t\t\tconst tools = h.tool_calls.map((tc: any) => ({\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\tname: tc.function.name,\n\t\t\t\t\targs: JSONAttemptParse(tc.function.arguments, {}),\n\t\t\t\t\ttimestamp: h.timestamp\n\t\t\t\t}));\n\t\t\t\thistory.splice(i, 1, ...tools);\n\t\t\t\ti += tools.length - 1;\n\t\t\t} else if(h.role === 'tool' && h.content) {\n\t\t\t\tconst record = history.find(h2 => h.tool_call_id == h2.id);\n\t\t\t\tif(record) {\n\t\t\t\t\tif(h.content.includes('\"error\":')) record.error = h.content;\n\t\t\t\t\telse record.content = h.content;\n\t\t\t\t}\n\t\t\t\thistory.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t\tif(!history[i]?.timestamp) history[i].timestamp = Date.now();\n\t\t}\n\t\treturn history;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\treturn history.reduce((result, h) => {\n\t\t\tif(h.role === 'tool') {\n\t\t\t\tresult.push({\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: null,\n\t\t\t\t\ttool_calls: [{ id: h.id, type: 'function', function: { name: h.name, arguments: JSON.stringify(h.args) } }],\n\t\t\t\t\trefusal: null,\n\t\t\t\t\tannotations: []\n\t\t\t\t}, {\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\ttool_call_id: h.id,\n\t\t\t\t\tcontent: h.error || h.content\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst {timestamp, ...rest} = h;\n\t\t\t\tresult.push(rest);\n\t\t\t}\n\t\t\treturn result;\n\t\t}, [] as any[]);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res, rej) => {\n\t\t\tif(options.system) {\n\t\t\t\tif(options.history?.[0]?.role != 'system') options.history?.splice(0, 0, {role: 'system', content: options.system, timestamp: Date.now()});\n\t\t\t\telse options.history[0].content = options.system;\n\t\t\t}\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\ttype: 'function',\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: t.name,\n\t\t\t\t\t\tdescription: t.description,\n\t\t\t\t\t\tparameters: {\n\t\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.chat.completions.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.choices = [{message: {role: 'assistant', content: '', tool_calls: []}}];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.choices[0].delta.content) {\n\t\t\t\t\t\t\tresp.choices[0].message.content += chunk.choices[0].delta.content;\n\t\t\t\t\t\t\toptions.stream({text: chunk.choices[0].delta.content});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\tfor(const deltaTC of chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\t\tconst existing = resp.choices[0].message.tool_calls.find(tc => tc.index === deltaTC.index);\n\t\t\t\t\t\t\t\tif(existing) {\n\t\t\t\t\t\t\t\t\tif(deltaTC.id) existing.id = deltaTC.id;\n\t\t\t\t\t\t\t\t\tif(deltaTC.type) existing.type = deltaTC.type;\n\t\t\t\t\t\t\t\t\tif(deltaTC.function) {\n\t\t\t\t\t\t\t\t\t\tif(!existing.function) existing.function = {};\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.name) existing.function.name = deltaTC.function.name;\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.arguments) existing.function.arguments = (existing.function.arguments || '') + deltaTC.function.arguments;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tresp.choices[0].message.tool_calls.push({\n\t\t\t\t\t\t\t\t\t\tindex: deltaTC.index,\n\t\t\t\t\t\t\t\t\t\tid: deltaTC.id || '',\n\t\t\t\t\t\t\t\t\t\ttype: deltaTC.type || 'function',\n\t\t\t\t\t\t\t\t\t\tfunction: {\n\t\t\t\t\t\t\t\t\t\t\tname: deltaTC.function?.name || '',\n\t\t\t\t\t\t\t\t\t\t\targuments: deltaTC.function?.arguments || ''\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst toolCalls = resp.choices[0].message.tool_calls || [];\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push(resp.choices[0].message);\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools?.find(findByProp('name', toolCall.function.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.function.name});\n\t\t\t\t\t\tif(!tool) return {role: 'tool', tool_call_id: toolCall.id, content: '{\"error\": \"Tool not found\"}'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst args = JSONAttemptParse(toolCall.function.arguments, {});\n\t\t\t\t\t\t\tconst result = await tool.fn(args, options.stream, this.ai);\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'})};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push(...results);\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.choices?.[0]?.message?.tool_calls?.length);\n\t\t\thistory.push({role: 'assistant', content: resp.choices[0].message.content || ''});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {Anthropic} from './antrhopic.ts';\nimport {OpenAi} from './open-ai.ts';\nimport {LLMProvider} from './provider.ts';\nimport {AiTool} from './tools.ts';\nimport {fileURLToPath} from 'url';\nimport {dirname, join} from 'path';\nimport { spawn } from 'node:child_process';\n\nexport type AnthropicConfig = {proto: 'anthropic', token: string};\nexport type OllamaConfig = {proto: 'ollama', host: string};\nexport type OpenAiConfig = {proto: 'openai', host?: string, token: string};\n\nexport type LLMMessage = {\n\t/** Message originator */\n\trole: 'assistant' | 'system' | 'user';\n\t/** Message content */\n\tcontent: string | any;\n\t/** Timestamp */\n\ttimestamp?: number;\n} | {\n\t/** Tool call */\n\trole: 'tool';\n\t/** Unique ID for call */\n\tid: string;\n\t/** Tool that was run */\n\tname: string;\n\t/** Tool arguments */\n\targs: any;\n\t/** Tool result */\n\tcontent: undefined | string;\n\t/** Tool error */\n\terror?: undefined | string;\n\t/** Timestamp */\n\ttimestamp?: number;\n}\n\n/** Background information the AI will be fed */\nexport type LLMMemory = {\n\t/** What entity is this fact about */\n\towner: string;\n\t/** The information that will be remembered */\n\tfact: string;\n\t/** Owner and fact embedding vector */\n\tembeddings: [number[], number[]];\n}\n\nexport type LLMRequest = {\n\t/** System prompt */\n\tsystem?: string;\n\t/** Message history */\n\thistory?: LLMMessage[];\n\t/** Max tokens for request */\n\tmax_tokens?: number;\n\t/** 0 = Rigid Logic, 1 = Balanced, 2 = Hyper Creative **/\n\ttemperature?: number;\n\t/** Available tools */\n\ttools?: AiTool[];\n\t/** LLM model */\n\tmodel?: string;\n\t/** Stream response */\n\tstream?: (chunk: {text?: string, tool?: string, done?: true}) => any;\n\t/** Compress old messages in the chat to free up context */\n\tcompress?: {\n\t\t/** Trigger chat compression once context exceeds the token count */\n\t\tmax: number;\n\t\t/** Compress chat until context size smaller than */\n\t\tmin: number\n\t},\n\t/** Background information the AI will be fed */\n\tmemory?: LLMMemory[],\n}\n\nclass LLM {\n\tdefaultModel!: string;\n\tmodels: {[model: string]: LLMProvider} = {};\n\n\tconstructor(public readonly ai: Ai) {\n\t\tif(!ai.options.llm?.models) return;\n\t\tObject.entries(ai.options.llm.models).forEach(([model, config]) => {\n\t\t\tif(!this.defaultModel) this.defaultModel = model;\n\t\t\tif(config.proto == 'anthropic') this.models[model] = new Anthropic(this.ai, config.token, model);\n\t\t\telse if(config.proto == 'ollama') this.models[model] = new OpenAi(this.ai, config.host, 'not-needed', model);\n\t\t\telse if(config.proto == 'openai') this.models[model] = new OpenAi(this.ai, config.host || null, config.token, model);\n\t\t});\n\t}\n\n\t/**\n\t * Chat with LLM\n\t * @param {string} message Question\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {{abort: () => void, response: Promise<string>}} Function to abort response and chat history\n\t */\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\toptions = <any>{\n\t\t\tsystem: '',\n\t\t\ttemperature: 0.8,\n\t\t\t...this.ai.options.llm,\n\t\t\tmodels: undefined,\n\t\t\thistory: [],\n\t\t\t...options,\n\t\t}\n\t\tconst m = options.model || this.defaultModel;\n\t\tif(!this.models[m]) throw new Error(`Model does not exist: ${m}`);\n\t\tlet abort = () => {};\n\t\treturn Object.assign(new Promise<string>(async res => {\n\t\t\tif(!options.history) options.history = [];\n\t\t\t// If memories were passed, find any relevant ones and add a tool for ADHOC lookups\n\t\t\tif(options.memory) {\n\t\t\t\tconst search = async (query?: string | null, subject?: string | null, limit = 10) => {\n\t\t\t\t\tconst [o, q] = await Promise.all([\n\t\t\t\t\t\tsubject ? this.embedding(subject) : Promise.resolve(null),\n\t\t\t\t\t\tquery ? this.embedding(query) : Promise.resolve(null),\n\t\t\t\t\t]);\n\t\t\t\t\treturn (options.memory || []).map(m => {\n\t\t\t\t\t\tconst score = (o ? this.cosineSimilarity(m.embeddings[0], o[0].embedding) : 0)\n\t\t\t\t\t\t\t+ (q ? this.cosineSimilarity(m.embeddings[1], q[0].embedding) : 0);\n\t\t\t\t\t\treturn {...m, score};\n\t\t\t\t\t}).toSorted((a: any, b: any) => a.score - b.score).slice(0, limit);\n\t\t\t\t}\n\n\t\t\t\toptions.system += '\\nYou have RAG memory and will be given the top_k closest memories regarding the users query. Save anything new you have learned worth remembering from the user message using the remember tool and feel free to recall memories manually.\\n';\n\t\t\t\tconst relevant = await search(message);\n\t\t\t\tif(relevant.length) options.history.push({role: 'tool', name: 'recall', id: 'auto_recall_' + Math.random().toString(), args: {}, content: 'Things I remembered:\\n' + relevant.map(m => `${m.owner}: ${m.fact}`).join('\\n')});\n\t\t\t\toptions.tools = [{\n\t\t\t\t\tname: 'recall',\n\t\t\t\t\tdescription: 'Recall the closest memories you have regarding a query using RAG',\n\t\t\t\t\targs: {\n\t\t\t\t\t\tsubject: {type: 'string', description: 'Find information by a subject topic, can be used with or without query argument'},\n\t\t\t\t\t\tquery: {type: 'string', description: 'Search memory based on a query, can be used with or without subject argument'},\n\t\t\t\t\t\ttopK: {type: 'number', description: 'Result limit, default 5'},\n\t\t\t\t\t},\n\t\t\t\t\tfn: (args) => {\n\t\t\t\t\t\tif(!args.subject && !args.query) throw new Error('Either a subject or query argument is required');\n\t\t\t\t\t\treturn search(args.query, args.subject, args.topK);\n\t\t\t\t\t}\n\t\t\t\t}, {\n\t\t\t\t\tname: 'remember',\n\t\t\t\t\tdescription: 'Store important facts user shares for future recall',\n\t\t\t\t\targs: {\n\t\t\t\t\t\towner: {type: 'string', description: 'Subject/person this fact is about'},\n\t\t\t\t\t\tfact: {type: 'string', description: 'The information to remember'}\n\t\t\t\t\t},\n\t\t\t\t\tfn: async (args) => {\n\t\t\t\t\t\tif(!options.memory) return;\n\t\t\t\t\t\tconst e = await Promise.all([\n\t\t\t\t\t\t\tthis.embedding(args.owner),\n\t\t\t\t\t\t\tthis.embedding(`${args.owner}: ${args.fact}`)\n\t\t\t\t\t\t]);\n\t\t\t\t\t\tconst newMem = {owner: args.owner, fact: args.fact, embeddings: <any>[e[0][0].embedding, e[1][0].embedding]};\n\t\t\t\t\t\toptions.memory.splice(0, options.memory.length, ...[\n\t\t\t\t\t\t\t...options.memory.filter(m => {\n\t\t\t\t\t\t\t\treturn !(this.cosineSimilarity(newMem.embeddings[0], m.embeddings[0]) >= 0.9 && this.cosineSimilarity(newMem.embeddings[1], m.embeddings[1]) >= 0.8);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tnewMem\n\t\t\t\t\t\t]);\n\t\t\t\t\t\treturn 'Remembered!';\n\t\t\t\t\t}\n\t\t\t\t}, ...options.tools || []];\n\t\t\t}\n\n\t\t\t// Ask\n\t\t\tconst resp = await this.models[m].ask(message, options);\n\n\t\t\t// Remove any memory calls from history\n\t\t\tif(options.memory) options.history.splice(0, options.history.length, ...options.history.filter(h => h.role != 'tool' || (h.name != 'recall' && h.name != 'remember')));\n\n\t\t\t// Compress message history\n\t\t\tif(options.compress) {\n\t\t\t\tconst compressed = await this.ai.language.compressHistory(options.history, options.compress.max, options.compress.min, options);\n\t\t\t\toptions.history.splice(0, options.history.length, ...compressed);\n\t\t\t}\n\n\t\t\treturn res(resp);\n\t\t}), {abort});\n\t}\n\n\tasync code(message: string, options?: LLMRequest): Promise<any> {\n\t\tconst resp = await this.ask(message, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t'Return your response in a code block'\n\t\t].filter(t => !!t).join(('\\n'))});\n\t\tconst codeBlock = /```(?:.+)?\\s*([\\s\\S]*?)```/.exec(resp);\n\t\treturn codeBlock ? codeBlock[1].trim() : null;\n\t}\n\n\t/**\n\t * Compress chat history to reduce context size\n\t * @param {LLMMessage[]} history Chatlog that will be compressed\n\t * @param max Trigger compression once context is larger than max\n\t * @param min Leave messages less than the token minimum, summarize the rest\n\t * @param {LLMRequest} options LLM options\n\t * @returns {Promise<LLMMessage[]>} New chat history will summary at index 0\n\t */\n\tasync compressHistory(history: LLMMessage[], max: number, min: number, options?: LLMRequest): Promise<LLMMessage[]> {\n\t\tif(this.estimateTokens(history) < max) return history;\n\t\tlet keep = 0, tokens = 0;\n\t\tfor(let m of history.toReversed()) {\n\t\t\ttokens += this.estimateTokens(m.content);\n\t\t\tif(tokens < min) keep++;\n\t\t\telse break;\n\t\t}\n\t\tif(history.length <= keep) return history;\n\t\tconst system = history[0].role == 'system' ? history[0] : null,\n\t\t\trecent = keep == 0 ? [] : history.slice(-keep),\n\t\t\tprocess = (keep == 0 ? history : history.slice(0, -keep)).filter(h => h.role === 'assistant' || h.role === 'user');\n\n\t\tconst summary: any = await this.summarize(process.map(m => `[${m.role}]: ${m.content}`).join('\\n\\n'), 500, options);\n\t\tconst d = Date.now();\n\t\tconst h = [{role: <any>'tool', name: 'summary', id: `summary_` + d, args: {}, content: `Conversation Summary: ${summary?.summary}`, timestamp: d}, ...recent];\n\t\tif(system) h.splice(0, 0, system);\n\t\treturn h;\n\t}\n\n\t/**\n\t * Compare the difference between embeddings (calculates the angle between two vectors)\n\t * @param {number[]} v1 First embedding / vector comparison\n\t * @param {number[]} v2 Second embedding / vector for comparison\n\t * @returns {number} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tcosineSimilarity(v1: number[], v2: number[]): number {\n\t\tif (v1.length !== v2.length) throw new Error('Vectors must be same length');\n\t\tlet dotProduct = 0, normA = 0, normB = 0;\n\t\tfor (let i = 0; i < v1.length; i++) {\n\t\t\tdotProduct += v1[i] * v2[i];\n\t\t\tnormA += v1[i] * v1[i];\n\t\t\tnormB += v2[i] * v2[i];\n\t\t}\n\t\tconst denominator = Math.sqrt(normA) * Math.sqrt(normB);\n\t\treturn denominator === 0 ? 0 : dotProduct / denominator;\n\t}\n\n\t/**\n\t * Chunk text into parts for AI digestion\n\t * @param {object | string} target Item that will be chunked (objects get converted)\n\t * @param {number} maxTokens Chunking size. More = better context, less = more specific (Search by paragraphs or lines)\n\t * @param {number} overlapTokens Includes previous X tokens to provide continuity to AI (In addition to max tokens)\n\t * @returns {string[]} Chunked strings\n\t */\n\tchunk(target: object | string, maxTokens = 500, overlapTokens = 50): string[] {\n\t\tconst objString = (obj: any, path = ''): string[] => {\n\t\t\tif(!obj) return [];\n\t\t\treturn Object.entries(obj).flatMap(([key, value]) => {\n\t\t\t\tconst p = path ? `${path}${isNaN(+key) ? `.${key}` : `[${key}]`}` : key;\n\t\t\t\tif(typeof value === 'object' && !Array.isArray(value)) return objString(value, p);\n\t\t\t\treturn `${p}: ${Array.isArray(value) ? value.join(', ') : value}`;\n\t\t\t});\n\t\t};\n\t\tconst lines = typeof target === 'object' ? objString(target) : target.toString().split('\\n');\n\t\tconst tokens = lines.flatMap(l => [...l.split(/\\s+/).filter(Boolean), '\\n']);\n\t\tconst chunks: string[] = [];\n\t\tfor(let i = 0; i < tokens.length;) {\n\t\t\tlet text = '', j = i;\n\t\t\twhile(j < tokens.length) {\n\t\t\t\tconst next = text + (text ? ' ' : '') + tokens[j];\n\t\t\t\tif(this.estimateTokens(next.replace(/\\s*\\n\\s*/g, '\\n')) > maxTokens && text) break;\n\t\t\t\ttext = next;\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tconst clean = text.replace(/\\s*\\n\\s*/g, '\\n').trim();\n\t\t\tif(clean) chunks.push(clean);\n\t\t\ti = Math.max(j - overlapTokens, j === i ? i + 1 : j);\n\t\t}\n\t\treturn chunks;\n\t}\n\n\t/**\n\t * Create a vector representation of a string\n\t * @param {object | string} target Item that will be embedded (objects get converted)\n\t * @param {maxTokens?: number, overlapTokens?: number} opts Options for embedding such as chunk sizes\n\t * @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings\n\t */\n\tembedding(target: object | string, opts: {maxTokens?: number, overlapTokens?: number} = {}): AbortablePromise<any[]> {\n\t\tlet {maxTokens = 500, overlapTokens = 50} = opts;\n\t\tlet aborted = false;\n\t\tconst abort = () => { aborted = true; };\n\n\t\tconst embed = (text: string): Promise<number[]> => {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\n\t\t\t\tconst args: string[] = [\n\t\t\t\t\tjoin(dirname(fileURLToPath(import.meta.url)), 'embedder.js'),\n\t\t\t\t\t<string>this.ai.options.path,\n\t\t\t\t\tthis.ai.options?.embedder || 'bge-small-en-v1.5'\n\t\t\t\t];\n\t\t\t\tconst proc = spawn('node', args, {stdio: ['pipe', 'pipe', 'ignore']});\n\t\t\t\tproc.stdin.write(text);\n\t\t\t\tproc.stdin.end();\n\n\t\t\t\tlet output = '';\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = JSON.parse(output);\n\t\t\t\t\t\t\tresolve(result.embedding);\n\t\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t\treject(new Error('Failed to parse embedding output'));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Embedder process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t});\n\t\t};\n\n\t\tconst p = (async () => {\n\t\t\tconst chunks = this.chunk(target, maxTokens, overlapTokens), results: any[] = [];\n\t\t\tfor(let i = 0; i < chunks.length; i++) {\n\t\t\t\tif(aborted) break;\n\t\t\t\tconst text = chunks[i];\n\t\t\t\tconst embedding = await embed(text);\n\t\t\t\tresults.push({index: i, embedding, text, tokens: this.estimateTokens(text)});\n\t\t\t}\n\t\t\treturn results;\n\t\t})();\n\t\treturn Object.assign(p, { abort });\n\t}\n\n\t/**\n\t * Estimate variable as tokens\n\t * @param history Object to size\n\t * @returns {number} Rough token count\n\t */\n\testimateTokens(history: any): number {\n\t\tconst text = JSON.stringify(history);\n\t\treturn Math.ceil((text.length / 4) * 1.2);\n\t}\n\n\t/**\n\t * Compare the difference between two strings using tensor math\n\t * @param target Text that will be checked\n\t * @param {string} searchTerms Multiple search terms to check against target\n\t * @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tfuzzyMatch(target: string, ...searchTerms: string[]) {\n\t\tif(searchTerms.length < 2) throw new Error('Requires at least 2 strings to compare');\n\t\tconst vector = (text: string, dimensions: number = 10): number[] => {\n\t\t\treturn text.toLowerCase().split('').map((char, index) =>\n\t\t\t\t(char.charCodeAt(0) * (index + 1)) % dimensions / dimensions).slice(0, dimensions);\n\t\t}\n\t\tconst v = vector(target);\n\t\tconst similarities = searchTerms.map(t => vector(t)).map(refVector => this.cosineSimilarity(v, refVector))\n\t\treturn {avg: similarities.reduce((acc, s) => acc + s, 0) / similarities.length, max: Math.max(...similarities), similarities}\n\t}\n\n\t/**\n\t * Ask a question with JSON response\n\t * @param {string} text Text to process\n\t * @param {string} schema JSON schema the AI should match\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {Promise<{} | {} | RegExpExecArray | null>}\n\t */\n\tasync json(text: string, schema: string, options?: LLMRequest): Promise<any> {\n\t\tconst code = await this.code(text, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t`Only respond using JSON matching this schema:\\n\\`\\`\\`json\\n${schema}\\n\\`\\`\\``\n\t\t].filter(t => !!t).join('\\n')});\n\t\treturn code ? JSONAttemptParse(code, {}) : null;\n\t}\n\n\t/**\n\t * Create a summary of some text\n\t * @param {string} text Text to summarize\n\t * @param {number} tokens Max number of tokens\n\t * @param options LLM request options\n\t * @returns {Promise<string>} Summary\n\t */\n\tsummarize(text: string, tokens: number = 500, options?: LLMRequest): Promise<string | null> {\n\t\treturn this.ask(text, {system: `Generate the shortest summary possible <= ${tokens} tokens. Output nothing else`, temperature: 0.3, ...options});\n\t}\n}\n\nexport default LLM;\n","import {execSync, spawn} from 'node:child_process';\nimport {mkdtempSync} from 'node:fs';\nimport fs from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport * as path from 'node:path';\nimport Path, {join} from 'node:path';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Audio {\n\tprivate downloads: {[key: string]: Promise<string>} = {};\n\tprivate pyannote!: string;\n\tprivate whisperModel!: string;\n\n\tconstructor(private ai: Ai) {\n\t\tif(ai.options.whisper) {\n\t\t\tthis.whisperModel = ai.options.asr || 'ggml-base.en.bin';\n\t\t\tthis.downloadAsrModel();\n\t\t}\n\n\t\tthis.pyannote = `\nimport sys\nimport json\nimport os\nfrom pyannote.audio import Pipeline\n\nos.environ['TORCH_HOME'] = r\"${ai.options.path}\"\npipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization-3.1\", token=\"${ai.options.hfToken}\")\noutput = pipeline(sys.argv[1])\n\nsegments = []\nfor turn, speaker in output.speaker_diarization:\n segments.append({\"start\": turn.start, \"end\": turn.end, \"speaker\": speaker})\n\nprint(json.dumps(segments))\n`;\n\t}\n\n\tprivate async addPunctuation(timestampData: any, llm?: boolean, cadence = 150): Promise<string> {\n\t\tconst countSyllables = (word: string): number => {\n\t\t\tword = word.toLowerCase().replace(/[^a-z]/g, '');\n\t\t\tif(word.length <= 3) return 1;\n\t\t\tconst matches = word.match(/[aeiouy]+/g);\n\t\t\tlet count = matches ? matches.length : 1;\n\t\t\tif(word.endsWith('e')) count--;\n\t\t\treturn Math.max(1, count);\n\t\t};\n\n\t\tlet result = '';\n\t\ttimestampData.transcription.filter((word, i) => {\n\t\t\tlet skip = false;\n\t\t\tconst prevWord = timestampData.transcription[i - 1];\n\t\t\tconst nextWord = timestampData.transcription[i + 1];\n\t\t\tif(!word.text && nextWord) {\n\t\t\t\tnextWord.offsets.from = word.offsets.from;\n\t\t\t\tnextWord.timestamps.from = word.offsets.from;\n\t\t\t} else if(word.text && word.text[0] != ' ' && prevWord) {\n\t\t\t\tprevWord.offsets.to = word.offsets.to;\n\t\t\t\tprevWord.timestamps.to = word.timestamps.to;\n\t\t\t\tprevWord.text += word.text;\n\t\t\t\tskip = true;\n\t\t\t}\n\t\t\treturn !!word.text && !skip;\n\t\t}).forEach((word: any) => {\n\t\t\tconst capital = /^[A-Z]/.test(word.text.trim());\n\t\t\tconst length = word.offsets.to - word.offsets.from;\n\t\t\tconst syllables = countSyllables(word.text.trim());\n\t\t\tconst expected = syllables * cadence;\n\t\t\tif(capital && length > expected * 2 && word.text[0] == ' ') result += '.';\n\t\t\tresult += word.text;\n\t\t});\n\t\tif(!llm) return result.trim();\n\t\treturn this.ai.language.ask(result, {\n\t\t\tsystem: 'Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo',\n\t\t\ttemperature: 0.1,\n\t\t\ttools: [{\n\t\t\t\tname: 'replace',\n\t\t\t\tdescription: 'Use find and replace to fix errors',\n\t\t\t\targs: {\n\t\t\t\t\tfind: {type: 'string', description: 'Text to find', required: true},\n\t\t\t\t\treplace: {type: 'string', description: 'Text to replace', required: true}\n\t\t\t\t},\n\t\t\t\tfn: (args) => result = result.replace(args.find, args.replace)\n\t\t\t}]\n\t\t}).then(() => result);\n\t}\n\n\tprivate async diarizeTranscript(timestampData: any, speakers: any[], llm: boolean): Promise<string> {\n\t\tconst speakerMap = new Map();\n\t\tlet speakerCount = 0;\n\t\tspeakers.forEach((seg: any) => {\n\t\t\tif(!speakerMap.has(seg.speaker)) speakerMap.set(seg.speaker, ++speakerCount);\n\t\t});\n\n\t\tconst punctuatedText = await this.addPunctuation(timestampData, llm);\n\t\tconst sentences = punctuatedText.match(/[^.!?]+[.!?]+/g) || [punctuatedText];\n\t\tconst words = timestampData.transcription.filter((w: any) => w.text.trim());\n\n\t\t// Assign speaker to each sentence\n\t\tconst sentencesWithSpeakers = sentences.map(sentence => {\n\t\t\tsentence = sentence.trim();\n\t\t\tif(!sentence) return null;\n\n\t\t\tconst sentenceWords = sentence.toLowerCase().replace(/[^\\w\\s]/g, '').split(/\\s+/);\n\t\t\tconst speakerWordCount = new Map<number, number>();\n\n\t\t\tsentenceWords.forEach(sw => {\n\t\t\t\tconst word = words.find((w: any) => sw === w.text.trim().toLowerCase().replace(/[^\\w]/g, ''));\n\t\t\t\tif(!word) return;\n\n\t\t\t\tconst wordTime = word.offsets.from / 1000;\n\t\t\t\tconst speaker = speakers.find((seg: any) => wordTime >= seg.start && wordTime <= seg.end);\n\t\t\t\tif(speaker) {\n\t\t\t\t\tconst spkNum = speakerMap.get(speaker.speaker);\n\t\t\t\t\tspeakerWordCount.set(spkNum, (speakerWordCount.get(spkNum) || 0) + 1);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tlet bestSpeaker = 1;\n\t\t\tlet maxWords = 0;\n\t\t\tspeakerWordCount.forEach((count, speaker) => {\n\t\t\t\tif(count > maxWords) {\n\t\t\t\t\tmaxWords = count;\n\t\t\t\t\tbestSpeaker = speaker;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn {speaker: bestSpeaker, text: sentence};\n\t\t}).filter(s => s !== null);\n\n\t\t// Merge adjacent sentences from same speaker\n\t\tconst merged: Array<{speaker: number, text: string}> = [];\n\t\tsentencesWithSpeakers.forEach(item => {\n\t\t\tconst last = merged[merged.length - 1];\n\t\t\tif(last && last.speaker === item.speaker) {\n\t\t\t\tlast.text += ' ' + item.text;\n\t\t\t} else {\n\t\t\t\tmerged.push({...item});\n\t\t\t}\n\t\t});\n\n\t\tlet transcript = merged.map(item => `[Speaker ${item.speaker}]: ${item.text}`).join('\\n').trim();\n\t\tif(!llm) return transcript;\n\t\tlet chunks = this.ai.language.chunk(transcript, 500, 0);\n\t\tif(chunks.length > 4) chunks = [...chunks.slice(0, 3), <string>chunks.at(-1)];\n\t\tconst names = await this.ai.language.json(chunks.join('\\n'), '{1: \"Detected Name\", 2: \"Second Name\"}', {\n\t\t\tsystem: 'Use the following transcript to identify speakers. Only identify speakers you are positive about, dont mention speakers you are unsure about in your response',\n\t\t\ttemperature: 0.1,\n\t\t});\n\t\tObject.entries(names).forEach(([speaker, name]) => transcript = transcript.replaceAll(`[Speaker ${speaker}]`, `[${name}]`));\n\t\treturn transcript;\n\t}\n\n\tprivate runAsr(file: string, opts: {model?: string, diarization?: boolean} = {}): AbortablePromise<any> {\n\t\tlet proc: any;\n\t\tconst p = new Promise<any>((resolve, reject) => {\n\t\t\tthis.downloadAsrModel(opts.model).then(m => {\n\t\t\t\tif(opts.diarization) {\n\t\t\t\t\tlet output = path.join(path.dirname(file), 'transcript');\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper,\n\t\t\t\t\t\t['-m', m, '-f', file, '-np', '-ml', '1', '-oj', '-of', output],\n\t\t\t\t\t\t{stdio: ['ignore', 'ignore', 'pipe']}\n\t\t\t\t\t);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\toutput = await fs.readFile(output + '.json', 'utf-8');\n\t\t\t\t\t\t\tfs.rm(output + '.json').catch(() => { });\n\t\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\t\tcatch(e) { reject(new Error('Failed to parse whisper JSON')); }\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlet output = '';\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper, ['-m', m, '-f', file, '-np', '-nt']);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\tresolve(output.trim() || null);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\treturn <any>Object.assign(p, {abort: () => proc?.kill('SIGTERM')});\n\t}\n\n\tprivate runDiarization(file: string): AbortablePromise<any> {\n\t\tlet aborted = false, abort = () => { aborted = true; };\n\t\tconst checkPython = (cmd: string) => {\n\t\t\treturn new Promise<boolean>((resolve) => {\n\t\t\t\tconst proc = spawn(cmd, ['-W', 'ignore', '-c', 'import pyannote.audio']);\n\t\t\t\tproc.on('close', (code: number) => resolve(code === 0));\n\t\t\t\tproc.on('error', () => resolve(false));\n\t\t\t});\n\t\t};\n\t\tconst p = Promise.all<any>([\n\t\t\tcheckPython('python'),\n\t\t\tcheckPython('python3'),\n\t\t]).then(<any>(async ([p, p3]: [boolean, boolean]) => {\n\t\t\tif(aborted) return;\n\t\t\tif(!p && !p3) throw new Error('Pyannote is not installed: pip install pyannote.audio');\n\t\t\tconst binary = p3 ? 'python3' : 'python';\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return;\n\t\t\t\tlet output = '';\n\t\t\t\tconst proc = spawn(binary, ['-W', 'ignore', '-c', this.pyannote, file]);\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.stderr.on('data', (data: Buffer) => console.error(data.toString()));\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\tcatch (err) { reject(new Error('Failed to parse diarization output')); }\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Python process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t\tabort = () => proc.kill('SIGTERM');\n\t\t\t});\n\t\t}));\n\t\treturn <any>Object.assign(p, {abort});\n\t}\n\n\tasr(file: string, options: { model?: string; diarization?: boolean | 'llm' } = {}): AbortablePromise<string | null> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\n\t\tconst tmp = join(mkdtempSync(join(tmpdir(), 'audio-')), 'converted.wav');\n\t\texecSync(`ffmpeg -i \"${file}\" -ar 16000 -ac 1 -f wav \"${tmp}\"`, { stdio: 'ignore' });\n\t\tconst clean = () => fs.rm(Path.dirname(tmp), {recursive: true, force: true}).catch(() => {});\n\n\t\tif(!options.diarization) return this.runAsr(tmp, {model: options.model});\n\t\tconst timestamps = this.runAsr(tmp, {model: options.model, diarization: true});\n\t\tconst diarization = this.runDiarization(tmp);\n\t\tlet aborted = false, abort = () => {\n\t\t\taborted = true;\n\t\t\ttimestamps.abort();\n\t\t\tdiarization.abort();\n\t\t\tclean();\n\t\t};\n\n\t\tconst response = Promise.allSettled([timestamps, diarization]).then(async ([ts, d]) => {\n\t\t\tif(ts.status == 'rejected') throw new Error('Whisper.cpp timestamps:\\n' + ts.reason);\n\t\t\tif(d.status == 'rejected') throw new Error('Pyannote:\\n' + d.reason);\n\t\t\tif(aborted || !options.diarization) return ts.value;\n\t\t\treturn this.diarizeTranscript(ts.value, d.value, options.diarization == 'llm');\n\t\t}).finally(() => clean());\n\t\treturn <any>Object.assign(response, {abort});\n\t}\n\n\tasync downloadAsrModel(model: string = this.whisperModel): Promise<string> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\t\tif(!model.endsWith('.bin')) model += '.bin';\n\t\tconst p = Path.join(<string>this.ai.options.path, model);\n\t\tif(await fs.stat(p).then(() => true).catch(() => false)) return p;\n\t\tif(!!this.downloads[model]) return this.downloads[model];\n\t\tthis.downloads[model] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${model}`)\n\t\t\t.then(resp => resp.arrayBuffer())\n\t\t\t.then(arr => Buffer.from(arr)).then(async buffer => {\n\t\t\t\tawait fs.writeFile(p, buffer);\n\t\t\t\tdelete this.downloads[model];\n\t\t\t\treturn p;\n\t\t\t});\n\t\treturn this.downloads[model];\n\t}\n}\n","import {createWorker} from 'tesseract.js';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Vision {\n\n\tconstructor(private ai: Ai) {}\n\n\t/**\n\t * Convert image to text using Optical Character Recognition\n\t * @param {string} path Path to image\n\t * @returns {AbortablePromise<string | null>} Promise of extracted text with abort method\n\t */\n\tocr(path: string): AbortablePromise<string | null> {\n\t\tlet worker: any;\n\t\tconst p = new Promise<string | null>(async res => {\n\t\t\tworker = await createWorker(this.ai.options.ocr || 'eng', 2, {cachePath: this.ai.options.path});\n\t\t\tconst {data} = await worker.recognize(path);\n\t\t\tawait worker.terminate();\n\t\t\tres(data.text.trim() || null);\n\t\t});\n\t\treturn Object.assign(p, {abort: () => worker?.terminate()});\n\t}\n}\n","import * as os from 'node:os';\nimport LLM, {AnthropicConfig, OllamaConfig, OpenAiConfig, LLMRequest} from './llm';\nimport { Audio } from './audio.ts';\nimport {Vision} from './vision.ts';\n\nexport type AbortablePromise<T> = Promise<T> & {\n\tabort: () => any\n};\n\nexport type AiOptions = {\n\t/** Token to pull models from hugging face */\n\thfToken?: string;\n\t/** Path to models */\n\tpath?: string;\n\t/** Whisper ASR model: ggml-tiny.en.bin, ggml-base.en.bin */\n\tasr?: string;\n\t/** Embedding model: all-MiniLM-L6-v2, bge-small-en-v1.5, bge-large-en-v1.5 */\n\tembedder?: string;\n\t/** Large language models, first is default */\n\tllm?: Omit<LLMRequest, 'model'> & {\n\t\tmodels: {[model: string]: AnthropicConfig | OllamaConfig | OpenAiConfig};\n\t}\n\t/** OCR model: eng, eng_best, eng_fast */\n\tocr?: string;\n\t/** Whisper binary */\n\twhisper?: string;\n}\n\nexport class Ai {\n\t/** Audio processing AI */\n\taudio!: Audio;\n\t/** Language processing AI */\n\tlanguage!: LLM;\n\t/** Vision processing AI */\n\tvision!: Vision;\n\n\tconstructor(public readonly options: AiOptions) {\n\t\tif(!options.path) options.path = os.tmpdir();\n\t\tprocess.env.TRANSFORMERS_CACHE = options.path;\n\t\tthis.audio = new Audio(this);\n\t\tthis.language = new LLM(this);\n\t\tthis.vision = new Vision(this);\n\t}\n}\n","import * as cheerio from 'cheerio';\nimport {$Sync} from '@ztimson/node-utils';\nimport {ASet, consoleInterceptor, Http, fn as Fn} from '@ztimson/utils';\nimport * as os from 'node:os';\nimport {Ai} from './ai.ts';\nimport {LLMRequest} from './llm.ts';\n\nconst getShell = () => {\n\tif(os.platform() == 'win32') return 'cmd';\n\treturn $Sync`echo $SHELL`?.split('/').pop() || 'bash';\n}\n\nexport type AiToolArg = {[key: string]: {\n\t/** Argument type */\n\ttype: 'array' | 'boolean' | 'number' | 'object' | 'string',\n\t/** Argument description */\n\tdescription: string,\n\t/** Required argument */\n\trequired?: boolean;\n\t/** Default value */\n\tdefault?: any,\n\t/** Options */\n\tenum?: string[],\n\t/** Minimum value or length */\n\tmin?: number,\n\t/** Maximum value or length */\n\tmax?: number,\n\t/** Match pattern */\n\tpattern?: string,\n\t/** Child arguments */\n\titems?: {[key: string]: AiToolArg}\n}}\n\nexport type AiTool = {\n\t/** Tool ID / Name - Must be snail_case */\n\tname: string,\n\t/** Tool description / prompt */\n\tdescription: string,\n\t/** Tool arguments */\n\targs?: AiToolArg,\n\t/** Callback function */\n\tfn: (args: any, stream: LLMRequest['stream'], ai: Ai) => any | Promise<any>,\n};\n\nexport const CliTool: AiTool = {\n\tname: 'cli',\n\tdescription: 'Use the command line interface, returns any output',\n\targs: {command: {type: 'string', description: 'Command to run', required: true}},\n\tfn: (args: {command: string}) => $Sync`${args.command}`\n}\n\nexport const DateTimeTool: AiTool = {\n\tname: 'get_datetime',\n\tdescription: 'Get current UTC date / time',\n\targs: {},\n\tfn: async () => new Date().toUTCString()\n}\n\nexport const ExecTool: AiTool = {\n\tname: 'exec',\n\tdescription: 'Run code/scripts',\n\targs: {\n\t\tlanguage: {type: 'string', description: `Execution language (CLI: ${getShell()})`, enum: ['cli', 'node', 'python'], required: true},\n\t\tcode: {type: 'string', description: 'Code to execute', required: true}\n\t},\n\tfn: async (args, stream, ai) => {\n\t\ttry {\n\t\t\tswitch(args.language) {\n\t\t\t\tcase 'cli':\n\t\t\t\t\treturn await CliTool.fn({command: args.code}, stream, ai);\n\t\t\t\tcase 'node':\n\t\t\t\t\treturn await JSTool.fn({code: args.code}, stream, ai);\n\t\t\t\tcase 'python':\n\t\t\t\t\treturn await PythonTool.fn({code: args.code}, stream, ai);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unsupported language: ${args.language}`);\n\t\t\t}\n\t\t} catch(err: any) {\n\t\t\treturn {error: err?.message || err.toString()};\n\t\t}\n\t}\n}\n\nexport const FetchTool: AiTool = {\n\tname: 'fetch',\n\tdescription: 'Make HTTP request to URL',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to fetch', required: true},\n\t\tmethod: {type: 'string', description: 'HTTP method to use', enum: ['GET', 'POST', 'PUT', 'DELETE'], default: 'GET'},\n\t\theaders: {type: 'object', description: 'HTTP headers to send', default: {}},\n\t\tbody: {type: 'object', description: 'HTTP body to send'},\n\t},\n\tfn: (args: {\n\t\turl: string;\n\t\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE';\n\t\theaders: {[key: string]: string};\n\t\tbody: any;\n\t}) => new Http({url: args.url, headers: args.headers}).request({method: args.method || 'GET', body: args.body})\n}\n\nexport const JSTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => {\n\t\tconst c = consoleInterceptor(null);\n\t\tconst resp = await Fn<any>({console: c}, args.code, true).catch((err: any) => c.output.error.push(err));\n\t\treturn {...c.output, return: resp, stdout: undefined, stderr: undefined};\n\t}\n}\n\nexport const PythonTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => ({result: $Sync`python -c \"${args.code}\"`})\n}\n\nexport const ReadWebpageTool: AiTool = {\n\tname: 'read_webpage',\n\tdescription: 'Extract clean, structured content from a webpage. Use after web_search to read specific URLs',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to extract content from', required: true},\n\t\tfocus: {type: 'string', description: 'Optional: What aspect to focus on (e.g., \"pricing\", \"features\", \"contact info\")'}\n\t},\n\tfn: async (args: {url: string; focus?: string}) => {\n\t\tconst html = await fetch(args.url, {headers: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"}})\n\t\t\t.then(r => r.text()).catch(err => {throw new Error(`Failed to fetch: ${err.message}`)});\n\n\t\tconst $ = cheerio.load(html);\n\t\t$('script, style, nav, footer, header, aside, iframe, noscript, [role=\"navigation\"], [role=\"banner\"], .ad, .ads, .cookie, .popup').remove();\n\t\tconst metadata = {\n\t\t\ttitle: $('meta[property=\"og:title\"]').attr('content') || $('title').text() || '',\n\t\t\tdescription: $('meta[name=\"description\"]').attr('content') || $('meta[property=\"og:description\"]').attr('content') || '',\n\t\t};\n\n\t\tlet content = '';\n\t\tconst contentSelectors = ['article', 'main', '[role=\"main\"]', '.content', '.post', '.entry', 'body'];\n\t\tfor (const selector of contentSelectors) {\n\t\t\tconst el = $(selector).first();\n\t\t\tif (el.length && el.text().trim().length > 200) {\n\t\t\t\tcontent = el.text();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!content) content = $('body').text();\n\t\tcontent = content.replace(/\\s+/g, ' ').trim().slice(0, 8000);\n\n\t\treturn {url: args.url, title: metadata.title.trim(), description: metadata.description.trim(), content, focus: args.focus};\n\t}\n}\n\nexport const WebSearchTool: AiTool = {\n\tname: 'web_search',\n\tdescription: 'Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool',\n\targs: {\n\t\tquery: {type: 'string', description: 'Search string', required: true},\n\t\tlength: {type: 'string', description: 'Number of results to return', default: 5},\n\t},\n\tfn: async (args: {\n\t\tquery: string;\n\t\tlength: number;\n\t}) => {\n\t\tconst html = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(args.query)}`, {\n\t\t\theaders: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\", \"Accept-Language\": \"en-US,en;q=0.9\"}\n\t\t}).then(resp => resp.text());\n\t\tlet match, regex = /<a .*?href=\"(.+?)\".+?<\\/a>/g;\n\t\tconst results = new ASet<string>();\n\t\twhile((match = regex.exec(html)) !== null) {\n\t\t\tlet url = /uddg=(.+)&amp?/.exec(decodeURIComponent(match[1]))?.[1];\n\t\t\tif(url) url = decodeURIComponent(url);\n\t\t\tif(url) results.add(url);\n\t\t\tif(results.size >= (args.length || 5)) break;\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"names":["LLMProvider","Anthropic","ai","apiToken","model","anthropic","history","timestamp","messages","h","textContent","c","m","i","message","options","controller","res","tools","requestParams","t","objectMap","key","value","resp","isFirstMessage","err","chunk","text","last","JSONAttemptParse","toolCalls","results","toolCall","tool","findByProp","result","JSONSanitize","OpenAi","host","token","openAI","clean","tc","record","h2","rest","rej","deltaTC","existing","args","LLM","config","abort","search","query","subject","limit","o","q","score","a","b","relevant","e","newMem","compressed","codeBlock","max","min","keep","tokens","system","recent","process","summary","d","v1","v2","dotProduct","normA","normB","denominator","target","maxTokens","overlapTokens","objString","obj","path","p","l","chunks","j","next","opts","aborted","embed","resolve","reject","join","dirname","fileURLToPath","_documentCurrentScript","proc","spawn","output","data","code","embedding","searchTerms","vector","dimensions","char","index","v","similarities","refVector","acc","s","schema","Audio","timestampData","llm","cadence","countSyllables","word","matches","count","skip","prevWord","nextWord","capital","length","expected","speakers","speakerMap","speakerCount","seg","punctuatedText","sentences","words","w","sentencesWithSpeakers","sentence","sentenceWords","speakerWordCount","sw","wordTime","speaker","spkNum","bestSpeaker","maxWords","merged","item","transcript","names","name","file","fs","checkPython","cmd","p3","binary","tmp","mkdtempSync","tmpdir","execSync","Path","timestamps","diarization","response","ts","arr","buffer","Vision","worker","createWorker","Ai","os","getShell","$Sync","CliTool","DateTimeTool","ExecTool","stream","JSTool","PythonTool","FetchTool","Http","consoleInterceptor","Fn","ReadWebpageTool","html","$","cheerio","metadata","content","contentSelectors","selector","el","WebSearchTool","match","regex","ASet","url"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as O from "node:os";
2
2
  import { tmpdir as L } from "node:os";
3
- import { objectMap as R, JSONAttemptParse as _, findByProp as z, JSONSanitize as S, clean as W, Http as N, consoleInterceptor as C, fn as J, ASet as F } from "@ztimson/utils";
3
+ import { objectMap as R, JSONAttemptParse as _, findByProp as U, JSONSanitize as S, clean as W, Http as N, consoleInterceptor as C, fn as J, ASet as F } from "@ztimson/utils";
4
4
  import { Anthropic as H } from "@anthropic-ai/sdk";
5
5
  import { OpenAI as D } from "openai";
6
6
  import { fileURLToPath as G } from "url";
@@ -13,9 +13,9 @@ import P, { join as q } from "node:path";
13
13
  import { createWorker as Y } from "tesseract.js";
14
14
  import * as Z from "cheerio";
15
15
  import { $Sync as j } from "@ztimson/node-utils";
16
- class U {
16
+ class z {
17
17
  }
18
- class Q extends U {
18
+ class Q extends z {
19
19
  constructor(r, e, t) {
20
20
  super(), this.ai = r, this.apiToken = e, this.model = t, this.client = new H({ apiKey: e });
21
21
  }
@@ -106,7 +106,7 @@ ${JSON.stringify(s, null, 2)}`, o;
106
106
  if (m.length && !t.signal.aborted) {
107
107
  s.push({ role: "assistant", content: u.content });
108
108
  const o = await Promise.all(m.map(async (l) => {
109
- const d = n.find(z("name", l.name));
109
+ const d = n.find(U("name", l.name));
110
110
  if (e.stream && e.stream({ tool: l.name }), !d) return { tool_use_id: l.id, is_error: !0, content: "Tool not found" };
111
111
  try {
112
112
  const p = await d.fn(l.input, e?.stream, this.ai);
@@ -124,7 +124,7 @@ ${JSON.stringify(s, null, 2)}`, o;
124
124
  }), { abort: () => t.abort() });
125
125
  }
126
126
  }
127
- class A extends U {
127
+ class A extends z {
128
128
  constructor(r, e, t, a) {
129
129
  super(), this.ai = r, this.host = e, this.token = t, this.model = a, this.client = new D(W({
130
130
  baseURL: e,
@@ -229,7 +229,7 @@ ${JSON.stringify(n, null, 2)}`, l;
229
229
  if (o.length && !t.signal.aborted) {
230
230
  n.push(i.choices[0].message);
231
231
  const l = await Promise.all(o.map(async (d) => {
232
- const p = c?.find(z("name", d.function.name));
232
+ const p = c?.find(U("name", d.function.name));
233
233
  if (e.stream && e.stream({ tool: d.function.name }), !p) return { role: "tool", tool_call_id: d.id, content: '{"error": "Tool not found"}' };
234
234
  try {
235
235
  const f = _(d.function.arguments, {}), g = await p.fn(f, e.stream, this.ai);
@@ -717,13 +717,15 @@ const re = () => O.platform() == "win32" ? "cmd" : j`echo $SHELL`?.split("/").po
717
717
  },
718
718
  fn: async (h, r, e) => {
719
719
  try {
720
- switch (h.type) {
720
+ switch (h.language) {
721
721
  case "cli":
722
722
  return await ne.fn({ command: h.code }, r, e);
723
723
  case "node":
724
724
  return await se.fn({ code: h.code }, r, e);
725
725
  case "python":
726
726
  return await oe.fn({ code: h.code }, r, e);
727
+ default:
728
+ throw new Error(`Unsupported language: ${h.language}`);
727
729
  }
728
730
  } catch (t) {
729
731
  return { error: t?.message || t.toString() };
@@ -812,7 +814,7 @@ export {
812
814
  ke as ExecTool,
813
815
  xe as FetchTool,
814
816
  se as JSTool,
815
- U as LLMProvider,
817
+ z as LLMProvider,
816
818
  A as OpenAi,
817
819
  oe as PythonTool,
818
820
  _e as ReadWebpageTool,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/provider.ts","../src/antrhopic.ts","../src/open-ai.ts","../src/llm.ts","../src/audio.ts","../src/vision.ts","../src/ai.ts","../src/tools.ts"],"sourcesContent":["import {AbortablePromise} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\n\nexport abstract class LLMProvider {\n\tabstract ask(message: string, options: LLMRequest): AbortablePromise<string>;\n}\n","import {Anthropic as anthropic} from '@anthropic-ai/sdk';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class Anthropic extends LLMProvider {\n\tclient!: anthropic;\n\n\tconstructor(public readonly ai: Ai, public readonly apiToken: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new anthropic({apiKey: apiToken});\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tconst timestamp = Date.now();\n\t\tconst messages: LLMMessage[] = [];\n\t\tfor(let h of history) {\n\t\t\tif(typeof h.content == 'string') {\n\t\t\t\tmessages.push(<any>{timestamp, ...h});\n\t\t\t} else {\n\t\t\t\tconst textContent = h.content?.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n');\n\t\t\t\tif(textContent) messages.push({timestamp, role: h.role, content: textContent});\n\t\t\t\th.content.forEach((c: any) => {\n\t\t\t\t\tif(c.type == 'tool_use') {\n\t\t\t\t\t\tmessages.push({timestamp, role: 'tool', id: c.id, name: c.name, args: c.input, content: undefined});\n\t\t\t\t\t} else if(c.type == 'tool_result') {\n\t\t\t\t\t\tconst m: any = messages.findLast(m => (<any>m).id == c.tool_use_id);\n\t\t\t\t\t\tif(m) m[c.is_error ? 'error' : 'content'] = c.content;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn messages;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tif(history[i].role == 'tool') {\n\t\t\t\tconst h: any = history[i];\n\t\t\t\thistory.splice(i, 1,\n\t\t\t\t\t{role: 'assistant', content: [{type: 'tool_use', id: h.id, name: h.name, input: h.args}]},\n\t\t\t\t\t{role: 'user', content: [{type: 'tool_result', tool_use_id: h.id, is_error: !!h.error, content: h.error || h.content}]}\n\t\t\t\t)\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\treturn history.map(({timestamp, ...h}) => h);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res) => {\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\tsystem: options.system || this.ai.options.llm?.system || '',\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\tname: t.name,\n\t\t\t\t\tdescription: t.description,\n\t\t\t\t\tinput_schema: {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t},\n\t\t\t\t\tfn: undefined\n\t\t\t\t})),\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.messages.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\t// Streaming mode\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.content = [];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.type === 'content_block_start') {\n\t\t\t\t\t\t\tif(chunk.content_block.type === 'text') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'text', text: ''});\n\t\t\t\t\t\t\t} else if(chunk.content_block.type === 'tool_use') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'tool_use', id: chunk.content_block.id, name: chunk.content_block.name, input: <any>''});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_delta') {\n\t\t\t\t\t\t\tif(chunk.delta.type === 'text_delta') {\n\t\t\t\t\t\t\t\tconst text = chunk.delta.text;\n\t\t\t\t\t\t\t\tresp.content.at(-1).text += text;\n\t\t\t\t\t\t\t\toptions.stream({text});\n\t\t\t\t\t\t\t} else if(chunk.delta.type === 'input_json_delta') {\n\t\t\t\t\t\t\t\tresp.content.at(-1).input += chunk.delta.partial_json;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_stop') {\n\t\t\t\t\t\t\tconst last = resp.content.at(-1);\n\t\t\t\t\t\t\tif(last.input != null) last.input = last.input ? JSONAttemptParse(last.input, {}) : {};\n\t\t\t\t\t\t} else if(chunk.type === 'message_stop') {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Run tools\n\t\t\t\tconst toolCalls = resp.content.filter((c: any) => c.type === 'tool_use');\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push({role: 'assistant', content: resp.content});\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools.find(findByProp('name', toolCall.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.name});\n\t\t\t\t\t\tif(!tool) return {tool_use_id: toolCall.id, is_error: true, content: 'Tool not found'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await tool.fn(toolCall.input, options?.stream, this.ai);\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, is_error: true, content: err?.message || err?.toString() || 'Unknown'};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push({role: 'user', content: results});\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.content.some((c: any) => c.type === 'tool_use'));\n\t\t\thistory.push({role: 'assistant', content: resp.content.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n')});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {OpenAI as openAI} from 'openai';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse, clean} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class OpenAi extends LLMProvider {\n\tclient!: openAI;\n\n\tconstructor(public readonly ai: Ai, public readonly host: string | null, public readonly token: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new openAI(clean({\n\t\t\tbaseURL: host,\n\t\t\tapiKey: token || host ? 'ignored' : undefined\n\t\t}));\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tconst h = history[i];\n\t\t\tif(h.role === 'assistant' && h.tool_calls) {\n\t\t\t\tconst tools = h.tool_calls.map((tc: any) => ({\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\tname: tc.function.name,\n\t\t\t\t\targs: JSONAttemptParse(tc.function.arguments, {}),\n\t\t\t\t\ttimestamp: h.timestamp\n\t\t\t\t}));\n\t\t\t\thistory.splice(i, 1, ...tools);\n\t\t\t\ti += tools.length - 1;\n\t\t\t} else if(h.role === 'tool' && h.content) {\n\t\t\t\tconst record = history.find(h2 => h.tool_call_id == h2.id);\n\t\t\t\tif(record) {\n\t\t\t\t\tif(h.content.includes('\"error\":')) record.error = h.content;\n\t\t\t\t\telse record.content = h.content;\n\t\t\t\t}\n\t\t\t\thistory.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t\tif(!history[i]?.timestamp) history[i].timestamp = Date.now();\n\t\t}\n\t\treturn history;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\treturn history.reduce((result, h) => {\n\t\t\tif(h.role === 'tool') {\n\t\t\t\tresult.push({\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: null,\n\t\t\t\t\ttool_calls: [{ id: h.id, type: 'function', function: { name: h.name, arguments: JSON.stringify(h.args) } }],\n\t\t\t\t\trefusal: null,\n\t\t\t\t\tannotations: []\n\t\t\t\t}, {\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\ttool_call_id: h.id,\n\t\t\t\t\tcontent: h.error || h.content\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst {timestamp, ...rest} = h;\n\t\t\t\tresult.push(rest);\n\t\t\t}\n\t\t\treturn result;\n\t\t}, [] as any[]);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res, rej) => {\n\t\t\tif(options.system) {\n\t\t\t\tif(options.history?.[0]?.role != 'system') options.history?.splice(0, 0, {role: 'system', content: options.system, timestamp: Date.now()});\n\t\t\t\telse options.history[0].content = options.system;\n\t\t\t}\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\ttype: 'function',\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: t.name,\n\t\t\t\t\t\tdescription: t.description,\n\t\t\t\t\t\tparameters: {\n\t\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.chat.completions.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.choices = [{message: {role: 'assistant', content: '', tool_calls: []}}];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.choices[0].delta.content) {\n\t\t\t\t\t\t\tresp.choices[0].message.content += chunk.choices[0].delta.content;\n\t\t\t\t\t\t\toptions.stream({text: chunk.choices[0].delta.content});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\tfor(const deltaTC of chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\t\tconst existing = resp.choices[0].message.tool_calls.find(tc => tc.index === deltaTC.index);\n\t\t\t\t\t\t\t\tif(existing) {\n\t\t\t\t\t\t\t\t\tif(deltaTC.id) existing.id = deltaTC.id;\n\t\t\t\t\t\t\t\t\tif(deltaTC.type) existing.type = deltaTC.type;\n\t\t\t\t\t\t\t\t\tif(deltaTC.function) {\n\t\t\t\t\t\t\t\t\t\tif(!existing.function) existing.function = {};\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.name) existing.function.name = deltaTC.function.name;\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.arguments) existing.function.arguments = (existing.function.arguments || '') + deltaTC.function.arguments;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tresp.choices[0].message.tool_calls.push({\n\t\t\t\t\t\t\t\t\t\tindex: deltaTC.index,\n\t\t\t\t\t\t\t\t\t\tid: deltaTC.id || '',\n\t\t\t\t\t\t\t\t\t\ttype: deltaTC.type || 'function',\n\t\t\t\t\t\t\t\t\t\tfunction: {\n\t\t\t\t\t\t\t\t\t\t\tname: deltaTC.function?.name || '',\n\t\t\t\t\t\t\t\t\t\t\targuments: deltaTC.function?.arguments || ''\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst toolCalls = resp.choices[0].message.tool_calls || [];\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push(resp.choices[0].message);\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools?.find(findByProp('name', toolCall.function.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.function.name});\n\t\t\t\t\t\tif(!tool) return {role: 'tool', tool_call_id: toolCall.id, content: '{\"error\": \"Tool not found\"}'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst args = JSONAttemptParse(toolCall.function.arguments, {});\n\t\t\t\t\t\t\tconst result = await tool.fn(args, options.stream, this.ai);\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'})};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push(...results);\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.choices?.[0]?.message?.tool_calls?.length);\n\t\t\thistory.push({role: 'assistant', content: resp.choices[0].message.content || ''});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {Anthropic} from './antrhopic.ts';\nimport {OpenAi} from './open-ai.ts';\nimport {LLMProvider} from './provider.ts';\nimport {AiTool} from './tools.ts';\nimport {fileURLToPath} from 'url';\nimport {dirname, join} from 'path';\nimport { spawn } from 'node:child_process';\n\nexport type AnthropicConfig = {proto: 'anthropic', token: string};\nexport type OllamaConfig = {proto: 'ollama', host: string};\nexport type OpenAiConfig = {proto: 'openai', host?: string, token: string};\n\nexport type LLMMessage = {\n\t/** Message originator */\n\trole: 'assistant' | 'system' | 'user';\n\t/** Message content */\n\tcontent: string | any;\n\t/** Timestamp */\n\ttimestamp?: number;\n} | {\n\t/** Tool call */\n\trole: 'tool';\n\t/** Unique ID for call */\n\tid: string;\n\t/** Tool that was run */\n\tname: string;\n\t/** Tool arguments */\n\targs: any;\n\t/** Tool result */\n\tcontent: undefined | string;\n\t/** Tool error */\n\terror?: undefined | string;\n\t/** Timestamp */\n\ttimestamp?: number;\n}\n\n/** Background information the AI will be fed */\nexport type LLMMemory = {\n\t/** What entity is this fact about */\n\towner: string;\n\t/** The information that will be remembered */\n\tfact: string;\n\t/** Owner and fact embedding vector */\n\tembeddings: [number[], number[]];\n}\n\nexport type LLMRequest = {\n\t/** System prompt */\n\tsystem?: string;\n\t/** Message history */\n\thistory?: LLMMessage[];\n\t/** Max tokens for request */\n\tmax_tokens?: number;\n\t/** 0 = Rigid Logic, 1 = Balanced, 2 = Hyper Creative **/\n\ttemperature?: number;\n\t/** Available tools */\n\ttools?: AiTool[];\n\t/** LLM model */\n\tmodel?: string;\n\t/** Stream response */\n\tstream?: (chunk: {text?: string, tool?: string, done?: true}) => any;\n\t/** Compress old messages in the chat to free up context */\n\tcompress?: {\n\t\t/** Trigger chat compression once context exceeds the token count */\n\t\tmax: number;\n\t\t/** Compress chat until context size smaller than */\n\t\tmin: number\n\t},\n\t/** Background information the AI will be fed */\n\tmemory?: LLMMemory[],\n}\n\nclass LLM {\n\tdefaultModel!: string;\n\tmodels: {[model: string]: LLMProvider} = {};\n\n\tconstructor(public readonly ai: Ai) {\n\t\tif(!ai.options.llm?.models) return;\n\t\tObject.entries(ai.options.llm.models).forEach(([model, config]) => {\n\t\t\tif(!this.defaultModel) this.defaultModel = model;\n\t\t\tif(config.proto == 'anthropic') this.models[model] = new Anthropic(this.ai, config.token, model);\n\t\t\telse if(config.proto == 'ollama') this.models[model] = new OpenAi(this.ai, config.host, 'not-needed', model);\n\t\t\telse if(config.proto == 'openai') this.models[model] = new OpenAi(this.ai, config.host || null, config.token, model);\n\t\t});\n\t}\n\n\t/**\n\t * Chat with LLM\n\t * @param {string} message Question\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {{abort: () => void, response: Promise<string>}} Function to abort response and chat history\n\t */\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\toptions = <any>{\n\t\t\tsystem: '',\n\t\t\ttemperature: 0.8,\n\t\t\t...this.ai.options.llm,\n\t\t\tmodels: undefined,\n\t\t\thistory: [],\n\t\t\t...options,\n\t\t}\n\t\tconst m = options.model || this.defaultModel;\n\t\tif(!this.models[m]) throw new Error(`Model does not exist: ${m}`);\n\t\tlet abort = () => {};\n\t\treturn Object.assign(new Promise<string>(async res => {\n\t\t\tif(!options.history) options.history = [];\n\t\t\t// If memories were passed, find any relevant ones and add a tool for ADHOC lookups\n\t\t\tif(options.memory) {\n\t\t\t\tconst search = async (query?: string | null, subject?: string | null, limit = 10) => {\n\t\t\t\t\tconst [o, q] = await Promise.all([\n\t\t\t\t\t\tsubject ? this.embedding(subject) : Promise.resolve(null),\n\t\t\t\t\t\tquery ? this.embedding(query) : Promise.resolve(null),\n\t\t\t\t\t]);\n\t\t\t\t\treturn (options.memory || []).map(m => {\n\t\t\t\t\t\tconst score = (o ? this.cosineSimilarity(m.embeddings[0], o[0].embedding) : 0)\n\t\t\t\t\t\t\t+ (q ? this.cosineSimilarity(m.embeddings[1], q[0].embedding) : 0);\n\t\t\t\t\t\treturn {...m, score};\n\t\t\t\t\t}).toSorted((a: any, b: any) => a.score - b.score).slice(0, limit);\n\t\t\t\t}\n\n\t\t\t\toptions.system += '\\nYou have RAG memory and will be given the top_k closest memories regarding the users query. Save anything new you have learned worth remembering from the user message using the remember tool and feel free to recall memories manually.\\n';\n\t\t\t\tconst relevant = await search(message);\n\t\t\t\tif(relevant.length) options.history.push({role: 'tool', name: 'recall', id: 'auto_recall_' + Math.random().toString(), args: {}, content: 'Things I remembered:\\n' + relevant.map(m => `${m.owner}: ${m.fact}`).join('\\n')});\n\t\t\t\toptions.tools = [{\n\t\t\t\t\tname: 'recall',\n\t\t\t\t\tdescription: 'Recall the closest memories you have regarding a query using RAG',\n\t\t\t\t\targs: {\n\t\t\t\t\t\tsubject: {type: 'string', description: 'Find information by a subject topic, can be used with or without query argument'},\n\t\t\t\t\t\tquery: {type: 'string', description: 'Search memory based on a query, can be used with or without subject argument'},\n\t\t\t\t\t\ttopK: {type: 'number', description: 'Result limit, default 5'},\n\t\t\t\t\t},\n\t\t\t\t\tfn: (args) => {\n\t\t\t\t\t\tif(!args.subject && !args.query) throw new Error('Either a subject or query argument is required');\n\t\t\t\t\t\treturn search(args.query, args.subject, args.topK);\n\t\t\t\t\t}\n\t\t\t\t}, {\n\t\t\t\t\tname: 'remember',\n\t\t\t\t\tdescription: 'Store important facts user shares for future recall',\n\t\t\t\t\targs: {\n\t\t\t\t\t\towner: {type: 'string', description: 'Subject/person this fact is about'},\n\t\t\t\t\t\tfact: {type: 'string', description: 'The information to remember'}\n\t\t\t\t\t},\n\t\t\t\t\tfn: async (args) => {\n\t\t\t\t\t\tif(!options.memory) return;\n\t\t\t\t\t\tconst e = await Promise.all([\n\t\t\t\t\t\t\tthis.embedding(args.owner),\n\t\t\t\t\t\t\tthis.embedding(`${args.owner}: ${args.fact}`)\n\t\t\t\t\t\t]);\n\t\t\t\t\t\tconst newMem = {owner: args.owner, fact: args.fact, embeddings: <any>[e[0][0].embedding, e[1][0].embedding]};\n\t\t\t\t\t\toptions.memory.splice(0, options.memory.length, ...[\n\t\t\t\t\t\t\t...options.memory.filter(m => {\n\t\t\t\t\t\t\t\treturn !(this.cosineSimilarity(newMem.embeddings[0], m.embeddings[0]) >= 0.9 && this.cosineSimilarity(newMem.embeddings[1], m.embeddings[1]) >= 0.8);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tnewMem\n\t\t\t\t\t\t]);\n\t\t\t\t\t\treturn 'Remembered!';\n\t\t\t\t\t}\n\t\t\t\t}, ...options.tools || []];\n\t\t\t}\n\n\t\t\t// Ask\n\t\t\tconst resp = await this.models[m].ask(message, options);\n\n\t\t\t// Remove any memory calls from history\n\t\t\tif(options.memory) options.history.splice(0, options.history.length, ...options.history.filter(h => h.role != 'tool' || (h.name != 'recall' && h.name != 'remember')));\n\n\t\t\t// Compress message history\n\t\t\tif(options.compress) {\n\t\t\t\tconst compressed = await this.ai.language.compressHistory(options.history, options.compress.max, options.compress.min, options);\n\t\t\t\toptions.history.splice(0, options.history.length, ...compressed);\n\t\t\t}\n\n\t\t\treturn res(resp);\n\t\t}), {abort});\n\t}\n\n\tasync code(message: string, options?: LLMRequest): Promise<any> {\n\t\tconst resp = await this.ask(message, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t'Return your response in a code block'\n\t\t].filter(t => !!t).join(('\\n'))});\n\t\tconst codeBlock = /```(?:.+)?\\s*([\\s\\S]*?)```/.exec(resp);\n\t\treturn codeBlock ? codeBlock[1].trim() : null;\n\t}\n\n\t/**\n\t * Compress chat history to reduce context size\n\t * @param {LLMMessage[]} history Chatlog that will be compressed\n\t * @param max Trigger compression once context is larger than max\n\t * @param min Leave messages less than the token minimum, summarize the rest\n\t * @param {LLMRequest} options LLM options\n\t * @returns {Promise<LLMMessage[]>} New chat history will summary at index 0\n\t */\n\tasync compressHistory(history: LLMMessage[], max: number, min: number, options?: LLMRequest): Promise<LLMMessage[]> {\n\t\tif(this.estimateTokens(history) < max) return history;\n\t\tlet keep = 0, tokens = 0;\n\t\tfor(let m of history.toReversed()) {\n\t\t\ttokens += this.estimateTokens(m.content);\n\t\t\tif(tokens < min) keep++;\n\t\t\telse break;\n\t\t}\n\t\tif(history.length <= keep) return history;\n\t\tconst system = history[0].role == 'system' ? history[0] : null,\n\t\t\trecent = keep == 0 ? [] : history.slice(-keep),\n\t\t\tprocess = (keep == 0 ? history : history.slice(0, -keep)).filter(h => h.role === 'assistant' || h.role === 'user');\n\n\t\tconst summary: any = await this.summarize(process.map(m => `[${m.role}]: ${m.content}`).join('\\n\\n'), 500, options);\n\t\tconst d = Date.now();\n\t\tconst h = [{role: <any>'tool', name: 'summary', id: `summary_` + d, args: {}, content: `Conversation Summary: ${summary?.summary}`, timestamp: d}, ...recent];\n\t\tif(system) h.splice(0, 0, system);\n\t\treturn h;\n\t}\n\n\t/**\n\t * Compare the difference between embeddings (calculates the angle between two vectors)\n\t * @param {number[]} v1 First embedding / vector comparison\n\t * @param {number[]} v2 Second embedding / vector for comparison\n\t * @returns {number} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tcosineSimilarity(v1: number[], v2: number[]): number {\n\t\tif (v1.length !== v2.length) throw new Error('Vectors must be same length');\n\t\tlet dotProduct = 0, normA = 0, normB = 0;\n\t\tfor (let i = 0; i < v1.length; i++) {\n\t\t\tdotProduct += v1[i] * v2[i];\n\t\t\tnormA += v1[i] * v1[i];\n\t\t\tnormB += v2[i] * v2[i];\n\t\t}\n\t\tconst denominator = Math.sqrt(normA) * Math.sqrt(normB);\n\t\treturn denominator === 0 ? 0 : dotProduct / denominator;\n\t}\n\n\t/**\n\t * Chunk text into parts for AI digestion\n\t * @param {object | string} target Item that will be chunked (objects get converted)\n\t * @param {number} maxTokens Chunking size. More = better context, less = more specific (Search by paragraphs or lines)\n\t * @param {number} overlapTokens Includes previous X tokens to provide continuity to AI (In addition to max tokens)\n\t * @returns {string[]} Chunked strings\n\t */\n\tchunk(target: object | string, maxTokens = 500, overlapTokens = 50): string[] {\n\t\tconst objString = (obj: any, path = ''): string[] => {\n\t\t\tif(!obj) return [];\n\t\t\treturn Object.entries(obj).flatMap(([key, value]) => {\n\t\t\t\tconst p = path ? `${path}${isNaN(+key) ? `.${key}` : `[${key}]`}` : key;\n\t\t\t\tif(typeof value === 'object' && !Array.isArray(value)) return objString(value, p);\n\t\t\t\treturn `${p}: ${Array.isArray(value) ? value.join(', ') : value}`;\n\t\t\t});\n\t\t};\n\t\tconst lines = typeof target === 'object' ? objString(target) : target.toString().split('\\n');\n\t\tconst tokens = lines.flatMap(l => [...l.split(/\\s+/).filter(Boolean), '\\n']);\n\t\tconst chunks: string[] = [];\n\t\tfor(let i = 0; i < tokens.length;) {\n\t\t\tlet text = '', j = i;\n\t\t\twhile(j < tokens.length) {\n\t\t\t\tconst next = text + (text ? ' ' : '') + tokens[j];\n\t\t\t\tif(this.estimateTokens(next.replace(/\\s*\\n\\s*/g, '\\n')) > maxTokens && text) break;\n\t\t\t\ttext = next;\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tconst clean = text.replace(/\\s*\\n\\s*/g, '\\n').trim();\n\t\t\tif(clean) chunks.push(clean);\n\t\t\ti = Math.max(j - overlapTokens, j === i ? i + 1 : j);\n\t\t}\n\t\treturn chunks;\n\t}\n\n\t/**\n\t * Create a vector representation of a string\n\t * @param {object | string} target Item that will be embedded (objects get converted)\n\t * @param {maxTokens?: number, overlapTokens?: number} opts Options for embedding such as chunk sizes\n\t * @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings\n\t */\n\tembedding(target: object | string, opts: {maxTokens?: number, overlapTokens?: number} = {}): AbortablePromise<any[]> {\n\t\tlet {maxTokens = 500, overlapTokens = 50} = opts;\n\t\tlet aborted = false;\n\t\tconst abort = () => { aborted = true; };\n\n\t\tconst embed = (text: string): Promise<number[]> => {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\n\t\t\t\tconst args: string[] = [\n\t\t\t\t\tjoin(dirname(fileURLToPath(import.meta.url)), 'embedder.js'),\n\t\t\t\t\t<string>this.ai.options.path,\n\t\t\t\t\tthis.ai.options?.embedder || 'bge-small-en-v1.5'\n\t\t\t\t];\n\t\t\t\tconst proc = spawn('node', args, {stdio: ['pipe', 'pipe', 'ignore']});\n\t\t\t\tproc.stdin.write(text);\n\t\t\t\tproc.stdin.end();\n\n\t\t\t\tlet output = '';\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = JSON.parse(output);\n\t\t\t\t\t\t\tresolve(result.embedding);\n\t\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t\treject(new Error('Failed to parse embedding output'));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Embedder process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t});\n\t\t};\n\n\t\tconst p = (async () => {\n\t\t\tconst chunks = this.chunk(target, maxTokens, overlapTokens), results: any[] = [];\n\t\t\tfor(let i = 0; i < chunks.length; i++) {\n\t\t\t\tif(aborted) break;\n\t\t\t\tconst text = chunks[i];\n\t\t\t\tconst embedding = await embed(text);\n\t\t\t\tresults.push({index: i, embedding, text, tokens: this.estimateTokens(text)});\n\t\t\t}\n\t\t\treturn results;\n\t\t})();\n\t\treturn Object.assign(p, { abort });\n\t}\n\n\t/**\n\t * Estimate variable as tokens\n\t * @param history Object to size\n\t * @returns {number} Rough token count\n\t */\n\testimateTokens(history: any): number {\n\t\tconst text = JSON.stringify(history);\n\t\treturn Math.ceil((text.length / 4) * 1.2);\n\t}\n\n\t/**\n\t * Compare the difference between two strings using tensor math\n\t * @param target Text that will be checked\n\t * @param {string} searchTerms Multiple search terms to check against target\n\t * @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tfuzzyMatch(target: string, ...searchTerms: string[]) {\n\t\tif(searchTerms.length < 2) throw new Error('Requires at least 2 strings to compare');\n\t\tconst vector = (text: string, dimensions: number = 10): number[] => {\n\t\t\treturn text.toLowerCase().split('').map((char, index) =>\n\t\t\t\t(char.charCodeAt(0) * (index + 1)) % dimensions / dimensions).slice(0, dimensions);\n\t\t}\n\t\tconst v = vector(target);\n\t\tconst similarities = searchTerms.map(t => vector(t)).map(refVector => this.cosineSimilarity(v, refVector))\n\t\treturn {avg: similarities.reduce((acc, s) => acc + s, 0) / similarities.length, max: Math.max(...similarities), similarities}\n\t}\n\n\t/**\n\t * Ask a question with JSON response\n\t * @param {string} text Text to process\n\t * @param {string} schema JSON schema the AI should match\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {Promise<{} | {} | RegExpExecArray | null>}\n\t */\n\tasync json(text: string, schema: string, options?: LLMRequest): Promise<any> {\n\t\tconst code = await this.code(text, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t`Only respond using JSON matching this schema:\\n\\`\\`\\`json\\n${schema}\\n\\`\\`\\``\n\t\t].filter(t => !!t).join('\\n')});\n\t\treturn code ? JSONAttemptParse(code, {}) : null;\n\t}\n\n\t/**\n\t * Create a summary of some text\n\t * @param {string} text Text to summarize\n\t * @param {number} tokens Max number of tokens\n\t * @param options LLM request options\n\t * @returns {Promise<string>} Summary\n\t */\n\tsummarize(text: string, tokens: number = 500, options?: LLMRequest): Promise<string | null> {\n\t\treturn this.ask(text, {system: `Generate the shortest summary possible <= ${tokens} tokens. Output nothing else`, temperature: 0.3, ...options});\n\t}\n}\n\nexport default LLM;\n","import {execSync, spawn} from 'node:child_process';\nimport {mkdtempSync} from 'node:fs';\nimport fs from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport * as path from 'node:path';\nimport Path, {join} from 'node:path';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Audio {\n\tprivate downloads: {[key: string]: Promise<string>} = {};\n\tprivate pyannote!: string;\n\tprivate whisperModel!: string;\n\n\tconstructor(private ai: Ai) {\n\t\tif(ai.options.whisper) {\n\t\t\tthis.whisperModel = ai.options.asr || 'ggml-base.en.bin';\n\t\t\tthis.downloadAsrModel();\n\t\t}\n\n\t\tthis.pyannote = `\nimport sys\nimport json\nimport os\nfrom pyannote.audio import Pipeline\n\nos.environ['TORCH_HOME'] = r\"${ai.options.path}\"\npipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization-3.1\", token=\"${ai.options.hfToken}\")\noutput = pipeline(sys.argv[1])\n\nsegments = []\nfor turn, speaker in output.speaker_diarization:\n segments.append({\"start\": turn.start, \"end\": turn.end, \"speaker\": speaker})\n\nprint(json.dumps(segments))\n`;\n\t}\n\n\tprivate async addPunctuation(timestampData: any, llm?: boolean, cadence = 150): Promise<string> {\n\t\tconst countSyllables = (word: string): number => {\n\t\t\tword = word.toLowerCase().replace(/[^a-z]/g, '');\n\t\t\tif(word.length <= 3) return 1;\n\t\t\tconst matches = word.match(/[aeiouy]+/g);\n\t\t\tlet count = matches ? matches.length : 1;\n\t\t\tif(word.endsWith('e')) count--;\n\t\t\treturn Math.max(1, count);\n\t\t};\n\n\t\tlet result = '';\n\t\ttimestampData.transcription.filter((word, i) => {\n\t\t\tlet skip = false;\n\t\t\tconst prevWord = timestampData.transcription[i - 1];\n\t\t\tconst nextWord = timestampData.transcription[i + 1];\n\t\t\tif(!word.text && nextWord) {\n\t\t\t\tnextWord.offsets.from = word.offsets.from;\n\t\t\t\tnextWord.timestamps.from = word.offsets.from;\n\t\t\t} else if(word.text && word.text[0] != ' ' && prevWord) {\n\t\t\t\tprevWord.offsets.to = word.offsets.to;\n\t\t\t\tprevWord.timestamps.to = word.timestamps.to;\n\t\t\t\tprevWord.text += word.text;\n\t\t\t\tskip = true;\n\t\t\t}\n\t\t\treturn !!word.text && !skip;\n\t\t}).forEach((word: any) => {\n\t\t\tconst capital = /^[A-Z]/.test(word.text.trim());\n\t\t\tconst length = word.offsets.to - word.offsets.from;\n\t\t\tconst syllables = countSyllables(word.text.trim());\n\t\t\tconst expected = syllables * cadence;\n\t\t\tif(capital && length > expected * 2 && word.text[0] == ' ') result += '.';\n\t\t\tresult += word.text;\n\t\t});\n\t\tif(!llm) return result.trim();\n\t\treturn this.ai.language.ask(result, {\n\t\t\tsystem: 'Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo',\n\t\t\ttemperature: 0.1,\n\t\t\ttools: [{\n\t\t\t\tname: 'replace',\n\t\t\t\tdescription: 'Use find and replace to fix errors',\n\t\t\t\targs: {\n\t\t\t\t\tfind: {type: 'string', description: 'Text to find', required: true},\n\t\t\t\t\treplace: {type: 'string', description: 'Text to replace', required: true}\n\t\t\t\t},\n\t\t\t\tfn: (args) => result = result.replace(args.find, args.replace)\n\t\t\t}]\n\t\t}).then(() => result);\n\t}\n\n\tprivate async diarizeTranscript(timestampData: any, speakers: any[], llm: boolean): Promise<string> {\n\t\tconst speakerMap = new Map();\n\t\tlet speakerCount = 0;\n\t\tspeakers.forEach((seg: any) => {\n\t\t\tif(!speakerMap.has(seg.speaker)) speakerMap.set(seg.speaker, ++speakerCount);\n\t\t});\n\n\t\tconst punctuatedText = await this.addPunctuation(timestampData, llm);\n\t\tconst sentences = punctuatedText.match(/[^.!?]+[.!?]+/g) || [punctuatedText];\n\t\tconst words = timestampData.transcription.filter((w: any) => w.text.trim());\n\n\t\t// Assign speaker to each sentence\n\t\tconst sentencesWithSpeakers = sentences.map(sentence => {\n\t\t\tsentence = sentence.trim();\n\t\t\tif(!sentence) return null;\n\n\t\t\tconst sentenceWords = sentence.toLowerCase().replace(/[^\\w\\s]/g, '').split(/\\s+/);\n\t\t\tconst speakerWordCount = new Map<number, number>();\n\n\t\t\tsentenceWords.forEach(sw => {\n\t\t\t\tconst word = words.find((w: any) => sw === w.text.trim().toLowerCase().replace(/[^\\w]/g, ''));\n\t\t\t\tif(!word) return;\n\n\t\t\t\tconst wordTime = word.offsets.from / 1000;\n\t\t\t\tconst speaker = speakers.find((seg: any) => wordTime >= seg.start && wordTime <= seg.end);\n\t\t\t\tif(speaker) {\n\t\t\t\t\tconst spkNum = speakerMap.get(speaker.speaker);\n\t\t\t\t\tspeakerWordCount.set(spkNum, (speakerWordCount.get(spkNum) || 0) + 1);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tlet bestSpeaker = 1;\n\t\t\tlet maxWords = 0;\n\t\t\tspeakerWordCount.forEach((count, speaker) => {\n\t\t\t\tif(count > maxWords) {\n\t\t\t\t\tmaxWords = count;\n\t\t\t\t\tbestSpeaker = speaker;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn {speaker: bestSpeaker, text: sentence};\n\t\t}).filter(s => s !== null);\n\n\t\t// Merge adjacent sentences from same speaker\n\t\tconst merged: Array<{speaker: number, text: string}> = [];\n\t\tsentencesWithSpeakers.forEach(item => {\n\t\t\tconst last = merged[merged.length - 1];\n\t\t\tif(last && last.speaker === item.speaker) {\n\t\t\t\tlast.text += ' ' + item.text;\n\t\t\t} else {\n\t\t\t\tmerged.push({...item});\n\t\t\t}\n\t\t});\n\n\t\tlet transcript = merged.map(item => `[Speaker ${item.speaker}]: ${item.text}`).join('\\n').trim();\n\t\tif(!llm) return transcript;\n\t\tlet chunks = this.ai.language.chunk(transcript, 500, 0);\n\t\tif(chunks.length > 4) chunks = [...chunks.slice(0, 3), <string>chunks.at(-1)];\n\t\tconst names = await this.ai.language.json(chunks.join('\\n'), '{1: \"Detected Name\", 2: \"Second Name\"}', {\n\t\t\tsystem: 'Use the following transcript to identify speakers. Only identify speakers you are positive about, dont mention speakers you are unsure about in your response',\n\t\t\ttemperature: 0.1,\n\t\t});\n\t\tObject.entries(names).forEach(([speaker, name]) => transcript = transcript.replaceAll(`[Speaker ${speaker}]`, `[${name}]`));\n\t\treturn transcript;\n\t}\n\n\tprivate runAsr(file: string, opts: {model?: string, diarization?: boolean} = {}): AbortablePromise<any> {\n\t\tlet proc: any;\n\t\tconst p = new Promise<any>((resolve, reject) => {\n\t\t\tthis.downloadAsrModel(opts.model).then(m => {\n\t\t\t\tif(opts.diarization) {\n\t\t\t\t\tlet output = path.join(path.dirname(file), 'transcript');\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper,\n\t\t\t\t\t\t['-m', m, '-f', file, '-np', '-ml', '1', '-oj', '-of', output],\n\t\t\t\t\t\t{stdio: ['ignore', 'ignore', 'pipe']}\n\t\t\t\t\t);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\toutput = await fs.readFile(output + '.json', 'utf-8');\n\t\t\t\t\t\t\tfs.rm(output + '.json').catch(() => { });\n\t\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\t\tcatch(e) { reject(new Error('Failed to parse whisper JSON')); }\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlet output = '';\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper, ['-m', m, '-f', file, '-np', '-nt']);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\tresolve(output.trim() || null);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\treturn <any>Object.assign(p, {abort: () => proc?.kill('SIGTERM')});\n\t}\n\n\tprivate runDiarization(file: string): AbortablePromise<any> {\n\t\tlet aborted = false, abort = () => { aborted = true; };\n\t\tconst checkPython = (cmd: string) => {\n\t\t\treturn new Promise<boolean>((resolve) => {\n\t\t\t\tconst proc = spawn(cmd, ['-W', 'ignore', '-c', 'import pyannote.audio']);\n\t\t\t\tproc.on('close', (code: number) => resolve(code === 0));\n\t\t\t\tproc.on('error', () => resolve(false));\n\t\t\t});\n\t\t};\n\t\tconst p = Promise.all<any>([\n\t\t\tcheckPython('python'),\n\t\t\tcheckPython('python3'),\n\t\t]).then(<any>(async ([p, p3]: [boolean, boolean]) => {\n\t\t\tif(aborted) return;\n\t\t\tif(!p && !p3) throw new Error('Pyannote is not installed: pip install pyannote.audio');\n\t\t\tconst binary = p3 ? 'python3' : 'python';\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return;\n\t\t\t\tlet output = '';\n\t\t\t\tconst proc = spawn(binary, ['-W', 'ignore', '-c', this.pyannote, file]);\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.stderr.on('data', (data: Buffer) => console.error(data.toString()));\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\tcatch (err) { reject(new Error('Failed to parse diarization output')); }\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Python process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t\tabort = () => proc.kill('SIGTERM');\n\t\t\t});\n\t\t}));\n\t\treturn <any>Object.assign(p, {abort});\n\t}\n\n\tasr(file: string, options: { model?: string; diarization?: boolean | 'llm' } = {}): AbortablePromise<string | null> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\n\t\tconst tmp = join(mkdtempSync(join(tmpdir(), 'audio-')), 'converted.wav');\n\t\texecSync(`ffmpeg -i \"${file}\" -ar 16000 -ac 1 -f wav \"${tmp}\"`, { stdio: 'ignore' });\n\t\tconst clean = () => fs.rm(Path.dirname(tmp), {recursive: true, force: true}).catch(() => {});\n\n\t\tif(!options.diarization) return this.runAsr(tmp, {model: options.model});\n\t\tconst timestamps = this.runAsr(tmp, {model: options.model, diarization: true});\n\t\tconst diarization = this.runDiarization(tmp);\n\t\tlet aborted = false, abort = () => {\n\t\t\taborted = true;\n\t\t\ttimestamps.abort();\n\t\t\tdiarization.abort();\n\t\t\tclean();\n\t\t};\n\n\t\tconst response = Promise.allSettled([timestamps, diarization]).then(async ([ts, d]) => {\n\t\t\tif(ts.status == 'rejected') throw new Error('Whisper.cpp timestamps:\\n' + ts.reason);\n\t\t\tif(d.status == 'rejected') throw new Error('Pyannote:\\n' + d.reason);\n\t\t\tif(aborted || !options.diarization) return ts.value;\n\t\t\treturn this.diarizeTranscript(ts.value, d.value, options.diarization == 'llm');\n\t\t}).finally(() => clean());\n\t\treturn <any>Object.assign(response, {abort});\n\t}\n\n\tasync downloadAsrModel(model: string = this.whisperModel): Promise<string> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\t\tif(!model.endsWith('.bin')) model += '.bin';\n\t\tconst p = Path.join(<string>this.ai.options.path, model);\n\t\tif(await fs.stat(p).then(() => true).catch(() => false)) return p;\n\t\tif(!!this.downloads[model]) return this.downloads[model];\n\t\tthis.downloads[model] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${model}`)\n\t\t\t.then(resp => resp.arrayBuffer())\n\t\t\t.then(arr => Buffer.from(arr)).then(async buffer => {\n\t\t\t\tawait fs.writeFile(p, buffer);\n\t\t\t\tdelete this.downloads[model];\n\t\t\t\treturn p;\n\t\t\t});\n\t\treturn this.downloads[model];\n\t}\n}\n","import {createWorker} from 'tesseract.js';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Vision {\n\n\tconstructor(private ai: Ai) {}\n\n\t/**\n\t * Convert image to text using Optical Character Recognition\n\t * @param {string} path Path to image\n\t * @returns {AbortablePromise<string | null>} Promise of extracted text with abort method\n\t */\n\tocr(path: string): AbortablePromise<string | null> {\n\t\tlet worker: any;\n\t\tconst p = new Promise<string | null>(async res => {\n\t\t\tworker = await createWorker(this.ai.options.ocr || 'eng', 2, {cachePath: this.ai.options.path});\n\t\t\tconst {data} = await worker.recognize(path);\n\t\t\tawait worker.terminate();\n\t\t\tres(data.text.trim() || null);\n\t\t});\n\t\treturn Object.assign(p, {abort: () => worker?.terminate()});\n\t}\n}\n","import * as os from 'node:os';\nimport LLM, {AnthropicConfig, OllamaConfig, OpenAiConfig, LLMRequest} from './llm';\nimport { Audio } from './audio.ts';\nimport {Vision} from './vision.ts';\n\nexport type AbortablePromise<T> = Promise<T> & {\n\tabort: () => any\n};\n\nexport type AiOptions = {\n\t/** Token to pull models from hugging face */\n\thfToken?: string;\n\t/** Path to models */\n\tpath?: string;\n\t/** Whisper ASR model: ggml-tiny.en.bin, ggml-base.en.bin */\n\tasr?: string;\n\t/** Embedding model: all-MiniLM-L6-v2, bge-small-en-v1.5, bge-large-en-v1.5 */\n\tembedder?: string;\n\t/** Large language models, first is default */\n\tllm?: Omit<LLMRequest, 'model'> & {\n\t\tmodels: {[model: string]: AnthropicConfig | OllamaConfig | OpenAiConfig};\n\t}\n\t/** OCR model: eng, eng_best, eng_fast */\n\tocr?: string;\n\t/** Whisper binary */\n\twhisper?: string;\n}\n\nexport class Ai {\n\t/** Audio processing AI */\n\taudio!: Audio;\n\t/** Language processing AI */\n\tlanguage!: LLM;\n\t/** Vision processing AI */\n\tvision!: Vision;\n\n\tconstructor(public readonly options: AiOptions) {\n\t\tif(!options.path) options.path = os.tmpdir();\n\t\tprocess.env.TRANSFORMERS_CACHE = options.path;\n\t\tthis.audio = new Audio(this);\n\t\tthis.language = new LLM(this);\n\t\tthis.vision = new Vision(this);\n\t}\n}\n","import * as cheerio from 'cheerio';\nimport {$Sync} from '@ztimson/node-utils';\nimport {ASet, consoleInterceptor, Http, fn as Fn} from '@ztimson/utils';\nimport * as os from 'node:os';\nimport {Ai} from './ai.ts';\nimport {LLMRequest} from './llm.ts';\n\nconst getShell = () => {\n\tif(os.platform() == 'win32') return 'cmd';\n\treturn $Sync`echo $SHELL`?.split('/').pop() || 'bash';\n}\n\nexport type AiToolArg = {[key: string]: {\n\t/** Argument type */\n\ttype: 'array' | 'boolean' | 'number' | 'object' | 'string',\n\t/** Argument description */\n\tdescription: string,\n\t/** Required argument */\n\trequired?: boolean;\n\t/** Default value */\n\tdefault?: any,\n\t/** Options */\n\tenum?: string[],\n\t/** Minimum value or length */\n\tmin?: number,\n\t/** Maximum value or length */\n\tmax?: number,\n\t/** Match pattern */\n\tpattern?: string,\n\t/** Child arguments */\n\titems?: {[key: string]: AiToolArg}\n}}\n\nexport type AiTool = {\n\t/** Tool ID / Name - Must be snail_case */\n\tname: string,\n\t/** Tool description / prompt */\n\tdescription: string,\n\t/** Tool arguments */\n\targs?: AiToolArg,\n\t/** Callback function */\n\tfn: (args: any, stream: LLMRequest['stream'], ai: Ai) => any | Promise<any>,\n};\n\nexport const CliTool: AiTool = {\n\tname: 'cli',\n\tdescription: 'Use the command line interface, returns any output',\n\targs: {command: {type: 'string', description: 'Command to run', required: true}},\n\tfn: (args: {command: string}) => $Sync`${args.command}`\n}\n\nexport const DateTimeTool: AiTool = {\n\tname: 'get_datetime',\n\tdescription: 'Get current UTC date / time',\n\targs: {},\n\tfn: async () => new Date().toUTCString()\n}\n\nexport const ExecTool: AiTool = {\n\tname: 'exec',\n\tdescription: 'Run code/scripts',\n\targs: {\n\t\tlanguage: {type: 'string', description: `Execution language (CLI: ${getShell()})`, enum: ['cli', 'node', 'python'], required: true},\n\t\tcode: {type: 'string', description: 'Code to execute', required: true}\n\t},\n\tfn: async (args, stream, ai) => {\n\t\ttry {\n\t\t\tswitch(args.type) {\n\t\t\t\tcase 'cli':\n\t\t\t\t\treturn await CliTool.fn({command: args.code}, stream, ai);\n\t\t\t\tcase 'node':\n\t\t\t\t\treturn await JSTool.fn({code: args.code}, stream, ai);\n\t\t\t\tcase 'python': {\n\t\t\t\t\treturn await PythonTool.fn({code: args.code}, stream, ai);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch(err: any) {\n\t\t\treturn {error: err?.message || err.toString()};\n\t\t}\n\t}\n}\n\nexport const FetchTool: AiTool = {\n\tname: 'fetch',\n\tdescription: 'Make HTTP request to URL',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to fetch', required: true},\n\t\tmethod: {type: 'string', description: 'HTTP method to use', enum: ['GET', 'POST', 'PUT', 'DELETE'], default: 'GET'},\n\t\theaders: {type: 'object', description: 'HTTP headers to send', default: {}},\n\t\tbody: {type: 'object', description: 'HTTP body to send'},\n\t},\n\tfn: (args: {\n\t\turl: string;\n\t\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE';\n\t\theaders: {[key: string]: string};\n\t\tbody: any;\n\t}) => new Http({url: args.url, headers: args.headers}).request({method: args.method || 'GET', body: args.body})\n}\n\nexport const JSTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => {\n\t\tconst console = consoleInterceptor(null);\n\t\tconst resp = await Fn<any>({console}, args.code, true).catch((err: any) => console.output.error.push(err));\n\t\treturn {...console.output, return: resp, stdout: undefined, stderr: undefined};\n\t}\n}\n\nexport const PythonTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => ({result: $Sync`python -c \"${args.code}\"`})\n}\n\nexport const ReadWebpageTool: AiTool = {\n\tname: 'read_webpage',\n\tdescription: 'Extract clean, structured content from a webpage. Use after web_search to read specific URLs',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to extract content from', required: true},\n\t\tfocus: {type: 'string', description: 'Optional: What aspect to focus on (e.g., \"pricing\", \"features\", \"contact info\")'}\n\t},\n\tfn: async (args: {url: string; focus?: string}) => {\n\t\tconst html = await fetch(args.url, {headers: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"}})\n\t\t\t.then(r => r.text()).catch(err => {throw new Error(`Failed to fetch: ${err.message}`)});\n\n\t\tconst $ = cheerio.load(html);\n\t\t$('script, style, nav, footer, header, aside, iframe, noscript, [role=\"navigation\"], [role=\"banner\"], .ad, .ads, .cookie, .popup').remove();\n\t\tconst metadata = {\n\t\t\ttitle: $('meta[property=\"og:title\"]').attr('content') || $('title').text() || '',\n\t\t\tdescription: $('meta[name=\"description\"]').attr('content') || $('meta[property=\"og:description\"]').attr('content') || '',\n\t\t};\n\n\t\tlet content = '';\n\t\tconst contentSelectors = ['article', 'main', '[role=\"main\"]', '.content', '.post', '.entry', 'body'];\n\t\tfor (const selector of contentSelectors) {\n\t\t\tconst el = $(selector).first();\n\t\t\tif (el.length && el.text().trim().length > 200) {\n\t\t\t\tcontent = el.text();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!content) content = $('body').text();\n\t\tcontent = content.replace(/\\s+/g, ' ').trim().slice(0, 8000);\n\n\t\treturn {url: args.url, title: metadata.title.trim(), description: metadata.description.trim(), content, focus: args.focus};\n\t}\n}\n\nexport const WebSearchTool: AiTool = {\n\tname: 'web_search',\n\tdescription: 'Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool',\n\targs: {\n\t\tquery: {type: 'string', description: 'Search string', required: true},\n\t\tlength: {type: 'string', description: 'Number of results to return', default: 5},\n\t},\n\tfn: async (args: {\n\t\tquery: string;\n\t\tlength: number;\n\t}) => {\n\t\tconst html = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(args.query)}`, {\n\t\t\theaders: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\", \"Accept-Language\": \"en-US,en;q=0.9\"}\n\t\t}).then(resp => resp.text());\n\t\tlet match, regex = /<a .*?href=\"(.+?)\".+?<\\/a>/g;\n\t\tconst results = new ASet<string>();\n\t\twhile((match = regex.exec(html)) !== null) {\n\t\t\tlet url = /uddg=(.+)&amp?/.exec(decodeURIComponent(match[1]))?.[1];\n\t\t\tif(url) url = decodeURIComponent(url);\n\t\t\tif(url) results.add(url);\n\t\t\tif(results.size >= (args.length || 5)) break;\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"names":["LLMProvider","Anthropic","ai","apiToken","model","anthropic","history","timestamp","messages","h","textContent","c","m","i","message","options","controller","res","tools","requestParams","t","objectMap","key","value","resp","isFirstMessage","err","chunk","text","last","JSONAttemptParse","toolCalls","results","toolCall","tool","findByProp","result","JSONSanitize","OpenAi","host","token","openAI","clean","tc","record","h2","rest","rej","deltaTC","existing","args","LLM","config","abort","search","query","subject","limit","o","q","score","a","b","relevant","e","newMem","compressed","codeBlock","max","min","keep","tokens","system","recent","process","summary","d","v1","v2","dotProduct","normA","normB","denominator","target","maxTokens","overlapTokens","objString","obj","path","p","l","chunks","j","next","opts","aborted","embed","resolve","reject","join","dirname","fileURLToPath","proc","spawn","output","data","code","embedding","searchTerms","vector","dimensions","char","index","v","similarities","refVector","acc","s","schema","Audio","timestampData","llm","cadence","countSyllables","word","matches","count","skip","prevWord","nextWord","capital","length","expected","speakers","speakerMap","speakerCount","seg","punctuatedText","sentences","words","w","sentencesWithSpeakers","sentence","sentenceWords","speakerWordCount","sw","wordTime","speaker","spkNum","bestSpeaker","maxWords","merged","item","transcript","names","name","file","fs","checkPython","cmd","p3","binary","tmp","mkdtempSync","tmpdir","execSync","Path","timestamps","diarization","response","ts","arr","buffer","Vision","worker","createWorker","Ai","os","getShell","$Sync","CliTool","DateTimeTool","ExecTool","stream","JSTool","PythonTool","FetchTool","Http","console","consoleInterceptor","Fn","ReadWebpageTool","html","r","$","cheerio","metadata","content","contentSelectors","selector","el","WebSearchTool","match","regex","ASet","url"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/provider.ts","../src/antrhopic.ts","../src/open-ai.ts","../src/llm.ts","../src/audio.ts","../src/vision.ts","../src/ai.ts","../src/tools.ts"],"sourcesContent":["import {AbortablePromise} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\n\nexport abstract class LLMProvider {\n\tabstract ask(message: string, options: LLMRequest): AbortablePromise<string>;\n}\n","import {Anthropic as anthropic} from '@anthropic-ai/sdk';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class Anthropic extends LLMProvider {\n\tclient!: anthropic;\n\n\tconstructor(public readonly ai: Ai, public readonly apiToken: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new anthropic({apiKey: apiToken});\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tconst timestamp = Date.now();\n\t\tconst messages: LLMMessage[] = [];\n\t\tfor(let h of history) {\n\t\t\tif(typeof h.content == 'string') {\n\t\t\t\tmessages.push(<any>{timestamp, ...h});\n\t\t\t} else {\n\t\t\t\tconst textContent = h.content?.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n');\n\t\t\t\tif(textContent) messages.push({timestamp, role: h.role, content: textContent});\n\t\t\t\th.content.forEach((c: any) => {\n\t\t\t\t\tif(c.type == 'tool_use') {\n\t\t\t\t\t\tmessages.push({timestamp, role: 'tool', id: c.id, name: c.name, args: c.input, content: undefined});\n\t\t\t\t\t} else if(c.type == 'tool_result') {\n\t\t\t\t\t\tconst m: any = messages.findLast(m => (<any>m).id == c.tool_use_id);\n\t\t\t\t\t\tif(m) m[c.is_error ? 'error' : 'content'] = c.content;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn messages;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tif(history[i].role == 'tool') {\n\t\t\t\tconst h: any = history[i];\n\t\t\t\thistory.splice(i, 1,\n\t\t\t\t\t{role: 'assistant', content: [{type: 'tool_use', id: h.id, name: h.name, input: h.args}]},\n\t\t\t\t\t{role: 'user', content: [{type: 'tool_result', tool_use_id: h.id, is_error: !!h.error, content: h.error || h.content}]}\n\t\t\t\t)\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\treturn history.map(({timestamp, ...h}) => h);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res) => {\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\tsystem: options.system || this.ai.options.llm?.system || '',\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\tname: t.name,\n\t\t\t\t\tdescription: t.description,\n\t\t\t\t\tinput_schema: {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t},\n\t\t\t\t\tfn: undefined\n\t\t\t\t})),\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.messages.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\t// Streaming mode\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.content = [];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.type === 'content_block_start') {\n\t\t\t\t\t\t\tif(chunk.content_block.type === 'text') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'text', text: ''});\n\t\t\t\t\t\t\t} else if(chunk.content_block.type === 'tool_use') {\n\t\t\t\t\t\t\t\tresp.content.push({type: 'tool_use', id: chunk.content_block.id, name: chunk.content_block.name, input: <any>''});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_delta') {\n\t\t\t\t\t\t\tif(chunk.delta.type === 'text_delta') {\n\t\t\t\t\t\t\t\tconst text = chunk.delta.text;\n\t\t\t\t\t\t\t\tresp.content.at(-1).text += text;\n\t\t\t\t\t\t\t\toptions.stream({text});\n\t\t\t\t\t\t\t} else if(chunk.delta.type === 'input_json_delta') {\n\t\t\t\t\t\t\t\tresp.content.at(-1).input += chunk.delta.partial_json;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if(chunk.type === 'content_block_stop') {\n\t\t\t\t\t\t\tconst last = resp.content.at(-1);\n\t\t\t\t\t\t\tif(last.input != null) last.input = last.input ? JSONAttemptParse(last.input, {}) : {};\n\t\t\t\t\t\t} else if(chunk.type === 'message_stop') {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Run tools\n\t\t\t\tconst toolCalls = resp.content.filter((c: any) => c.type === 'tool_use');\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push({role: 'assistant', content: resp.content});\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools.find(findByProp('name', toolCall.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.name});\n\t\t\t\t\t\tif(!tool) return {tool_use_id: toolCall.id, is_error: true, content: 'Tool not found'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = await tool.fn(toolCall.input, options?.stream, this.ai);\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {type: 'tool_result', tool_use_id: toolCall.id, is_error: true, content: err?.message || err?.toString() || 'Unknown'};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push({role: 'user', content: results});\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.content.some((c: any) => c.type === 'tool_use'));\n\t\t\thistory.push({role: 'assistant', content: resp.content.filter((c: any) => c.type == 'text').map((c: any) => c.text).join('\\n\\n')});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {OpenAI as openAI} from 'openai';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse, clean} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\n\nexport class OpenAi extends LLMProvider {\n\tclient!: openAI;\n\n\tconstructor(public readonly ai: Ai, public readonly host: string | null, public readonly token: string, public model: string) {\n\t\tsuper();\n\t\tthis.client = new openAI(clean({\n\t\t\tbaseURL: host,\n\t\t\tapiKey: token || host ? 'ignored' : undefined\n\t\t}));\n\t}\n\n\tprivate toStandard(history: any[]): LLMMessage[] {\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tconst h = history[i];\n\t\t\tif(h.role === 'assistant' && h.tool_calls) {\n\t\t\t\tconst tools = h.tool_calls.map((tc: any) => ({\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\tid: tc.id,\n\t\t\t\t\tname: tc.function.name,\n\t\t\t\t\targs: JSONAttemptParse(tc.function.arguments, {}),\n\t\t\t\t\ttimestamp: h.timestamp\n\t\t\t\t}));\n\t\t\t\thistory.splice(i, 1, ...tools);\n\t\t\t\ti += tools.length - 1;\n\t\t\t} else if(h.role === 'tool' && h.content) {\n\t\t\t\tconst record = history.find(h2 => h.tool_call_id == h2.id);\n\t\t\t\tif(record) {\n\t\t\t\t\tif(h.content.includes('\"error\":')) record.error = h.content;\n\t\t\t\t\telse record.content = h.content;\n\t\t\t\t}\n\t\t\t\thistory.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t\tif(!history[i]?.timestamp) history[i].timestamp = Date.now();\n\t\t}\n\t\treturn history;\n\t}\n\n\tprivate fromStandard(history: LLMMessage[]): any[] {\n\t\treturn history.reduce((result, h) => {\n\t\t\tif(h.role === 'tool') {\n\t\t\t\tresult.push({\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: null,\n\t\t\t\t\ttool_calls: [{ id: h.id, type: 'function', function: { name: h.name, arguments: JSON.stringify(h.args) } }],\n\t\t\t\t\trefusal: null,\n\t\t\t\t\tannotations: []\n\t\t\t\t}, {\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\ttool_call_id: h.id,\n\t\t\t\t\tcontent: h.error || h.content\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst {timestamp, ...rest} = h;\n\t\t\t\tresult.push(rest);\n\t\t\t}\n\t\t\treturn result;\n\t\t}, [] as any[]);\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res, rej) => {\n\t\t\tif(options.system) {\n\t\t\t\tif(options.history?.[0]?.role != 'system') options.history?.splice(0, 0, {role: 'system', content: options.system, timestamp: Date.now()});\n\t\t\t\telse options.history[0].content = options.system;\n\t\t\t}\n\t\t\tlet history = this.fromStandard([...options.history || [], {role: 'user', content: message, timestamp: Date.now()}]);\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmessages: history,\n\t\t\t\tstream: !!options.stream,\n\t\t\t\tmax_tokens: options.max_tokens || this.ai.options.llm?.max_tokens || 4096,\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || 0.7,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\ttype: 'function',\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: t.name,\n\t\t\t\t\t\tdescription: t.description,\n\t\t\t\t\t\tparameters: {\n\t\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t};\n\n\t\t\tlet resp: any, isFirstMessage = true;\n\t\t\tdo {\n\t\t\t\tresp = await this.client.chat.completions.create(requestParams).catch(err => {\n\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(history, null, 2)}`;\n\t\t\t\t\tthrow err;\n\t\t\t\t});\n\n\t\t\t\tif(options.stream) {\n\t\t\t\t\tif(!isFirstMessage) options.stream({text: '\\n\\n'});\n\t\t\t\t\telse isFirstMessage = false;\n\t\t\t\t\tresp.choices = [{message: {role: 'assistant', content: '', tool_calls: []}}];\n\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\tif(chunk.choices[0].delta.content) {\n\t\t\t\t\t\t\tresp.choices[0].message.content += chunk.choices[0].delta.content;\n\t\t\t\t\t\t\toptions.stream({text: chunk.choices[0].delta.content});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\tfor(const deltaTC of chunk.choices[0].delta.tool_calls) {\n\t\t\t\t\t\t\t\tconst existing = resp.choices[0].message.tool_calls.find(tc => tc.index === deltaTC.index);\n\t\t\t\t\t\t\t\tif(existing) {\n\t\t\t\t\t\t\t\t\tif(deltaTC.id) existing.id = deltaTC.id;\n\t\t\t\t\t\t\t\t\tif(deltaTC.type) existing.type = deltaTC.type;\n\t\t\t\t\t\t\t\t\tif(deltaTC.function) {\n\t\t\t\t\t\t\t\t\t\tif(!existing.function) existing.function = {};\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.name) existing.function.name = deltaTC.function.name;\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function.arguments) existing.function.arguments = (existing.function.arguments || '') + deltaTC.function.arguments;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tresp.choices[0].message.tool_calls.push({\n\t\t\t\t\t\t\t\t\t\tindex: deltaTC.index,\n\t\t\t\t\t\t\t\t\t\tid: deltaTC.id || '',\n\t\t\t\t\t\t\t\t\t\ttype: deltaTC.type || 'function',\n\t\t\t\t\t\t\t\t\t\tfunction: {\n\t\t\t\t\t\t\t\t\t\t\tname: deltaTC.function?.name || '',\n\t\t\t\t\t\t\t\t\t\t\targuments: deltaTC.function?.arguments || ''\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst toolCalls = resp.choices[0].message.tool_calls || [];\n\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\thistory.push(resp.choices[0].message);\n\t\t\t\t\tconst results = await Promise.all(toolCalls.map(async (toolCall: any) => {\n\t\t\t\t\t\tconst tool = tools?.find(findByProp('name', toolCall.function.name));\n\t\t\t\t\t\tif(options.stream) options.stream({tool: toolCall.function.name});\n\t\t\t\t\t\tif(!tool) return {role: 'tool', tool_call_id: toolCall.id, content: '{\"error\": \"Tool not found\"}'};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst args = JSONAttemptParse(toolCall.function.arguments, {});\n\t\t\t\t\t\t\tconst result = await tool.fn(args, options.stream, this.ai);\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize(result)};\n\t\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\t\treturn {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'})};\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t\thistory.push(...results);\n\t\t\t\t\trequestParams.messages = history;\n\t\t\t\t}\n\t\t\t} while (!controller.signal.aborted && resp.choices?.[0]?.message?.tool_calls?.length);\n\t\t\thistory.push({role: 'assistant', content: resp.choices[0].message.content || ''});\n\t\t\thistory = this.toStandard(history);\n\n\t\t\tif(options.stream) options.stream({done: true});\n\t\t\tif(options.history) options.history.splice(0, options.history.length, ...history);\n\t\t\tres(history.at(-1)?.content);\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {JSONAttemptParse} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {Anthropic} from './antrhopic.ts';\nimport {OpenAi} from './open-ai.ts';\nimport {LLMProvider} from './provider.ts';\nimport {AiTool} from './tools.ts';\nimport {fileURLToPath} from 'url';\nimport {dirname, join} from 'path';\nimport { spawn } from 'node:child_process';\n\nexport type AnthropicConfig = {proto: 'anthropic', token: string};\nexport type OllamaConfig = {proto: 'ollama', host: string};\nexport type OpenAiConfig = {proto: 'openai', host?: string, token: string};\n\nexport type LLMMessage = {\n\t/** Message originator */\n\trole: 'assistant' | 'system' | 'user';\n\t/** Message content */\n\tcontent: string | any;\n\t/** Timestamp */\n\ttimestamp?: number;\n} | {\n\t/** Tool call */\n\trole: 'tool';\n\t/** Unique ID for call */\n\tid: string;\n\t/** Tool that was run */\n\tname: string;\n\t/** Tool arguments */\n\targs: any;\n\t/** Tool result */\n\tcontent: undefined | string;\n\t/** Tool error */\n\terror?: undefined | string;\n\t/** Timestamp */\n\ttimestamp?: number;\n}\n\n/** Background information the AI will be fed */\nexport type LLMMemory = {\n\t/** What entity is this fact about */\n\towner: string;\n\t/** The information that will be remembered */\n\tfact: string;\n\t/** Owner and fact embedding vector */\n\tembeddings: [number[], number[]];\n}\n\nexport type LLMRequest = {\n\t/** System prompt */\n\tsystem?: string;\n\t/** Message history */\n\thistory?: LLMMessage[];\n\t/** Max tokens for request */\n\tmax_tokens?: number;\n\t/** 0 = Rigid Logic, 1 = Balanced, 2 = Hyper Creative **/\n\ttemperature?: number;\n\t/** Available tools */\n\ttools?: AiTool[];\n\t/** LLM model */\n\tmodel?: string;\n\t/** Stream response */\n\tstream?: (chunk: {text?: string, tool?: string, done?: true}) => any;\n\t/** Compress old messages in the chat to free up context */\n\tcompress?: {\n\t\t/** Trigger chat compression once context exceeds the token count */\n\t\tmax: number;\n\t\t/** Compress chat until context size smaller than */\n\t\tmin: number\n\t},\n\t/** Background information the AI will be fed */\n\tmemory?: LLMMemory[],\n}\n\nclass LLM {\n\tdefaultModel!: string;\n\tmodels: {[model: string]: LLMProvider} = {};\n\n\tconstructor(public readonly ai: Ai) {\n\t\tif(!ai.options.llm?.models) return;\n\t\tObject.entries(ai.options.llm.models).forEach(([model, config]) => {\n\t\t\tif(!this.defaultModel) this.defaultModel = model;\n\t\t\tif(config.proto == 'anthropic') this.models[model] = new Anthropic(this.ai, config.token, model);\n\t\t\telse if(config.proto == 'ollama') this.models[model] = new OpenAi(this.ai, config.host, 'not-needed', model);\n\t\t\telse if(config.proto == 'openai') this.models[model] = new OpenAi(this.ai, config.host || null, config.token, model);\n\t\t});\n\t}\n\n\t/**\n\t * Chat with LLM\n\t * @param {string} message Question\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {{abort: () => void, response: Promise<string>}} Function to abort response and chat history\n\t */\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\toptions = <any>{\n\t\t\tsystem: '',\n\t\t\ttemperature: 0.8,\n\t\t\t...this.ai.options.llm,\n\t\t\tmodels: undefined,\n\t\t\thistory: [],\n\t\t\t...options,\n\t\t}\n\t\tconst m = options.model || this.defaultModel;\n\t\tif(!this.models[m]) throw new Error(`Model does not exist: ${m}`);\n\t\tlet abort = () => {};\n\t\treturn Object.assign(new Promise<string>(async res => {\n\t\t\tif(!options.history) options.history = [];\n\t\t\t// If memories were passed, find any relevant ones and add a tool for ADHOC lookups\n\t\t\tif(options.memory) {\n\t\t\t\tconst search = async (query?: string | null, subject?: string | null, limit = 10) => {\n\t\t\t\t\tconst [o, q] = await Promise.all([\n\t\t\t\t\t\tsubject ? this.embedding(subject) : Promise.resolve(null),\n\t\t\t\t\t\tquery ? this.embedding(query) : Promise.resolve(null),\n\t\t\t\t\t]);\n\t\t\t\t\treturn (options.memory || []).map(m => {\n\t\t\t\t\t\tconst score = (o ? this.cosineSimilarity(m.embeddings[0], o[0].embedding) : 0)\n\t\t\t\t\t\t\t+ (q ? this.cosineSimilarity(m.embeddings[1], q[0].embedding) : 0);\n\t\t\t\t\t\treturn {...m, score};\n\t\t\t\t\t}).toSorted((a: any, b: any) => a.score - b.score).slice(0, limit);\n\t\t\t\t}\n\n\t\t\t\toptions.system += '\\nYou have RAG memory and will be given the top_k closest memories regarding the users query. Save anything new you have learned worth remembering from the user message using the remember tool and feel free to recall memories manually.\\n';\n\t\t\t\tconst relevant = await search(message);\n\t\t\t\tif(relevant.length) options.history.push({role: 'tool', name: 'recall', id: 'auto_recall_' + Math.random().toString(), args: {}, content: 'Things I remembered:\\n' + relevant.map(m => `${m.owner}: ${m.fact}`).join('\\n')});\n\t\t\t\toptions.tools = [{\n\t\t\t\t\tname: 'recall',\n\t\t\t\t\tdescription: 'Recall the closest memories you have regarding a query using RAG',\n\t\t\t\t\targs: {\n\t\t\t\t\t\tsubject: {type: 'string', description: 'Find information by a subject topic, can be used with or without query argument'},\n\t\t\t\t\t\tquery: {type: 'string', description: 'Search memory based on a query, can be used with or without subject argument'},\n\t\t\t\t\t\ttopK: {type: 'number', description: 'Result limit, default 5'},\n\t\t\t\t\t},\n\t\t\t\t\tfn: (args) => {\n\t\t\t\t\t\tif(!args.subject && !args.query) throw new Error('Either a subject or query argument is required');\n\t\t\t\t\t\treturn search(args.query, args.subject, args.topK);\n\t\t\t\t\t}\n\t\t\t\t}, {\n\t\t\t\t\tname: 'remember',\n\t\t\t\t\tdescription: 'Store important facts user shares for future recall',\n\t\t\t\t\targs: {\n\t\t\t\t\t\towner: {type: 'string', description: 'Subject/person this fact is about'},\n\t\t\t\t\t\tfact: {type: 'string', description: 'The information to remember'}\n\t\t\t\t\t},\n\t\t\t\t\tfn: async (args) => {\n\t\t\t\t\t\tif(!options.memory) return;\n\t\t\t\t\t\tconst e = await Promise.all([\n\t\t\t\t\t\t\tthis.embedding(args.owner),\n\t\t\t\t\t\t\tthis.embedding(`${args.owner}: ${args.fact}`)\n\t\t\t\t\t\t]);\n\t\t\t\t\t\tconst newMem = {owner: args.owner, fact: args.fact, embeddings: <any>[e[0][0].embedding, e[1][0].embedding]};\n\t\t\t\t\t\toptions.memory.splice(0, options.memory.length, ...[\n\t\t\t\t\t\t\t...options.memory.filter(m => {\n\t\t\t\t\t\t\t\treturn !(this.cosineSimilarity(newMem.embeddings[0], m.embeddings[0]) >= 0.9 && this.cosineSimilarity(newMem.embeddings[1], m.embeddings[1]) >= 0.8);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tnewMem\n\t\t\t\t\t\t]);\n\t\t\t\t\t\treturn 'Remembered!';\n\t\t\t\t\t}\n\t\t\t\t}, ...options.tools || []];\n\t\t\t}\n\n\t\t\t// Ask\n\t\t\tconst resp = await this.models[m].ask(message, options);\n\n\t\t\t// Remove any memory calls from history\n\t\t\tif(options.memory) options.history.splice(0, options.history.length, ...options.history.filter(h => h.role != 'tool' || (h.name != 'recall' && h.name != 'remember')));\n\n\t\t\t// Compress message history\n\t\t\tif(options.compress) {\n\t\t\t\tconst compressed = await this.ai.language.compressHistory(options.history, options.compress.max, options.compress.min, options);\n\t\t\t\toptions.history.splice(0, options.history.length, ...compressed);\n\t\t\t}\n\n\t\t\treturn res(resp);\n\t\t}), {abort});\n\t}\n\n\tasync code(message: string, options?: LLMRequest): Promise<any> {\n\t\tconst resp = await this.ask(message, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t'Return your response in a code block'\n\t\t].filter(t => !!t).join(('\\n'))});\n\t\tconst codeBlock = /```(?:.+)?\\s*([\\s\\S]*?)```/.exec(resp);\n\t\treturn codeBlock ? codeBlock[1].trim() : null;\n\t}\n\n\t/**\n\t * Compress chat history to reduce context size\n\t * @param {LLMMessage[]} history Chatlog that will be compressed\n\t * @param max Trigger compression once context is larger than max\n\t * @param min Leave messages less than the token minimum, summarize the rest\n\t * @param {LLMRequest} options LLM options\n\t * @returns {Promise<LLMMessage[]>} New chat history will summary at index 0\n\t */\n\tasync compressHistory(history: LLMMessage[], max: number, min: number, options?: LLMRequest): Promise<LLMMessage[]> {\n\t\tif(this.estimateTokens(history) < max) return history;\n\t\tlet keep = 0, tokens = 0;\n\t\tfor(let m of history.toReversed()) {\n\t\t\ttokens += this.estimateTokens(m.content);\n\t\t\tif(tokens < min) keep++;\n\t\t\telse break;\n\t\t}\n\t\tif(history.length <= keep) return history;\n\t\tconst system = history[0].role == 'system' ? history[0] : null,\n\t\t\trecent = keep == 0 ? [] : history.slice(-keep),\n\t\t\tprocess = (keep == 0 ? history : history.slice(0, -keep)).filter(h => h.role === 'assistant' || h.role === 'user');\n\n\t\tconst summary: any = await this.summarize(process.map(m => `[${m.role}]: ${m.content}`).join('\\n\\n'), 500, options);\n\t\tconst d = Date.now();\n\t\tconst h = [{role: <any>'tool', name: 'summary', id: `summary_` + d, args: {}, content: `Conversation Summary: ${summary?.summary}`, timestamp: d}, ...recent];\n\t\tif(system) h.splice(0, 0, system);\n\t\treturn h;\n\t}\n\n\t/**\n\t * Compare the difference between embeddings (calculates the angle between two vectors)\n\t * @param {number[]} v1 First embedding / vector comparison\n\t * @param {number[]} v2 Second embedding / vector for comparison\n\t * @returns {number} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tcosineSimilarity(v1: number[], v2: number[]): number {\n\t\tif (v1.length !== v2.length) throw new Error('Vectors must be same length');\n\t\tlet dotProduct = 0, normA = 0, normB = 0;\n\t\tfor (let i = 0; i < v1.length; i++) {\n\t\t\tdotProduct += v1[i] * v2[i];\n\t\t\tnormA += v1[i] * v1[i];\n\t\t\tnormB += v2[i] * v2[i];\n\t\t}\n\t\tconst denominator = Math.sqrt(normA) * Math.sqrt(normB);\n\t\treturn denominator === 0 ? 0 : dotProduct / denominator;\n\t}\n\n\t/**\n\t * Chunk text into parts for AI digestion\n\t * @param {object | string} target Item that will be chunked (objects get converted)\n\t * @param {number} maxTokens Chunking size. More = better context, less = more specific (Search by paragraphs or lines)\n\t * @param {number} overlapTokens Includes previous X tokens to provide continuity to AI (In addition to max tokens)\n\t * @returns {string[]} Chunked strings\n\t */\n\tchunk(target: object | string, maxTokens = 500, overlapTokens = 50): string[] {\n\t\tconst objString = (obj: any, path = ''): string[] => {\n\t\t\tif(!obj) return [];\n\t\t\treturn Object.entries(obj).flatMap(([key, value]) => {\n\t\t\t\tconst p = path ? `${path}${isNaN(+key) ? `.${key}` : `[${key}]`}` : key;\n\t\t\t\tif(typeof value === 'object' && !Array.isArray(value)) return objString(value, p);\n\t\t\t\treturn `${p}: ${Array.isArray(value) ? value.join(', ') : value}`;\n\t\t\t});\n\t\t};\n\t\tconst lines = typeof target === 'object' ? objString(target) : target.toString().split('\\n');\n\t\tconst tokens = lines.flatMap(l => [...l.split(/\\s+/).filter(Boolean), '\\n']);\n\t\tconst chunks: string[] = [];\n\t\tfor(let i = 0; i < tokens.length;) {\n\t\t\tlet text = '', j = i;\n\t\t\twhile(j < tokens.length) {\n\t\t\t\tconst next = text + (text ? ' ' : '') + tokens[j];\n\t\t\t\tif(this.estimateTokens(next.replace(/\\s*\\n\\s*/g, '\\n')) > maxTokens && text) break;\n\t\t\t\ttext = next;\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tconst clean = text.replace(/\\s*\\n\\s*/g, '\\n').trim();\n\t\t\tif(clean) chunks.push(clean);\n\t\t\ti = Math.max(j - overlapTokens, j === i ? i + 1 : j);\n\t\t}\n\t\treturn chunks;\n\t}\n\n\t/**\n\t * Create a vector representation of a string\n\t * @param {object | string} target Item that will be embedded (objects get converted)\n\t * @param {maxTokens?: number, overlapTokens?: number} opts Options for embedding such as chunk sizes\n\t * @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings\n\t */\n\tembedding(target: object | string, opts: {maxTokens?: number, overlapTokens?: number} = {}): AbortablePromise<any[]> {\n\t\tlet {maxTokens = 500, overlapTokens = 50} = opts;\n\t\tlet aborted = false;\n\t\tconst abort = () => { aborted = true; };\n\n\t\tconst embed = (text: string): Promise<number[]> => {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\n\t\t\t\tconst args: string[] = [\n\t\t\t\t\tjoin(dirname(fileURLToPath(import.meta.url)), 'embedder.js'),\n\t\t\t\t\t<string>this.ai.options.path,\n\t\t\t\t\tthis.ai.options?.embedder || 'bge-small-en-v1.5'\n\t\t\t\t];\n\t\t\t\tconst proc = spawn('node', args, {stdio: ['pipe', 'pipe', 'ignore']});\n\t\t\t\tproc.stdin.write(text);\n\t\t\t\tproc.stdin.end();\n\n\t\t\t\tlet output = '';\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = JSON.parse(output);\n\t\t\t\t\t\t\tresolve(result.embedding);\n\t\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t\treject(new Error('Failed to parse embedding output'));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Embedder process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t});\n\t\t};\n\n\t\tconst p = (async () => {\n\t\t\tconst chunks = this.chunk(target, maxTokens, overlapTokens), results: any[] = [];\n\t\t\tfor(let i = 0; i < chunks.length; i++) {\n\t\t\t\tif(aborted) break;\n\t\t\t\tconst text = chunks[i];\n\t\t\t\tconst embedding = await embed(text);\n\t\t\t\tresults.push({index: i, embedding, text, tokens: this.estimateTokens(text)});\n\t\t\t}\n\t\t\treturn results;\n\t\t})();\n\t\treturn Object.assign(p, { abort });\n\t}\n\n\t/**\n\t * Estimate variable as tokens\n\t * @param history Object to size\n\t * @returns {number} Rough token count\n\t */\n\testimateTokens(history: any): number {\n\t\tconst text = JSON.stringify(history);\n\t\treturn Math.ceil((text.length / 4) * 1.2);\n\t}\n\n\t/**\n\t * Compare the difference between two strings using tensor math\n\t * @param target Text that will be checked\n\t * @param {string} searchTerms Multiple search terms to check against target\n\t * @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tfuzzyMatch(target: string, ...searchTerms: string[]) {\n\t\tif(searchTerms.length < 2) throw new Error('Requires at least 2 strings to compare');\n\t\tconst vector = (text: string, dimensions: number = 10): number[] => {\n\t\t\treturn text.toLowerCase().split('').map((char, index) =>\n\t\t\t\t(char.charCodeAt(0) * (index + 1)) % dimensions / dimensions).slice(0, dimensions);\n\t\t}\n\t\tconst v = vector(target);\n\t\tconst similarities = searchTerms.map(t => vector(t)).map(refVector => this.cosineSimilarity(v, refVector))\n\t\treturn {avg: similarities.reduce((acc, s) => acc + s, 0) / similarities.length, max: Math.max(...similarities), similarities}\n\t}\n\n\t/**\n\t * Ask a question with JSON response\n\t * @param {string} text Text to process\n\t * @param {string} schema JSON schema the AI should match\n\t * @param {LLMRequest} options Configuration options and chat history\n\t * @returns {Promise<{} | {} | RegExpExecArray | null>}\n\t */\n\tasync json(text: string, schema: string, options?: LLMRequest): Promise<any> {\n\t\tconst code = await this.code(text, {...options, system: [\n\t\t\toptions?.system,\n\t\t\t`Only respond using JSON matching this schema:\\n\\`\\`\\`json\\n${schema}\\n\\`\\`\\``\n\t\t].filter(t => !!t).join('\\n')});\n\t\treturn code ? JSONAttemptParse(code, {}) : null;\n\t}\n\n\t/**\n\t * Create a summary of some text\n\t * @param {string} text Text to summarize\n\t * @param {number} tokens Max number of tokens\n\t * @param options LLM request options\n\t * @returns {Promise<string>} Summary\n\t */\n\tsummarize(text: string, tokens: number = 500, options?: LLMRequest): Promise<string | null> {\n\t\treturn this.ask(text, {system: `Generate the shortest summary possible <= ${tokens} tokens. Output nothing else`, temperature: 0.3, ...options});\n\t}\n}\n\nexport default LLM;\n","import {execSync, spawn} from 'node:child_process';\nimport {mkdtempSync} from 'node:fs';\nimport fs from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport * as path from 'node:path';\nimport Path, {join} from 'node:path';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Audio {\n\tprivate downloads: {[key: string]: Promise<string>} = {};\n\tprivate pyannote!: string;\n\tprivate whisperModel!: string;\n\n\tconstructor(private ai: Ai) {\n\t\tif(ai.options.whisper) {\n\t\t\tthis.whisperModel = ai.options.asr || 'ggml-base.en.bin';\n\t\t\tthis.downloadAsrModel();\n\t\t}\n\n\t\tthis.pyannote = `\nimport sys\nimport json\nimport os\nfrom pyannote.audio import Pipeline\n\nos.environ['TORCH_HOME'] = r\"${ai.options.path}\"\npipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization-3.1\", token=\"${ai.options.hfToken}\")\noutput = pipeline(sys.argv[1])\n\nsegments = []\nfor turn, speaker in output.speaker_diarization:\n segments.append({\"start\": turn.start, \"end\": turn.end, \"speaker\": speaker})\n\nprint(json.dumps(segments))\n`;\n\t}\n\n\tprivate async addPunctuation(timestampData: any, llm?: boolean, cadence = 150): Promise<string> {\n\t\tconst countSyllables = (word: string): number => {\n\t\t\tword = word.toLowerCase().replace(/[^a-z]/g, '');\n\t\t\tif(word.length <= 3) return 1;\n\t\t\tconst matches = word.match(/[aeiouy]+/g);\n\t\t\tlet count = matches ? matches.length : 1;\n\t\t\tif(word.endsWith('e')) count--;\n\t\t\treturn Math.max(1, count);\n\t\t};\n\n\t\tlet result = '';\n\t\ttimestampData.transcription.filter((word, i) => {\n\t\t\tlet skip = false;\n\t\t\tconst prevWord = timestampData.transcription[i - 1];\n\t\t\tconst nextWord = timestampData.transcription[i + 1];\n\t\t\tif(!word.text && nextWord) {\n\t\t\t\tnextWord.offsets.from = word.offsets.from;\n\t\t\t\tnextWord.timestamps.from = word.offsets.from;\n\t\t\t} else if(word.text && word.text[0] != ' ' && prevWord) {\n\t\t\t\tprevWord.offsets.to = word.offsets.to;\n\t\t\t\tprevWord.timestamps.to = word.timestamps.to;\n\t\t\t\tprevWord.text += word.text;\n\t\t\t\tskip = true;\n\t\t\t}\n\t\t\treturn !!word.text && !skip;\n\t\t}).forEach((word: any) => {\n\t\t\tconst capital = /^[A-Z]/.test(word.text.trim());\n\t\t\tconst length = word.offsets.to - word.offsets.from;\n\t\t\tconst syllables = countSyllables(word.text.trim());\n\t\t\tconst expected = syllables * cadence;\n\t\t\tif(capital && length > expected * 2 && word.text[0] == ' ') result += '.';\n\t\t\tresult += word.text;\n\t\t});\n\t\tif(!llm) return result.trim();\n\t\treturn this.ai.language.ask(result, {\n\t\t\tsystem: 'Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo',\n\t\t\ttemperature: 0.1,\n\t\t\ttools: [{\n\t\t\t\tname: 'replace',\n\t\t\t\tdescription: 'Use find and replace to fix errors',\n\t\t\t\targs: {\n\t\t\t\t\tfind: {type: 'string', description: 'Text to find', required: true},\n\t\t\t\t\treplace: {type: 'string', description: 'Text to replace', required: true}\n\t\t\t\t},\n\t\t\t\tfn: (args) => result = result.replace(args.find, args.replace)\n\t\t\t}]\n\t\t}).then(() => result);\n\t}\n\n\tprivate async diarizeTranscript(timestampData: any, speakers: any[], llm: boolean): Promise<string> {\n\t\tconst speakerMap = new Map();\n\t\tlet speakerCount = 0;\n\t\tspeakers.forEach((seg: any) => {\n\t\t\tif(!speakerMap.has(seg.speaker)) speakerMap.set(seg.speaker, ++speakerCount);\n\t\t});\n\n\t\tconst punctuatedText = await this.addPunctuation(timestampData, llm);\n\t\tconst sentences = punctuatedText.match(/[^.!?]+[.!?]+/g) || [punctuatedText];\n\t\tconst words = timestampData.transcription.filter((w: any) => w.text.trim());\n\n\t\t// Assign speaker to each sentence\n\t\tconst sentencesWithSpeakers = sentences.map(sentence => {\n\t\t\tsentence = sentence.trim();\n\t\t\tif(!sentence) return null;\n\n\t\t\tconst sentenceWords = sentence.toLowerCase().replace(/[^\\w\\s]/g, '').split(/\\s+/);\n\t\t\tconst speakerWordCount = new Map<number, number>();\n\n\t\t\tsentenceWords.forEach(sw => {\n\t\t\t\tconst word = words.find((w: any) => sw === w.text.trim().toLowerCase().replace(/[^\\w]/g, ''));\n\t\t\t\tif(!word) return;\n\n\t\t\t\tconst wordTime = word.offsets.from / 1000;\n\t\t\t\tconst speaker = speakers.find((seg: any) => wordTime >= seg.start && wordTime <= seg.end);\n\t\t\t\tif(speaker) {\n\t\t\t\t\tconst spkNum = speakerMap.get(speaker.speaker);\n\t\t\t\t\tspeakerWordCount.set(spkNum, (speakerWordCount.get(spkNum) || 0) + 1);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tlet bestSpeaker = 1;\n\t\t\tlet maxWords = 0;\n\t\t\tspeakerWordCount.forEach((count, speaker) => {\n\t\t\t\tif(count > maxWords) {\n\t\t\t\t\tmaxWords = count;\n\t\t\t\t\tbestSpeaker = speaker;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn {speaker: bestSpeaker, text: sentence};\n\t\t}).filter(s => s !== null);\n\n\t\t// Merge adjacent sentences from same speaker\n\t\tconst merged: Array<{speaker: number, text: string}> = [];\n\t\tsentencesWithSpeakers.forEach(item => {\n\t\t\tconst last = merged[merged.length - 1];\n\t\t\tif(last && last.speaker === item.speaker) {\n\t\t\t\tlast.text += ' ' + item.text;\n\t\t\t} else {\n\t\t\t\tmerged.push({...item});\n\t\t\t}\n\t\t});\n\n\t\tlet transcript = merged.map(item => `[Speaker ${item.speaker}]: ${item.text}`).join('\\n').trim();\n\t\tif(!llm) return transcript;\n\t\tlet chunks = this.ai.language.chunk(transcript, 500, 0);\n\t\tif(chunks.length > 4) chunks = [...chunks.slice(0, 3), <string>chunks.at(-1)];\n\t\tconst names = await this.ai.language.json(chunks.join('\\n'), '{1: \"Detected Name\", 2: \"Second Name\"}', {\n\t\t\tsystem: 'Use the following transcript to identify speakers. Only identify speakers you are positive about, dont mention speakers you are unsure about in your response',\n\t\t\ttemperature: 0.1,\n\t\t});\n\t\tObject.entries(names).forEach(([speaker, name]) => transcript = transcript.replaceAll(`[Speaker ${speaker}]`, `[${name}]`));\n\t\treturn transcript;\n\t}\n\n\tprivate runAsr(file: string, opts: {model?: string, diarization?: boolean} = {}): AbortablePromise<any> {\n\t\tlet proc: any;\n\t\tconst p = new Promise<any>((resolve, reject) => {\n\t\t\tthis.downloadAsrModel(opts.model).then(m => {\n\t\t\t\tif(opts.diarization) {\n\t\t\t\t\tlet output = path.join(path.dirname(file), 'transcript');\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper,\n\t\t\t\t\t\t['-m', m, '-f', file, '-np', '-ml', '1', '-oj', '-of', output],\n\t\t\t\t\t\t{stdio: ['ignore', 'ignore', 'pipe']}\n\t\t\t\t\t);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\toutput = await fs.readFile(output + '.json', 'utf-8');\n\t\t\t\t\t\t\tfs.rm(output + '.json').catch(() => { });\n\t\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\t\tcatch(e) { reject(new Error('Failed to parse whisper JSON')); }\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlet output = '';\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper, ['-m', m, '-f', file, '-np', '-nt']);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\tresolve(output.trim() || null);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\treturn <any>Object.assign(p, {abort: () => proc?.kill('SIGTERM')});\n\t}\n\n\tprivate runDiarization(file: string): AbortablePromise<any> {\n\t\tlet aborted = false, abort = () => { aborted = true; };\n\t\tconst checkPython = (cmd: string) => {\n\t\t\treturn new Promise<boolean>((resolve) => {\n\t\t\t\tconst proc = spawn(cmd, ['-W', 'ignore', '-c', 'import pyannote.audio']);\n\t\t\t\tproc.on('close', (code: number) => resolve(code === 0));\n\t\t\t\tproc.on('error', () => resolve(false));\n\t\t\t});\n\t\t};\n\t\tconst p = Promise.all<any>([\n\t\t\tcheckPython('python'),\n\t\t\tcheckPython('python3'),\n\t\t]).then(<any>(async ([p, p3]: [boolean, boolean]) => {\n\t\t\tif(aborted) return;\n\t\t\tif(!p && !p3) throw new Error('Pyannote is not installed: pip install pyannote.audio');\n\t\t\tconst binary = p3 ? 'python3' : 'python';\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return;\n\t\t\t\tlet output = '';\n\t\t\t\tconst proc = spawn(binary, ['-W', 'ignore', '-c', this.pyannote, file]);\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.stderr.on('data', (data: Buffer) => console.error(data.toString()));\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\tcatch (err) { reject(new Error('Failed to parse diarization output')); }\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Python process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t\tabort = () => proc.kill('SIGTERM');\n\t\t\t});\n\t\t}));\n\t\treturn <any>Object.assign(p, {abort});\n\t}\n\n\tasr(file: string, options: { model?: string; diarization?: boolean | 'llm' } = {}): AbortablePromise<string | null> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\n\t\tconst tmp = join(mkdtempSync(join(tmpdir(), 'audio-')), 'converted.wav');\n\t\texecSync(`ffmpeg -i \"${file}\" -ar 16000 -ac 1 -f wav \"${tmp}\"`, { stdio: 'ignore' });\n\t\tconst clean = () => fs.rm(Path.dirname(tmp), {recursive: true, force: true}).catch(() => {});\n\n\t\tif(!options.diarization) return this.runAsr(tmp, {model: options.model});\n\t\tconst timestamps = this.runAsr(tmp, {model: options.model, diarization: true});\n\t\tconst diarization = this.runDiarization(tmp);\n\t\tlet aborted = false, abort = () => {\n\t\t\taborted = true;\n\t\t\ttimestamps.abort();\n\t\t\tdiarization.abort();\n\t\t\tclean();\n\t\t};\n\n\t\tconst response = Promise.allSettled([timestamps, diarization]).then(async ([ts, d]) => {\n\t\t\tif(ts.status == 'rejected') throw new Error('Whisper.cpp timestamps:\\n' + ts.reason);\n\t\t\tif(d.status == 'rejected') throw new Error('Pyannote:\\n' + d.reason);\n\t\t\tif(aborted || !options.diarization) return ts.value;\n\t\t\treturn this.diarizeTranscript(ts.value, d.value, options.diarization == 'llm');\n\t\t}).finally(() => clean());\n\t\treturn <any>Object.assign(response, {abort});\n\t}\n\n\tasync downloadAsrModel(model: string = this.whisperModel): Promise<string> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\t\tif(!model.endsWith('.bin')) model += '.bin';\n\t\tconst p = Path.join(<string>this.ai.options.path, model);\n\t\tif(await fs.stat(p).then(() => true).catch(() => false)) return p;\n\t\tif(!!this.downloads[model]) return this.downloads[model];\n\t\tthis.downloads[model] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${model}`)\n\t\t\t.then(resp => resp.arrayBuffer())\n\t\t\t.then(arr => Buffer.from(arr)).then(async buffer => {\n\t\t\t\tawait fs.writeFile(p, buffer);\n\t\t\t\tdelete this.downloads[model];\n\t\t\t\treturn p;\n\t\t\t});\n\t\treturn this.downloads[model];\n\t}\n}\n","import {createWorker} from 'tesseract.js';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Vision {\n\n\tconstructor(private ai: Ai) {}\n\n\t/**\n\t * Convert image to text using Optical Character Recognition\n\t * @param {string} path Path to image\n\t * @returns {AbortablePromise<string | null>} Promise of extracted text with abort method\n\t */\n\tocr(path: string): AbortablePromise<string | null> {\n\t\tlet worker: any;\n\t\tconst p = new Promise<string | null>(async res => {\n\t\t\tworker = await createWorker(this.ai.options.ocr || 'eng', 2, {cachePath: this.ai.options.path});\n\t\t\tconst {data} = await worker.recognize(path);\n\t\t\tawait worker.terminate();\n\t\t\tres(data.text.trim() || null);\n\t\t});\n\t\treturn Object.assign(p, {abort: () => worker?.terminate()});\n\t}\n}\n","import * as os from 'node:os';\nimport LLM, {AnthropicConfig, OllamaConfig, OpenAiConfig, LLMRequest} from './llm';\nimport { Audio } from './audio.ts';\nimport {Vision} from './vision.ts';\n\nexport type AbortablePromise<T> = Promise<T> & {\n\tabort: () => any\n};\n\nexport type AiOptions = {\n\t/** Token to pull models from hugging face */\n\thfToken?: string;\n\t/** Path to models */\n\tpath?: string;\n\t/** Whisper ASR model: ggml-tiny.en.bin, ggml-base.en.bin */\n\tasr?: string;\n\t/** Embedding model: all-MiniLM-L6-v2, bge-small-en-v1.5, bge-large-en-v1.5 */\n\tembedder?: string;\n\t/** Large language models, first is default */\n\tllm?: Omit<LLMRequest, 'model'> & {\n\t\tmodels: {[model: string]: AnthropicConfig | OllamaConfig | OpenAiConfig};\n\t}\n\t/** OCR model: eng, eng_best, eng_fast */\n\tocr?: string;\n\t/** Whisper binary */\n\twhisper?: string;\n}\n\nexport class Ai {\n\t/** Audio processing AI */\n\taudio!: Audio;\n\t/** Language processing AI */\n\tlanguage!: LLM;\n\t/** Vision processing AI */\n\tvision!: Vision;\n\n\tconstructor(public readonly options: AiOptions) {\n\t\tif(!options.path) options.path = os.tmpdir();\n\t\tprocess.env.TRANSFORMERS_CACHE = options.path;\n\t\tthis.audio = new Audio(this);\n\t\tthis.language = new LLM(this);\n\t\tthis.vision = new Vision(this);\n\t}\n}\n","import * as cheerio from 'cheerio';\nimport {$Sync} from '@ztimson/node-utils';\nimport {ASet, consoleInterceptor, Http, fn as Fn} from '@ztimson/utils';\nimport * as os from 'node:os';\nimport {Ai} from './ai.ts';\nimport {LLMRequest} from './llm.ts';\n\nconst getShell = () => {\n\tif(os.platform() == 'win32') return 'cmd';\n\treturn $Sync`echo $SHELL`?.split('/').pop() || 'bash';\n}\n\nexport type AiToolArg = {[key: string]: {\n\t/** Argument type */\n\ttype: 'array' | 'boolean' | 'number' | 'object' | 'string',\n\t/** Argument description */\n\tdescription: string,\n\t/** Required argument */\n\trequired?: boolean;\n\t/** Default value */\n\tdefault?: any,\n\t/** Options */\n\tenum?: string[],\n\t/** Minimum value or length */\n\tmin?: number,\n\t/** Maximum value or length */\n\tmax?: number,\n\t/** Match pattern */\n\tpattern?: string,\n\t/** Child arguments */\n\titems?: {[key: string]: AiToolArg}\n}}\n\nexport type AiTool = {\n\t/** Tool ID / Name - Must be snail_case */\n\tname: string,\n\t/** Tool description / prompt */\n\tdescription: string,\n\t/** Tool arguments */\n\targs?: AiToolArg,\n\t/** Callback function */\n\tfn: (args: any, stream: LLMRequest['stream'], ai: Ai) => any | Promise<any>,\n};\n\nexport const CliTool: AiTool = {\n\tname: 'cli',\n\tdescription: 'Use the command line interface, returns any output',\n\targs: {command: {type: 'string', description: 'Command to run', required: true}},\n\tfn: (args: {command: string}) => $Sync`${args.command}`\n}\n\nexport const DateTimeTool: AiTool = {\n\tname: 'get_datetime',\n\tdescription: 'Get current UTC date / time',\n\targs: {},\n\tfn: async () => new Date().toUTCString()\n}\n\nexport const ExecTool: AiTool = {\n\tname: 'exec',\n\tdescription: 'Run code/scripts',\n\targs: {\n\t\tlanguage: {type: 'string', description: `Execution language (CLI: ${getShell()})`, enum: ['cli', 'node', 'python'], required: true},\n\t\tcode: {type: 'string', description: 'Code to execute', required: true}\n\t},\n\tfn: async (args, stream, ai) => {\n\t\ttry {\n\t\t\tswitch(args.language) {\n\t\t\t\tcase 'cli':\n\t\t\t\t\treturn await CliTool.fn({command: args.code}, stream, ai);\n\t\t\t\tcase 'node':\n\t\t\t\t\treturn await JSTool.fn({code: args.code}, stream, ai);\n\t\t\t\tcase 'python':\n\t\t\t\t\treturn await PythonTool.fn({code: args.code}, stream, ai);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unsupported language: ${args.language}`);\n\t\t\t}\n\t\t} catch(err: any) {\n\t\t\treturn {error: err?.message || err.toString()};\n\t\t}\n\t}\n}\n\nexport const FetchTool: AiTool = {\n\tname: 'fetch',\n\tdescription: 'Make HTTP request to URL',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to fetch', required: true},\n\t\tmethod: {type: 'string', description: 'HTTP method to use', enum: ['GET', 'POST', 'PUT', 'DELETE'], default: 'GET'},\n\t\theaders: {type: 'object', description: 'HTTP headers to send', default: {}},\n\t\tbody: {type: 'object', description: 'HTTP body to send'},\n\t},\n\tfn: (args: {\n\t\turl: string;\n\t\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE';\n\t\theaders: {[key: string]: string};\n\t\tbody: any;\n\t}) => new Http({url: args.url, headers: args.headers}).request({method: args.method || 'GET', body: args.body})\n}\n\nexport const JSTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => {\n\t\tconst c = consoleInterceptor(null);\n\t\tconst resp = await Fn<any>({console: c}, args.code, true).catch((err: any) => c.output.error.push(err));\n\t\treturn {...c.output, return: resp, stdout: undefined, stderr: undefined};\n\t}\n}\n\nexport const PythonTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => ({result: $Sync`python -c \"${args.code}\"`})\n}\n\nexport const ReadWebpageTool: AiTool = {\n\tname: 'read_webpage',\n\tdescription: 'Extract clean, structured content from a webpage. Use after web_search to read specific URLs',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to extract content from', required: true},\n\t\tfocus: {type: 'string', description: 'Optional: What aspect to focus on (e.g., \"pricing\", \"features\", \"contact info\")'}\n\t},\n\tfn: async (args: {url: string; focus?: string}) => {\n\t\tconst html = await fetch(args.url, {headers: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"}})\n\t\t\t.then(r => r.text()).catch(err => {throw new Error(`Failed to fetch: ${err.message}`)});\n\n\t\tconst $ = cheerio.load(html);\n\t\t$('script, style, nav, footer, header, aside, iframe, noscript, [role=\"navigation\"], [role=\"banner\"], .ad, .ads, .cookie, .popup').remove();\n\t\tconst metadata = {\n\t\t\ttitle: $('meta[property=\"og:title\"]').attr('content') || $('title').text() || '',\n\t\t\tdescription: $('meta[name=\"description\"]').attr('content') || $('meta[property=\"og:description\"]').attr('content') || '',\n\t\t};\n\n\t\tlet content = '';\n\t\tconst contentSelectors = ['article', 'main', '[role=\"main\"]', '.content', '.post', '.entry', 'body'];\n\t\tfor (const selector of contentSelectors) {\n\t\t\tconst el = $(selector).first();\n\t\t\tif (el.length && el.text().trim().length > 200) {\n\t\t\t\tcontent = el.text();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!content) content = $('body').text();\n\t\tcontent = content.replace(/\\s+/g, ' ').trim().slice(0, 8000);\n\n\t\treturn {url: args.url, title: metadata.title.trim(), description: metadata.description.trim(), content, focus: args.focus};\n\t}\n}\n\nexport const WebSearchTool: AiTool = {\n\tname: 'web_search',\n\tdescription: 'Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool',\n\targs: {\n\t\tquery: {type: 'string', description: 'Search string', required: true},\n\t\tlength: {type: 'string', description: 'Number of results to return', default: 5},\n\t},\n\tfn: async (args: {\n\t\tquery: string;\n\t\tlength: number;\n\t}) => {\n\t\tconst html = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(args.query)}`, {\n\t\t\theaders: {\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\", \"Accept-Language\": \"en-US,en;q=0.9\"}\n\t\t}).then(resp => resp.text());\n\t\tlet match, regex = /<a .*?href=\"(.+?)\".+?<\\/a>/g;\n\t\tconst results = new ASet<string>();\n\t\twhile((match = regex.exec(html)) !== null) {\n\t\t\tlet url = /uddg=(.+)&amp?/.exec(decodeURIComponent(match[1]))?.[1];\n\t\t\tif(url) url = decodeURIComponent(url);\n\t\t\tif(url) results.add(url);\n\t\t\tif(results.size >= (args.length || 5)) break;\n\t\t}\n\t\treturn results;\n\t}\n}\n"],"names":["LLMProvider","Anthropic","ai","apiToken","model","anthropic","history","timestamp","messages","h","textContent","c","m","i","message","options","controller","res","tools","requestParams","t","objectMap","key","value","resp","isFirstMessage","err","chunk","text","last","JSONAttemptParse","toolCalls","results","toolCall","tool","findByProp","result","JSONSanitize","OpenAi","host","token","openAI","clean","tc","record","h2","rest","rej","deltaTC","existing","args","LLM","config","abort","search","query","subject","limit","o","q","score","a","b","relevant","e","newMem","compressed","codeBlock","max","min","keep","tokens","system","recent","process","summary","d","v1","v2","dotProduct","normA","normB","denominator","target","maxTokens","overlapTokens","objString","obj","path","p","l","chunks","j","next","opts","aborted","embed","resolve","reject","join","dirname","fileURLToPath","proc","spawn","output","data","code","embedding","searchTerms","vector","dimensions","char","index","v","similarities","refVector","acc","s","schema","Audio","timestampData","llm","cadence","countSyllables","word","matches","count","skip","prevWord","nextWord","capital","length","expected","speakers","speakerMap","speakerCount","seg","punctuatedText","sentences","words","w","sentencesWithSpeakers","sentence","sentenceWords","speakerWordCount","sw","wordTime","speaker","spkNum","bestSpeaker","maxWords","merged","item","transcript","names","name","file","fs","checkPython","cmd","p3","binary","tmp","mkdtempSync","tmpdir","execSync","Path","timestamps","diarization","response","ts","arr","buffer","Vision","worker","createWorker","Ai","os","getShell","$Sync","CliTool","DateTimeTool","ExecTool","stream","JSTool","PythonTool","FetchTool","Http","consoleInterceptor","Fn","ReadWebpageTool","html","r","$","cheerio","metadata","content","contentSelectors","selector","el","WebSearchTool","match","regex","ASet","url"],"mappings":";;;;;;;;;;;;;;;AAGO,MAAeA,EAAY;AAElC;ACCO,MAAMC,UAAkBD,EAAY;AAAA,EAG1C,YAA4BE,GAAwBC,GAAyBC,GAAe;AAC3F,UAAA,GAD2B,KAAA,KAAAF,GAAwB,KAAA,WAAAC,GAAyB,KAAA,QAAAC,GAE5E,KAAK,SAAS,IAAIC,EAAU,EAAC,QAAQF,GAAS;AAAA,EAC/C;AAAA,EALA;AAAA,EAOQ,WAAWG,GAA8B;AAChD,UAAMC,IAAY,KAAK,IAAA,GACjBC,IAAyB,CAAA;AAC/B,aAAQC,KAAKH;AACZ,UAAG,OAAOG,EAAE,WAAW;AACtB,QAAAD,EAAS,KAAU,EAAC,WAAAD,GAAW,GAAGE,GAAE;AAAA,WAC9B;AACN,cAAMC,IAAcD,EAAE,SAAS,OAAO,CAACE,MAAWA,EAAE,QAAQ,MAAM,EAAE,IAAI,CAACA,MAAWA,EAAE,IAAI,EAAE,KAAK;AAAA;AAAA,CAAM;AACvG,QAAGD,KAAaF,EAAS,KAAK,EAAC,WAAAD,GAAW,MAAME,EAAE,MAAM,SAASC,GAAY,GAC7ED,EAAE,QAAQ,QAAQ,CAACE,MAAW;AAC7B,cAAGA,EAAE,QAAQ;AACZ,YAAAH,EAAS,KAAK,EAAC,WAAAD,GAAW,MAAM,QAAQ,IAAII,EAAE,IAAI,MAAMA,EAAE,MAAM,MAAMA,EAAE,OAAO,SAAS,QAAU;AAAA,mBACzFA,EAAE,QAAQ,eAAe;AAClC,kBAAMC,IAASJ,EAAS,SAAS,CAAAI,MAAWA,EAAG,MAAMD,EAAE,WAAW;AAClE,YAAGC,MAAGA,EAAED,EAAE,WAAW,UAAU,SAAS,IAAIA,EAAE;AAAA,UAC/C;AAAA,QACD,CAAC;AAAA,MACF;AAED,WAAOH;AAAA,EACR;AAAA,EAEQ,aAAaF,GAA8B;AAClD,aAAQO,IAAI,GAAGA,IAAIP,EAAQ,QAAQO;AAClC,UAAGP,EAAQO,CAAC,EAAE,QAAQ,QAAQ;AAC7B,cAAMJ,IAASH,EAAQO,CAAC;AACxB,QAAAP,EAAQ;AAAA,UAAOO;AAAA,UAAG;AAAA,UACjB,EAAC,MAAM,aAAa,SAAS,CAAC,EAAC,MAAM,YAAY,IAAIJ,EAAE,IAAI,MAAMA,EAAE,MAAM,OAAOA,EAAE,KAAA,CAAK,EAAA;AAAA,UACvF,EAAC,MAAM,QAAQ,SAAS,CAAC,EAAC,MAAM,eAAe,aAAaA,EAAE,IAAI,UAAU,CAAC,CAACA,EAAE,OAAO,SAAUA,EAAE,SAASA,EAAE,SAAQ,EAAA;AAAA,QAAC,GAExHI;AAAA,MACD;AAED,WAAOP,EAAQ,IAAI,CAAC,EAAC,WAAAC,GAAW,GAAGE,EAAA,MAAOA,CAAC;AAAA,EAC5C;AAAA,EAEA,IAAIK,GAAiBC,IAAsB,IAA8B;AACxE,UAAMC,IAAa,IAAI,gBAAA;AACvB,WAAO,OAAO,OAAO,IAAI,QAAa,OAAOC,MAAQ;AACpD,UAAIX,IAAU,KAAK,aAAa,CAAC,GAAGS,EAAQ,WAAW,IAAI,EAAC,MAAM,QAAQ,SAASD,GAAS,WAAW,KAAK,IAAA,EAAI,CAAE,CAAC;AACnH,YAAMI,IAAQH,EAAQ,SAAS,KAAK,GAAG,QAAQ,KAAK,SAAS,CAAA,GACvDI,IAAqB;AAAA,QAC1B,OAAOJ,EAAQ,SAAS,KAAK;AAAA,QAC7B,YAAYA,EAAQ,cAAc,KAAK,GAAG,QAAQ,KAAK,cAAc;AAAA,QACrE,QAAQA,EAAQ,UAAU,KAAK,GAAG,QAAQ,KAAK,UAAU;AAAA,QACzD,aAAaA,EAAQ,eAAe,KAAK,GAAG,QAAQ,KAAK,eAAe;AAAA,QACxE,OAAOG,EAAM,IAAI,CAAAE,OAAM;AAAA,UACtB,MAAMA,EAAE;AAAA,UACR,aAAaA,EAAE;AAAA,UACf,cAAc;AAAA,YACb,MAAM;AAAA,YACN,YAAYA,EAAE,OAAOC,EAAUD,EAAE,MAAM,CAACE,GAAKC,OAAW,EAAC,GAAGA,GAAO,UAAU,OAAA,EAAW,IAAI,CAAA;AAAA,YAC5F,UAAUH,EAAE,OAAO,OAAO,QAAQA,EAAE,IAAI,EAAE,OAAO,CAAAA,MAAKA,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAAA,MAAKA,EAAE,CAAC,CAAC,IAAI,CAAA;AAAA,UAAC;AAAA,UAExF,IAAI;AAAA,QAAA,EACH;AAAA,QACF,UAAUd;AAAA,QACV,QAAQ,CAAC,CAACS,EAAQ;AAAA,MAAA;AAGnB,UAAIS,GAAWC,IAAiB;AAChC,SAAG;AAOF,YANAD,IAAO,MAAM,KAAK,OAAO,SAAS,OAAOL,CAAa,EAAE,MAAM,CAAAO,MAAO;AACpE,gBAAAA,EAAI,WAAW;AAAA;AAAA;AAAA,EAAkB,KAAK,UAAUpB,GAAS,MAAM,CAAC,CAAC,IAC3DoB;AAAA,QACP,CAAC,GAGEX,EAAQ,QAAQ;AAClB,UAAIU,IACCA,IAAiB,KADFV,EAAQ,OAAO,EAAC,MAAM;AAAA;AAAA,GAAO,GAEjDS,EAAK,UAAU,CAAA;AACf,2BAAiBG,KAASH,GAAM;AAC/B,gBAAGR,EAAW,OAAO,QAAS;AAC9B,gBAAGW,EAAM,SAAS;AACjB,cAAGA,EAAM,cAAc,SAAS,SAC/BH,EAAK,QAAQ,KAAK,EAAC,MAAM,QAAQ,MAAM,IAAG,IACjCG,EAAM,cAAc,SAAS,cACtCH,EAAK,QAAQ,KAAK,EAAC,MAAM,YAAY,IAAIG,EAAM,cAAc,IAAI,MAAMA,EAAM,cAAc,MAAM,OAAY,IAAG;AAAA,qBAExGA,EAAM,SAAS;AACxB,kBAAGA,EAAM,MAAM,SAAS,cAAc;AACrC,sBAAMC,IAAOD,EAAM,MAAM;AACzB,gBAAAH,EAAK,QAAQ,GAAG,EAAE,EAAE,QAAQI,GAC5Bb,EAAQ,OAAO,EAAC,MAAAa,GAAK;AAAA,cACtB,MAAA,CAAUD,EAAM,MAAM,SAAS,uBAC9BH,EAAK,QAAQ,GAAG,EAAE,EAAE,SAASG,EAAM,MAAM;AAAA,qBAEjCA,EAAM,SAAS,sBAAsB;AAC9C,oBAAME,IAAOL,EAAK,QAAQ,GAAG,EAAE;AAC/B,cAAGK,EAAK,SAAS,SAAMA,EAAK,QAAQA,EAAK,QAAQC,EAAiBD,EAAK,OAAO,CAAA,CAAE,IAAI,CAAA;AAAA,YACrF,WAAUF,EAAM,SAAS;AACxB;AAAA,UAEF;AAAA,QACD;AAGA,cAAMI,IAAYP,EAAK,QAAQ,OAAO,CAACb,MAAWA,EAAE,SAAS,UAAU;AACvE,YAAGoB,EAAU,UAAU,CAACf,EAAW,OAAO,SAAS;AAClD,UAAAV,EAAQ,KAAK,EAAC,MAAM,aAAa,SAASkB,EAAK,SAAQ;AACvD,gBAAMQ,IAAU,MAAM,QAAQ,IAAID,EAAU,IAAI,OAAOE,MAAkB;AACxE,kBAAMC,IAAOhB,EAAM,KAAKiB,EAAW,QAAQF,EAAS,IAAI,CAAC;AAEzD,gBADGlB,EAAQ,UAAQA,EAAQ,OAAO,EAAC,MAAMkB,EAAS,MAAK,GACpD,CAACC,EAAM,QAAO,EAAC,aAAaD,EAAS,IAAI,UAAU,IAAM,SAAS,iBAAA;AACrE,gBAAI;AACH,oBAAMG,IAAS,MAAMF,EAAK,GAAGD,EAAS,OAAOlB,GAAS,QAAQ,KAAK,EAAE;AACrE,qBAAO,EAAC,MAAM,eAAe,aAAakB,EAAS,IAAI,SAASI,EAAaD,CAAM,EAAA;AAAA,YACpF,SAASV,GAAU;AAClB,qBAAO,EAAC,MAAM,eAAe,aAAaO,EAAS,IAAI,UAAU,IAAM,SAASP,GAAK,WAAWA,GAAK,SAAA,KAAc,UAAA;AAAA,YACpH;AAAA,UACD,CAAC,CAAC;AACF,UAAApB,EAAQ,KAAK,EAAC,MAAM,QAAQ,SAAS0B,GAAQ,GAC7Cb,EAAc,WAAWb;AAAA,QAC1B;AAAA,MACD,SAAS,CAACU,EAAW,OAAO,WAAWQ,EAAK,QAAQ,KAAK,CAACb,MAAWA,EAAE,SAAS,UAAU;AAC1F,MAAAL,EAAQ,KAAK,EAAC,MAAM,aAAa,SAASkB,EAAK,QAAQ,OAAO,CAACb,MAAWA,EAAE,QAAQ,MAAM,EAAE,IAAI,CAACA,MAAWA,EAAE,IAAI,EAAE,KAAK;AAAA;AAAA,CAAM,GAAE,GACjIL,IAAU,KAAK,WAAWA,CAAO,GAE9BS,EAAQ,UAAQA,EAAQ,OAAO,EAAC,MAAM,IAAK,GAC3CA,EAAQ,WAASA,EAAQ,QAAQ,OAAO,GAAGA,EAAQ,QAAQ,QAAQ,GAAGT,CAAO,GAChFW,EAAIX,EAAQ,GAAG,EAAE,GAAG,OAAO;AAAA,IAC5B,CAAC,GAAG,EAAC,OAAO,MAAMU,EAAW,MAAA,GAAQ;AAAA,EACtC;AACD;ACpIO,MAAMsB,UAAetC,EAAY;AAAA,EAGvC,YAA4BE,GAAwBqC,GAAqCC,GAAsBpC,GAAe;AAC7H,UAAA,GAD2B,KAAA,KAAAF,GAAwB,KAAA,OAAAqC,GAAqC,KAAA,QAAAC,GAAsB,KAAA,QAAApC,GAE9G,KAAK,SAAS,IAAIqC,EAAOC,EAAM;AAAA,MAC9B,SAASH;AAAA,MACT,QAAQC,KAASD,IAAO,YAAY;AAAA,IAAA,CACpC,CAAC;AAAA,EACH;AAAA,EARA;AAAA,EAUQ,WAAWjC,GAA8B;AAChD,aAAQO,IAAI,GAAGA,IAAIP,EAAQ,QAAQO,KAAK;AACvC,YAAMJ,IAAIH,EAAQO,CAAC;AACnB,UAAGJ,EAAE,SAAS,eAAeA,EAAE,YAAY;AAC1C,cAAMS,IAAQT,EAAE,WAAW,IAAI,CAACkC,OAAa;AAAA,UAC5C,MAAM;AAAA,UACN,IAAIA,EAAG;AAAA,UACP,MAAMA,EAAG,SAAS;AAAA,UAClB,MAAMb,EAAiBa,EAAG,SAAS,WAAW,CAAA,CAAE;AAAA,UAChD,WAAWlC,EAAE;AAAA,QAAA,EACZ;AACF,QAAAH,EAAQ,OAAOO,GAAG,GAAG,GAAGK,CAAK,GAC7BL,KAAKK,EAAM,SAAS;AAAA,MACrB,WAAUT,EAAE,SAAS,UAAUA,EAAE,SAAS;AACzC,cAAMmC,IAAStC,EAAQ,KAAK,OAAMG,EAAE,gBAAgBoC,EAAG,EAAE;AACzD,QAAGD,MACCnC,EAAE,QAAQ,SAAS,UAAU,IAAGmC,EAAO,QAAQnC,EAAE,UAC/CmC,EAAO,UAAUnC,EAAE,UAEzBH,EAAQ,OAAOO,GAAG,CAAC,GACnBA;AAAA,MACD;AACA,MAAIP,EAAQO,CAAC,GAAG,gBAAmBA,CAAC,EAAE,YAAY,KAAK,IAAA;AAAA,IACxD;AACA,WAAOP;AAAA,EACR;AAAA,EAEQ,aAAaA,GAA8B;AAClD,WAAOA,EAAQ,OAAO,CAAC8B,GAAQ3B,MAAM;AACpC,UAAGA,EAAE,SAAS;AACb,QAAA2B,EAAO,KAAK;AAAA,UACX,MAAM;AAAA,UACN,SAAS;AAAA,UACT,YAAY,CAAC,EAAE,IAAI3B,EAAE,IAAI,MAAM,YAAY,UAAU,EAAE,MAAMA,EAAE,MAAM,WAAW,KAAK,UAAUA,EAAE,IAAI,EAAA,GAAK;AAAA,UAC1G,SAAS;AAAA,UACT,aAAa,CAAA;AAAA,QAAC,GACZ;AAAA,UACF,MAAM;AAAA,UACN,cAAcA,EAAE;AAAA,UAChB,SAASA,EAAE,SAASA,EAAE;AAAA,QAAA,CACtB;AAAA,WACK;AACN,cAAM,EAAC,WAAAF,GAAW,GAAGuC,EAAA,IAAQrC;AAC7B,QAAA2B,EAAO,KAAKU,CAAI;AAAA,MACjB;AACA,aAAOV;AAAA,IACR,GAAG,CAAA,CAAW;AAAA,EACf;AAAA,EAEA,IAAItB,GAAiBC,IAAsB,IAA8B;AACxE,UAAMC,IAAa,IAAI,gBAAA;AACvB,WAAO,OAAO,OAAO,IAAI,QAAa,OAAOC,GAAK8B,MAAQ;AACzD,MAAGhC,EAAQ,WACPA,EAAQ,UAAU,CAAC,GAAG,QAAQ,WAAUA,EAAQ,SAAS,OAAO,GAAG,GAAG,EAAC,MAAM,UAAU,SAASA,EAAQ,QAAQ,WAAW,KAAK,IAAA,GAAM,IACpIA,EAAQ,QAAQ,CAAC,EAAE,UAAUA,EAAQ;AAE3C,UAAIT,IAAU,KAAK,aAAa,CAAC,GAAGS,EAAQ,WAAW,IAAI,EAAC,MAAM,QAAQ,SAASD,GAAS,WAAW,KAAK,IAAA,EAAI,CAAE,CAAC;AACnH,YAAMI,IAAQH,EAAQ,SAAS,KAAK,GAAG,QAAQ,KAAK,SAAS,CAAA,GACvDI,IAAqB;AAAA,QAC1B,OAAOJ,EAAQ,SAAS,KAAK;AAAA,QAC7B,UAAUT;AAAA,QACV,QAAQ,CAAC,CAACS,EAAQ;AAAA,QAClB,YAAYA,EAAQ,cAAc,KAAK,GAAG,QAAQ,KAAK,cAAc;AAAA,QACrE,aAAaA,EAAQ,eAAe,KAAK,GAAG,QAAQ,KAAK,eAAe;AAAA,QACxE,OAAOG,EAAM,IAAI,CAAAE,OAAM;AAAA,UACtB,MAAM;AAAA,UACN,UAAU;AAAA,YACT,MAAMA,EAAE;AAAA,YACR,aAAaA,EAAE;AAAA,YACf,YAAY;AAAA,cACX,MAAM;AAAA,cACN,YAAYA,EAAE,OAAOC,EAAUD,EAAE,MAAM,CAACE,GAAKC,OAAW,EAAC,GAAGA,GAAO,UAAU,OAAA,EAAW,IAAI,CAAA;AAAA,cAC5F,UAAUH,EAAE,OAAO,OAAO,QAAQA,EAAE,IAAI,EAAE,OAAO,CAAAA,MAAKA,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAAA,MAAKA,EAAE,CAAC,CAAC,IAAI,CAAA;AAAA,YAAC;AAAA,UACxF;AAAA,QACD,EACC;AAAA,MAAA;AAGH,UAAII,GAAWC,IAAiB;AAChC,SAAG;AAMF,YALAD,IAAO,MAAM,KAAK,OAAO,KAAK,YAAY,OAAOL,CAAa,EAAE,MAAM,CAAAO,MAAO;AAC5E,gBAAAA,EAAI,WAAW;AAAA;AAAA;AAAA,EAAkB,KAAK,UAAUpB,GAAS,MAAM,CAAC,CAAC,IAC3DoB;AAAA,QACP,CAAC,GAEEX,EAAQ,QAAQ;AAClB,UAAIU,IACCA,IAAiB,KADFV,EAAQ,OAAO,EAAC,MAAM;AAAA;AAAA,GAAO,GAEjDS,EAAK,UAAU,CAAC,EAAC,SAAS,EAAC,MAAM,aAAa,SAAS,IAAI,YAAY,CAAA,EAAC,GAAG;AAC3E,2BAAiBG,KAASH,GAAM;AAC/B,gBAAGR,EAAW,OAAO,QAAS;AAM9B,gBALGW,EAAM,QAAQ,CAAC,EAAE,MAAM,YACzBH,EAAK,QAAQ,CAAC,EAAE,QAAQ,WAAWG,EAAM,QAAQ,CAAC,EAAE,MAAM,SAC1DZ,EAAQ,OAAO,EAAC,MAAMY,EAAM,QAAQ,CAAC,EAAE,MAAM,SAAQ,IAGnDA,EAAM,QAAQ,CAAC,EAAE,MAAM;AACzB,yBAAUqB,KAAWrB,EAAM,QAAQ,CAAC,EAAE,MAAM,YAAY;AACvD,sBAAMsB,IAAWzB,EAAK,QAAQ,CAAC,EAAE,QAAQ,WAAW,KAAK,CAAAmB,MAAMA,EAAG,UAAUK,EAAQ,KAAK;AACzF,gBAAGC,KACCD,EAAQ,OAAIC,EAAS,KAAKD,EAAQ,KAClCA,EAAQ,SAAMC,EAAS,OAAOD,EAAQ,OACtCA,EAAQ,aACNC,EAAS,aAAUA,EAAS,WAAW,CAAA,IACxCD,EAAQ,SAAS,WAAe,SAAS,OAAOA,EAAQ,SAAS,OACjEA,EAAQ,SAAS,cAAWC,EAAS,SAAS,aAAaA,EAAS,SAAS,aAAa,MAAMD,EAAQ,SAAS,eAGrHxB,EAAK,QAAQ,CAAC,EAAE,QAAQ,WAAW,KAAK;AAAA,kBACvC,OAAOwB,EAAQ;AAAA,kBACf,IAAIA,EAAQ,MAAM;AAAA,kBAClB,MAAMA,EAAQ,QAAQ;AAAA,kBACtB,UAAU;AAAA,oBACT,MAAMA,EAAQ,UAAU,QAAQ;AAAA,oBAChC,WAAWA,EAAQ,UAAU,aAAa;AAAA,kBAAA;AAAA,gBAC3C,CACA;AAAA,cAEH;AAAA,UAEF;AAAA,QACD;AAEA,cAAMjB,IAAYP,EAAK,QAAQ,CAAC,EAAE,QAAQ,cAAc,CAAA;AACxD,YAAGO,EAAU,UAAU,CAACf,EAAW,OAAO,SAAS;AAClD,UAAAV,EAAQ,KAAKkB,EAAK,QAAQ,CAAC,EAAE,OAAO;AACpC,gBAAMQ,IAAU,MAAM,QAAQ,IAAID,EAAU,IAAI,OAAOE,MAAkB;AACxE,kBAAMC,IAAOhB,GAAO,KAAKiB,EAAW,QAAQF,EAAS,SAAS,IAAI,CAAC;AAEnE,gBADGlB,EAAQ,UAAQA,EAAQ,OAAO,EAAC,MAAMkB,EAAS,SAAS,MAAK,GAC7D,CAACC,EAAM,QAAO,EAAC,MAAM,QAAQ,cAAcD,EAAS,IAAI,SAAS,8BAAA;AACpE,gBAAI;AACH,oBAAMiB,IAAOpB,EAAiBG,EAAS,SAAS,WAAW,CAAA,CAAE,GACvDG,IAAS,MAAMF,EAAK,GAAGgB,GAAMnC,EAAQ,QAAQ,KAAK,EAAE;AAC1D,qBAAO,EAAC,MAAM,QAAQ,cAAckB,EAAS,IAAI,SAASI,EAAaD,CAAM,EAAA;AAAA,YAC9E,SAASV,GAAU;AAClB,qBAAO,EAAC,MAAM,QAAQ,cAAcO,EAAS,IAAI,SAASI,EAAa,EAAC,OAAOX,GAAK,WAAWA,GAAK,cAAc,UAAA,CAAU,EAAA;AAAA,YAC7H;AAAA,UACD,CAAC,CAAC;AACF,UAAApB,EAAQ,KAAK,GAAG0B,CAAO,GACvBb,EAAc,WAAWb;AAAA,QAC1B;AAAA,MACD,SAAS,CAACU,EAAW,OAAO,WAAWQ,EAAK,UAAU,CAAC,GAAG,SAAS,YAAY;AAC/E,MAAAlB,EAAQ,KAAK,EAAC,MAAM,aAAa,SAASkB,EAAK,QAAQ,CAAC,EAAE,QAAQ,WAAW,GAAA,CAAG,GAChFlB,IAAU,KAAK,WAAWA,CAAO,GAE9BS,EAAQ,UAAQA,EAAQ,OAAO,EAAC,MAAM,IAAK,GAC3CA,EAAQ,WAASA,EAAQ,QAAQ,OAAO,GAAGA,EAAQ,QAAQ,QAAQ,GAAGT,CAAO,GAChFW,EAAIX,EAAQ,GAAG,EAAE,GAAG,OAAO;AAAA,IAC5B,CAAC,GAAG,EAAC,OAAO,MAAMU,EAAW,MAAA,GAAQ;AAAA,EACtC;AACD;AC7FA,MAAMmC,EAAI;AAAA,EAIT,YAA4BjD,GAAQ;AACnC,IAD2B,KAAA,KAAAA,GACvBA,EAAG,QAAQ,KAAK,UACpB,OAAO,QAAQA,EAAG,QAAQ,IAAI,MAAM,EAAE,QAAQ,CAAC,CAACE,GAAOgD,CAAM,MAAM;AAClE,MAAI,KAAK,iBAAc,KAAK,eAAehD,IACxCgD,EAAO,SAAS,cAAa,KAAK,OAAOhD,CAAK,IAAI,IAAIH,EAAU,KAAK,IAAImD,EAAO,OAAOhD,CAAK,IACvFgD,EAAO,SAAS,WAAU,KAAK,OAAOhD,CAAK,IAAI,IAAIkC,EAAO,KAAK,IAAIc,EAAO,MAAM,cAAchD,CAAK,IACnGgD,EAAO,SAAS,aAAU,KAAK,OAAOhD,CAAK,IAAI,IAAIkC,EAAO,KAAK,IAAIc,EAAO,QAAQ,MAAMA,EAAO,OAAOhD,CAAK;AAAA,IACpH,CAAC;AAAA,EACF;AAAA,EAXA;AAAA,EACA,SAAyC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBzC,IAAIU,GAAiBC,IAAsB,IAA8B;AACxE,IAAAA,IAAe;AAAA,MACd,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,GAAG,KAAK,GAAG,QAAQ;AAAA,MACnB,QAAQ;AAAA,MACR,SAAS,CAAA;AAAA,MACT,GAAGA;AAAA,IAAA;AAEJ,UAAMH,IAAIG,EAAQ,SAAS,KAAK;AAChC,QAAG,CAAC,KAAK,OAAOH,CAAC,SAAS,IAAI,MAAM,yBAAyBA,CAAC,EAAE;AAChE,QAAIyC,IAAQ,MAAM;AAAA,IAAC;AACnB,WAAO,OAAO,OAAO,IAAI,QAAgB,OAAMpC,MAAO;AAGrD,UAFIF,EAAQ,YAASA,EAAQ,UAAU,CAAA,IAEpCA,EAAQ,QAAQ;AAClB,cAAMuC,IAAS,OAAOC,GAAuBC,GAAyBC,IAAQ,OAAO;AACpF,gBAAM,CAACC,GAAGC,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,YAChCH,IAAU,KAAK,UAAUA,CAAO,IAAI,QAAQ,QAAQ,IAAI;AAAA,YACxDD,IAAQ,KAAK,UAAUA,CAAK,IAAI,QAAQ,QAAQ,IAAI;AAAA,UAAA,CACpD;AACD,kBAAQxC,EAAQ,UAAU,CAAA,GAAI,IAAI,CAAAH,MAAK;AACtC,kBAAMgD,KAASF,IAAI,KAAK,iBAAiB9C,EAAE,WAAW,CAAC,GAAG8C,EAAE,CAAC,EAAE,SAAS,IAAI,MACxEC,IAAI,KAAK,iBAAiB/C,EAAE,WAAW,CAAC,GAAG+C,EAAE,CAAC,EAAE,SAAS,IAAI;AACjE,mBAAO,EAAC,GAAG/C,GAAG,OAAAgD,EAAA;AAAA,UACf,CAAC,EAAE,SAAS,CAACC,GAAQC,MAAWD,EAAE,QAAQC,EAAE,KAAK,EAAE,MAAM,GAAGL,CAAK;AAAA,QAClE;AAEA,QAAA1C,EAAQ,UAAU;AAAA;AAAA;AAClB,cAAMgD,IAAW,MAAMT,EAAOxC,CAAO;AACrC,QAAGiD,EAAS,UAAQhD,EAAQ,QAAQ,KAAK,EAAC,MAAM,QAAQ,MAAM,UAAU,IAAI,iBAAiB,KAAK,OAAA,EAAS,YAAY,MAAM,CAAA,GAAI,SAAS;AAAA,IAA2BgD,EAAS,IAAI,CAAAnD,MAAK,GAAGA,EAAE,KAAK,KAAKA,EAAE,IAAI,EAAE,EAAE,KAAK;AAAA,CAAI,GAAE,GAC3NG,EAAQ,QAAQ,CAAC;AAAA,UAChB,MAAM;AAAA,UACN,aAAa;AAAA,UACb,MAAM;AAAA,YACL,SAAS,EAAC,MAAM,UAAU,aAAa,kFAAA;AAAA,YACvC,OAAO,EAAC,MAAM,UAAU,aAAa,+EAAA;AAAA,YACrC,MAAM,EAAC,MAAM,UAAU,aAAa,0BAAA;AAAA,UAAyB;AAAA,UAE9D,IAAI,CAACmC,MAAS;AACb,gBAAG,CAACA,EAAK,WAAW,CAACA,EAAK,MAAO,OAAM,IAAI,MAAM,gDAAgD;AACjG,mBAAOI,EAAOJ,EAAK,OAAOA,EAAK,SAASA,EAAK,IAAI;AAAA,UAClD;AAAA,QAAA,GACE;AAAA,UACF,MAAM;AAAA,UACN,aAAa;AAAA,UACb,MAAM;AAAA,YACL,OAAO,EAAC,MAAM,UAAU,aAAa,oCAAA;AAAA,YACrC,MAAM,EAAC,MAAM,UAAU,aAAa,8BAAA;AAAA,UAA6B;AAAA,UAElE,IAAI,OAAOA,MAAS;AACnB,gBAAG,CAACnC,EAAQ,OAAQ;AACpB,kBAAMiD,IAAI,MAAM,QAAQ,IAAI;AAAA,cAC3B,KAAK,UAAUd,EAAK,KAAK;AAAA,cACzB,KAAK,UAAU,GAAGA,EAAK,KAAK,KAAKA,EAAK,IAAI,EAAE;AAAA,YAAA,CAC5C,GACKe,IAAS,EAAC,OAAOf,EAAK,OAAO,MAAMA,EAAK,MAAM,YAAiB,CAACc,EAAE,CAAC,EAAE,CAAC,EAAE,WAAWA,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAA;AAC1G,mBAAAjD,EAAQ,OAAO,OAAO,GAAGA,EAAQ,OAAO,QACvC,GAAGA,EAAQ,OAAO,OAAO,CAAAH,MACjB,EAAE,KAAK,iBAAiBqD,EAAO,WAAW,CAAC,GAAGrD,EAAE,WAAW,CAAC,CAAC,KAAK,OAAO,KAAK,iBAAiBqD,EAAO,WAAW,CAAC,GAAGrD,EAAE,WAAW,CAAC,CAAC,KAAK,IAChJ,GACDqD,CACA,GACM;AAAA,UACR;AAAA,QAAA,GACE,GAAGlD,EAAQ,SAAS,EAAE;AAAA,MAC1B;AAGA,YAAMS,IAAO,MAAM,KAAK,OAAOZ,CAAC,EAAE,IAAIE,GAASC,CAAO;AAMtD,UAHGA,EAAQ,UAAQA,EAAQ,QAAQ,OAAO,GAAGA,EAAQ,QAAQ,QAAQ,GAAGA,EAAQ,QAAQ,OAAO,CAAAN,MAAKA,EAAE,QAAQ,UAAWA,EAAE,QAAQ,YAAYA,EAAE,QAAQ,UAAW,CAAC,GAGlKM,EAAQ,UAAU;AACpB,cAAMmD,IAAa,MAAM,KAAK,GAAG,SAAS,gBAAgBnD,EAAQ,SAASA,EAAQ,SAAS,KAAKA,EAAQ,SAAS,KAAKA,CAAO;AAC9H,QAAAA,EAAQ,QAAQ,OAAO,GAAGA,EAAQ,QAAQ,QAAQ,GAAGmD,CAAU;AAAA,MAChE;AAEA,aAAOjD,EAAIO,CAAI;AAAA,IAChB,CAAC,GAAG,EAAC,OAAA6B,GAAM;AAAA,EACZ;AAAA,EAEA,MAAM,KAAKvC,GAAiBC,GAAoC;AAC/D,UAAMS,IAAO,MAAM,KAAK,IAAIV,GAAS,EAAC,GAAGC,GAAS,QAAQ;AAAA,MACzDA,GAAS;AAAA,MACT;AAAA,IAAA,EACC,OAAO,CAAAK,MAAK,CAAC,CAACA,CAAC,EAAE,KAAM;AAAA,CAAK,GAAE,GAC1B+C,IAAY,6BAA6B,KAAK3C,CAAI;AACxD,WAAO2C,IAAYA,EAAU,CAAC,EAAE,SAAS;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,gBAAgB7D,GAAuB8D,GAAaC,GAAatD,GAA6C;AACnH,QAAG,KAAK,eAAeT,CAAO,IAAI8D,EAAK,QAAO9D;AAC9C,QAAIgE,IAAO,GAAGC,IAAS;AACvB,aAAQ3D,KAAKN,EAAQ;AAEpB,UADAiE,KAAU,KAAK,eAAe3D,EAAE,OAAO,GACpC2D,IAASF,EAAK,CAAAC;AAAA,UACZ;AAEN,QAAGhE,EAAQ,UAAUgE,EAAM,QAAOhE;AAClC,UAAMkE,IAASlE,EAAQ,CAAC,EAAE,QAAQ,WAAWA,EAAQ,CAAC,IAAI,MACzDmE,IAASH,KAAQ,IAAI,CAAA,IAAKhE,EAAQ,MAAM,CAACgE,CAAI,GAC7CI,KAAWJ,KAAQ,IAAIhE,IAAUA,EAAQ,MAAM,GAAG,CAACgE,CAAI,GAAG,OAAO,CAAA7D,MAAKA,EAAE,SAAS,eAAeA,EAAE,SAAS,MAAM,GAE5GkE,IAAe,MAAM,KAAK,UAAUD,EAAQ,IAAI,OAAK,IAAI9D,EAAE,IAAI,MAAMA,EAAE,OAAO,EAAE,EAAE,KAAK;AAAA;AAAA,CAAM,GAAG,KAAKG,CAAO,GAC5G6D,IAAI,KAAK,IAAA,GACTnE,IAAI,CAAC,EAAC,MAAW,QAAQ,MAAM,WAAW,IAAI,aAAamE,GAAG,MAAM,CAAA,GAAI,SAAS,yBAAyBD,GAAS,OAAO,IAAI,WAAWC,KAAI,GAAGH,CAAM;AAC5J,WAAGD,KAAQ/D,EAAE,OAAO,GAAG,GAAG+D,CAAM,GACzB/D;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiBoE,GAAcC,GAAsB;AACpD,QAAID,EAAG,WAAWC,EAAG,OAAQ,OAAM,IAAI,MAAM,6BAA6B;AAC1E,QAAIC,IAAa,GAAGC,IAAQ,GAAGC,IAAQ;AACvC,aAASpE,IAAI,GAAGA,IAAIgE,EAAG,QAAQhE;AAC9B,MAAAkE,KAAcF,EAAGhE,CAAC,IAAIiE,EAAGjE,CAAC,GAC1BmE,KAASH,EAAGhE,CAAC,IAAIgE,EAAGhE,CAAC,GACrBoE,KAASH,EAAGjE,CAAC,IAAIiE,EAAGjE,CAAC;AAEtB,UAAMqE,IAAc,KAAK,KAAKF,CAAK,IAAI,KAAK,KAAKC,CAAK;AACtD,WAAOC,MAAgB,IAAI,IAAIH,IAAaG;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAMC,GAAyBC,IAAY,KAAKC,IAAgB,IAAc;AAC7E,UAAMC,IAAY,CAACC,GAAUC,IAAO,OAC/BD,IACG,OAAO,QAAQA,CAAG,EAAE,QAAQ,CAAC,CAACjE,GAAKC,CAAK,MAAM;AACpD,YAAMkE,IAAID,IAAO,GAAGA,CAAI,GAAG,MAAM,CAAClE,CAAG,IAAI,IAAIA,CAAG,KAAK,IAAIA,CAAG,GAAG,KAAKA;AACpE,aAAG,OAAOC,KAAU,YAAY,CAAC,MAAM,QAAQA,CAAK,IAAU+D,EAAU/D,GAAOkE,CAAC,IACzE,GAAGA,CAAC,KAAK,MAAM,QAAQlE,CAAK,IAAIA,EAAM,KAAK,IAAI,IAAIA,CAAK;AAAA,IAChE,CAAC,IALe,CAAA,GAQXgD,KADQ,OAAOY,KAAW,WAAWG,EAAUH,CAAM,IAAIA,EAAO,WAAW,MAAM;AAAA,CAAI,GACtE,QAAQ,CAAAO,MAAK,CAAC,GAAGA,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO,GAAG;AAAA,CAAI,CAAC,GACrEC,IAAmB,CAAA;AACzB,aAAQ9E,IAAI,GAAGA,IAAI0D,EAAO,UAAS;AAClC,UAAI3C,IAAO,IAAIgE,IAAI/E;AACnB,aAAM+E,IAAIrB,EAAO,UAAQ;AACxB,cAAMsB,IAAOjE,KAAQA,IAAO,MAAM,MAAM2C,EAAOqB,CAAC;AAChD,YAAG,KAAK,eAAeC,EAAK,QAAQ,aAAa;AAAA,CAAI,CAAC,IAAIT,KAAaxD,EAAM;AAC7E,QAAAA,IAAOiE,GACPD;AAAA,MACD;AACA,YAAMlD,IAAQd,EAAK,QAAQ,aAAa;AAAA,CAAI,EAAE,KAAA;AAC9C,MAAGc,KAAOiD,EAAO,KAAKjD,CAAK,GAC3B7B,IAAI,KAAK,IAAI+E,IAAIP,GAAeO,MAAM/E,IAAIA,IAAI,IAAI+E,CAAC;AAAA,IACpD;AACA,WAAOD;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAUR,GAAyBW,IAAqD,IAA6B;AACpH,QAAI,EAAC,WAAAV,IAAY,KAAK,eAAAC,IAAgB,OAAMS,GACxCC,IAAU;AACd,UAAM1C,IAAQ,MAAM;AAAE,MAAA0C,IAAU;AAAA,IAAM,GAEhCC,IAAQ,CAACpE,MACP,IAAI,QAAQ,CAACqE,GAASC,MAAW;AACvC,UAAGH,EAAS,QAAOG,EAAO,IAAI,MAAM,SAAS,CAAC;AAE9C,YAAMhD,IAAiB;AAAA,QACtBiD,EAAKC,EAAQC,EAAc,YAAY,GAAG,CAAC,GAAG,aAAa;AAAA,QACnD,KAAK,GAAG,QAAQ;AAAA,QACxB,KAAK,GAAG,SAAS,YAAY;AAAA,MAAA,GAExBC,IAAOC,EAAM,QAAQrD,GAAM,EAAC,OAAO,CAAC,QAAQ,QAAQ,QAAQ,GAAE;AACpE,MAAAoD,EAAK,MAAM,MAAM1E,CAAI,GACrB0E,EAAK,MAAM,IAAA;AAEX,UAAIE,IAAS;AACb,MAAAF,EAAK,OAAO,GAAG,QAAQ,CAACG,MAAiBD,KAAUC,EAAK,UAAU,GAClEH,EAAK,GAAG,SAAS,CAACI,MAAiB;AAClC,YAAGX,EAAS,QAAOG,EAAO,IAAI,MAAM,SAAS,CAAC;AAC9C,YAAGQ,MAAS;AACX,cAAI;AACH,kBAAMtE,IAAS,KAAK,MAAMoE,CAAM;AAChC,YAAAP,EAAQ7D,EAAO,SAAS;AAAA,UACzB,QAAa;AACZ,YAAA8D,EAAO,IAAI,MAAM,kCAAkC,CAAC;AAAA,UACrD;AAAA;AAEA,UAAAA,EAAO,IAAI,MAAM,qCAAqCQ,CAAI,EAAE,CAAC;AAAA,MAE/D,CAAC,GACDJ,EAAK,GAAG,SAASJ,CAAM;AAAA,IACxB,CAAC,GAGIT,KAAK,YAAY;AACtB,YAAME,IAAS,KAAK,MAAMR,GAAQC,GAAWC,CAAa,GAAGrD,IAAiB,CAAA;AAC9E,eAAQnB,IAAI,GAAGA,IAAI8E,EAAO,UACtB,CAAAI,GAD8BlF,KAAK;AAEtC,cAAMe,IAAO+D,EAAO9E,CAAC,GACf8F,IAAY,MAAMX,EAAMpE,CAAI;AAClC,QAAAI,EAAQ,KAAK,EAAC,OAAOnB,GAAG,WAAA8F,GAAW,MAAA/E,GAAM,QAAQ,KAAK,eAAeA,CAAI,EAAA,CAAE;AAAA,MAC5E;AACA,aAAOI;AAAA,IACR,GAAA;AACA,WAAO,OAAO,OAAOyD,GAAG,EAAE,OAAApC,GAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe/C,GAAsB;AACpC,UAAMsB,IAAO,KAAK,UAAUtB,CAAO;AACnC,WAAO,KAAK,KAAMsB,EAAK,SAAS,IAAK,GAAG;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAWuD,MAAmByB,GAAuB;AACpD,QAAGA,EAAY,SAAS,EAAG,OAAM,IAAI,MAAM,wCAAwC;AACnF,UAAMC,IAAS,CAACjF,GAAckF,IAAqB,OAC3ClF,EAAK,cAAc,MAAM,EAAE,EAAE,IAAI,CAACmF,GAAMC,MAC7CD,EAAK,WAAW,CAAC,KAAKC,IAAQ,KAAMF,IAAaA,CAAU,EAAE,MAAM,GAAGA,CAAU,GAE7EG,IAAIJ,EAAO1B,CAAM,GACjB+B,IAAeN,EAAY,IAAI,CAAAxF,MAAKyF,EAAOzF,CAAC,CAAC,EAAE,IAAI,CAAA+F,MAAa,KAAK,iBAAiBF,GAAGE,CAAS,CAAC;AACzG,WAAO,EAAC,KAAKD,EAAa,OAAO,CAACE,GAAKC,MAAMD,IAAMC,GAAG,CAAC,IAAIH,EAAa,QAAQ,KAAK,KAAK,IAAI,GAAGA,CAAY,GAAG,cAAAA,EAAA;AAAA,EACjH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAKtF,GAAc0F,GAAgBvG,GAAoC;AAC5E,UAAM2F,IAAO,MAAM,KAAK,KAAK9E,GAAM,EAAC,GAAGb,GAAS,QAAQ;AAAA,MACvDA,GAAS;AAAA,MACT;AAAA;AAAA,EAA8DuG,CAAM;AAAA;AAAA,IAAA,EACnE,OAAO,CAAAlG,MAAK,CAAC,CAACA,CAAC,EAAE,KAAK;AAAA,CAAI,GAAE;AAC9B,WAAOsF,IAAO5E,EAAiB4E,GAAM,CAAA,CAAE,IAAI;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAU9E,GAAc2C,IAAiB,KAAKxD,GAA8C;AAC3F,WAAO,KAAK,IAAIa,GAAM,EAAC,QAAQ,6CAA6C2C,CAAM,gCAAgC,aAAa,KAAK,GAAGxD,EAAA,CAAQ;AAAA,EAChJ;AACD;AC/WO,MAAMwG,GAAM;AAAA,EAKlB,YAAoBrH,GAAQ;AAAR,SAAA,KAAAA,GAChBA,EAAG,QAAQ,YACb,KAAK,eAAeA,EAAG,QAAQ,OAAO,oBACtC,KAAK,iBAAA,IAGN,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAMaA,EAAG,QAAQ,IAAI;AAAA,iFACmCA,EAAG,QAAQ,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlG;AAAA,EA1BQ,YAA8C,CAAA;AAAA,EAC9C;AAAA,EACA;AAAA,EA0BR,MAAc,eAAesH,GAAoBC,GAAeC,IAAU,KAAsB;AAC/F,UAAMC,IAAiB,CAACC,MAAyB;AAEhD,UADAA,IAAOA,EAAK,YAAA,EAAc,QAAQ,WAAW,EAAE,GAC5CA,EAAK,UAAU,EAAG,QAAO;AAC5B,YAAMC,IAAUD,EAAK,MAAM,YAAY;AACvC,UAAIE,IAAQD,IAAUA,EAAQ,SAAS;AACvC,aAAGD,EAAK,SAAS,GAAG,KAAGE,KAChB,KAAK,IAAI,GAAGA,CAAK;AAAA,IACzB;AAEA,QAAI1F,IAAS;AAuBb,WAtBAoF,EAAc,cAAc,OAAO,CAACI,GAAM/G,MAAM;AAC/C,UAAIkH,IAAO;AACX,YAAMC,IAAWR,EAAc,cAAc3G,IAAI,CAAC,GAC5CoH,IAAWT,EAAc,cAAc3G,IAAI,CAAC;AAClD,aAAG,CAAC+G,EAAK,QAAQK,KAChBA,EAAS,QAAQ,OAAOL,EAAK,QAAQ,MACrCK,EAAS,WAAW,OAAOL,EAAK,QAAQ,QAC/BA,EAAK,QAAQA,EAAK,KAAK,CAAC,KAAK,OAAOI,MAC7CA,EAAS,QAAQ,KAAKJ,EAAK,QAAQ,IACnCI,EAAS,WAAW,KAAKJ,EAAK,WAAW,IACzCI,EAAS,QAAQJ,EAAK,MACtBG,IAAO,KAED,CAAC,CAACH,EAAK,QAAQ,CAACG;AAAA,IACxB,CAAC,EAAE,QAAQ,CAACH,MAAc;AACzB,YAAMM,IAAU,SAAS,KAAKN,EAAK,KAAK,MAAM,GACxCO,IAASP,EAAK,QAAQ,KAAKA,EAAK,QAAQ,MAExCQ,IADYT,EAAeC,EAAK,KAAK,MAAM,IACpBF;AAC7B,MAAGQ,KAAWC,IAASC,IAAW,KAAKR,EAAK,KAAK,CAAC,KAAK,QAAKxF,KAAU,MACtEA,KAAUwF,EAAK;AAAA,IAChB,CAAC,GACGH,IACG,KAAK,GAAG,SAAS,IAAIrF,GAAQ;AAAA,MACnC,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,OAAO,CAAC;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,QACb,MAAM;AAAA,UACL,MAAM,EAAC,MAAM,UAAU,aAAa,gBAAgB,UAAU,GAAA;AAAA,UAC9D,SAAS,EAAC,MAAM,UAAU,aAAa,mBAAmB,UAAU,GAAA;AAAA,QAAI;AAAA,QAEzE,IAAI,CAACc,MAASd,IAASA,EAAO,QAAQc,EAAK,MAAMA,EAAK,OAAO;AAAA,MAAA,CAC7D;AAAA,IAAA,CACD,EAAE,KAAK,MAAMd,CAAM,IAbJA,EAAO,KAAA;AAAA,EAcxB;AAAA,EAEA,MAAc,kBAAkBoF,GAAoBa,GAAiBZ,GAA+B;AACnG,UAAMa,wBAAiB,IAAA;AACvB,QAAIC,IAAe;AACnB,IAAAF,EAAS,QAAQ,CAACG,MAAa;AAC9B,MAAIF,EAAW,IAAIE,EAAI,OAAO,KAAGF,EAAW,IAAIE,EAAI,SAAS,EAAED,CAAY;AAAA,IAC5E,CAAC;AAED,UAAME,IAAiB,MAAM,KAAK,eAAejB,GAAeC,CAAG,GAC7DiB,IAAYD,EAAe,MAAM,gBAAgB,KAAK,CAACA,CAAc,GACrEE,IAAQnB,EAAc,cAAc,OAAO,CAACoB,MAAWA,EAAE,KAAK,MAAM,GAGpEC,IAAwBH,EAAU,IAAI,CAAAI,MAAY;AAEvD,UADAA,IAAWA,EAAS,KAAA,GACjB,CAACA,EAAU,QAAO;AAErB,YAAMC,IAAgBD,EAAS,cAAc,QAAQ,YAAY,EAAE,EAAE,MAAM,KAAK,GAC1EE,wBAAuB,IAAA;AAE7B,MAAAD,EAAc,QAAQ,CAAAE,MAAM;AAC3B,cAAMrB,IAAOe,EAAM,KAAK,CAACC,MAAWK,MAAOL,EAAE,KAAK,KAAA,EAAO,YAAA,EAAc,QAAQ,UAAU,EAAE,CAAC;AAC5F,YAAG,CAAChB,EAAM;AAEV,cAAMsB,IAAWtB,EAAK,QAAQ,OAAO,KAC/BuB,IAAUd,EAAS,KAAK,CAACG,MAAaU,KAAYV,EAAI,SAASU,KAAYV,EAAI,GAAG;AACxF,YAAGW,GAAS;AACX,gBAAMC,IAASd,EAAW,IAAIa,EAAQ,OAAO;AAC7C,UAAAH,EAAiB,IAAII,IAASJ,EAAiB,IAAII,CAAM,KAAK,KAAK,CAAC;AAAA,QACrE;AAAA,MACD,CAAC;AAED,UAAIC,IAAc,GACdC,IAAW;AACf,aAAAN,EAAiB,QAAQ,CAAClB,GAAOqB,MAAY;AAC5C,QAAGrB,IAAQwB,MACVA,IAAWxB,GACXuB,IAAcF;AAAA,MAEhB,CAAC,GAEM,EAAC,SAASE,GAAa,MAAMP,EAAA;AAAA,IACrC,CAAC,EAAE,OAAO,CAAAzB,MAAKA,MAAM,IAAI,GAGnBkC,IAAiD,CAAA;AACvD,IAAAV,EAAsB,QAAQ,CAAAW,MAAQ;AACrC,YAAM3H,IAAO0H,EAAOA,EAAO,SAAS,CAAC;AACrC,MAAG1H,KAAQA,EAAK,YAAY2H,EAAK,UAChC3H,EAAK,QAAQ,MAAM2H,EAAK,OAExBD,EAAO,KAAK,EAAC,GAAGC,GAAK;AAAA,IAEvB,CAAC;AAED,QAAIC,IAAaF,EAAO,IAAI,CAAAC,MAAQ,YAAYA,EAAK,OAAO,MAAMA,EAAK,IAAI,EAAE,EAAE,KAAK;AAAA,CAAI,EAAE,KAAA;AAC1F,QAAG,CAAC/B,EAAK,QAAOgC;AAChB,QAAI9D,IAAS,KAAK,GAAG,SAAS,MAAM8D,GAAY,KAAK,CAAC;AACtD,IAAG9D,EAAO,SAAS,MAAGA,IAAS,CAAC,GAAGA,EAAO,MAAM,GAAG,CAAC,GAAWA,EAAO,GAAG,EAAE,CAAC;AAC5E,UAAM+D,IAAQ,MAAM,KAAK,GAAG,SAAS,KAAK/D,EAAO,KAAK;AAAA,CAAI,GAAG,0CAA0C;AAAA,MACtG,QAAQ;AAAA,MACR,aAAa;AAAA,IAAA,CACb;AACD,kBAAO,QAAQ+D,CAAK,EAAE,QAAQ,CAAC,CAACP,GAASQ,CAAI,MAAMF,IAAaA,EAAW,WAAW,YAAYN,CAAO,KAAK,IAAIQ,CAAI,GAAG,CAAC,GACnHF;AAAA,EACR;AAAA,EAEQ,OAAOG,GAAc9D,IAAgD,IAA2B;AACvG,QAAIQ;AACJ,UAAMb,IAAI,IAAI,QAAa,CAACQ,GAASC,MAAW;AAC/C,WAAK,iBAAiBJ,EAAK,KAAK,EAAE,KAAK,CAAAlF,MAAK;AAC3C,YAAGkF,EAAK,aAAa;AACpB,cAAIU,IAAShB,EAAK,KAAKA,EAAK,QAAQoE,CAAI,GAAG,YAAY;AACvD,UAAAtD,IAAOC;AAAA,YAAc,KAAK,GAAG,QAAQ;AAAA,YACpC,CAAC,MAAM3F,GAAG,MAAMgJ,GAAM,OAAO,OAAO,KAAK,OAAO,OAAOpD,CAAM;AAAA,YAC7D,EAAC,OAAO,CAAC,UAAU,UAAU,MAAM,EAAA;AAAA,UAAC,GAErCF,EAAK,GAAG,SAAS,CAAC5E,MAAewE,EAAOxE,CAAG,CAAC,GAC5C4E,EAAK,GAAG,SAAS,OAAOI,MAAiB;AACxC,gBAAGA,MAAS,GAAG;AACd,cAAAF,IAAS,MAAMqD,EAAG,SAASrD,IAAS,SAAS,OAAO,GACpDqD,EAAG,GAAGrD,IAAS,OAAO,EAAE,MAAM,MAAM;AAAA,cAAE,CAAC;AACvC,kBAAI;AAAE,gBAAAP,EAAQ,KAAK,MAAMO,CAAM,CAAC;AAAA,cAAG,QAC1B;AAAE,gBAAAN,EAAO,IAAI,MAAM,8BAA8B,CAAC;AAAA,cAAG;AAAA,YAC/D;AACC,cAAAA,EAAO,IAAI,MAAM,aAAaQ,CAAI,EAAE,CAAC;AAAA,UAEvC,CAAC;AAAA,QACF,OAAO;AACN,cAAIF,IAAS;AACb,UAAAF,IAAOC,EAAc,KAAK,GAAG,QAAQ,SAAS,CAAC,MAAM3F,GAAG,MAAMgJ,GAAM,OAAO,KAAK,CAAC,GACjFtD,EAAK,GAAG,SAAS,CAAC5E,MAAewE,EAAOxE,CAAG,CAAC,GAC5C4E,EAAK,OAAO,GAAG,QAAQ,CAACG,MAAiBD,KAAUC,EAAK,UAAU,GAClEH,EAAK,GAAG,SAAS,OAAOI,MAAiB;AACxC,YAAGA,MAAS,IACXT,EAAQO,EAAO,KAAA,KAAU,IAAI,IAE7BN,EAAO,IAAI,MAAM,aAAaQ,CAAI,EAAE,CAAC;AAAA,UAEvC,CAAC;AAAA,QACF;AAAA,MACD,CAAC;AAAA,IACF,CAAC;AACD,WAAY,OAAO,OAAOjB,GAAG,EAAC,OAAO,MAAMa,GAAM,KAAK,SAAS,GAAE;AAAA,EAClE;AAAA,EAEQ,eAAesD,GAAqC;AAC3D,QAAI7D,IAAU,IAAO1C,IAAQ,MAAM;AAAE,MAAA0C,IAAU;AAAA,IAAM;AACrD,UAAM+D,IAAc,CAACC,MACb,IAAI,QAAiB,CAAC9D,MAAY;AACxC,YAAMK,IAAOC,EAAMwD,GAAK,CAAC,MAAM,UAAU,MAAM,uBAAuB,CAAC;AACvE,MAAAzD,EAAK,GAAG,SAAS,CAACI,MAAiBT,EAAQS,MAAS,CAAC,CAAC,GACtDJ,EAAK,GAAG,SAAS,MAAML,EAAQ,EAAK,CAAC;AAAA,IACtC,CAAC,GAEIR,IAAI,QAAQ,IAAS;AAAA,MAC1BqE,EAAY,QAAQ;AAAA,MACpBA,EAAY,SAAS;AAAA,IAAA,CACrB,EAAE,MAAW,OAAO,CAACrE,GAAGuE,CAAE,MAA0B;AACpD,UAAGjE,EAAS;AACZ,UAAG,CAACN,KAAK,CAACuE,EAAI,OAAM,IAAI,MAAM,uDAAuD;AACrF,YAAMC,IAASD,IAAK,YAAY;AAChC,aAAO,IAAI,QAAQ,CAAC/D,GAASC,MAAW;AACvC,YAAGH,EAAS;AACZ,YAAIS,IAAS;AACb,cAAMF,IAAOC,EAAM0D,GAAQ,CAAC,MAAM,UAAU,MAAM,KAAK,UAAUL,CAAI,CAAC;AACtE,QAAAtD,EAAK,OAAO,GAAG,QAAQ,CAACG,MAAiBD,KAAUC,EAAK,UAAU,GAClEH,EAAK,OAAO,GAAG,QAAQ,CAACG,MAAiB,QAAQ,MAAMA,EAAK,SAAA,CAAU,CAAC,GACvEH,EAAK,GAAG,SAAS,CAACI,MAAiB;AAClC,cAAGA,MAAS;AACX,gBAAI;AAAE,cAAAT,EAAQ,KAAK,MAAMO,CAAM,CAAC;AAAA,YAAG,QACvB;AAAE,cAAAN,EAAO,IAAI,MAAM,oCAAoC,CAAC;AAAA,YAAG;AAAA;AAEvE,YAAAA,EAAO,IAAI,MAAM,mCAAmCQ,CAAI,EAAE,CAAC;AAAA,QAE7D,CAAC,GACDJ,EAAK,GAAG,SAASJ,CAAM,GACvB7C,IAAQ,MAAMiD,EAAK,KAAK,SAAS;AAAA,MAClC,CAAC;AAAA,IACF,EAAA;AACA,WAAY,OAAO,OAAOb,GAAG,EAAC,OAAApC,GAAM;AAAA,EACrC;AAAA,EAEA,IAAIuG,GAAc7I,IAA6D,IAAqC;AACnH,QAAG,CAAC,KAAK,GAAG,QAAQ,QAAS,OAAM,IAAI,MAAM,wBAAwB;AAErE,UAAMmJ,IAAM/D,EAAKgE,EAAYhE,EAAKiE,KAAU,QAAQ,CAAC,GAAG,eAAe;AACvE,IAAAC,EAAS,cAAcT,CAAI,6BAA6BM,CAAG,KAAK,EAAE,OAAO,UAAU;AACnF,UAAMxH,IAAQ,MAAMmH,EAAG,GAAGS,EAAK,QAAQJ,CAAG,GAAG,EAAC,WAAW,IAAM,OAAO,GAAA,CAAK,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAE3F,QAAG,CAACnJ,EAAQ,YAAa,QAAO,KAAK,OAAOmJ,GAAK,EAAC,OAAOnJ,EAAQ,OAAM;AACvE,UAAMwJ,IAAa,KAAK,OAAOL,GAAK,EAAC,OAAOnJ,EAAQ,OAAO,aAAa,IAAK,GACvEyJ,IAAc,KAAK,eAAeN,CAAG;AAC3C,QAAInE,IAAU,IAAO1C,IAAQ,MAAM;AAClC,MAAA0C,IAAU,IACVwE,EAAW,MAAA,GACXC,EAAY,MAAA,GACZ9H,EAAA;AAAA,IACD;AAEA,UAAM+H,IAAW,QAAQ,WAAW,CAACF,GAAYC,CAAW,CAAC,EAAE,KAAK,OAAO,CAACE,GAAI9F,CAAC,MAAM;AACtF,UAAG8F,EAAG,UAAU,WAAY,OAAM,IAAI,MAAM;AAAA,IAA8BA,EAAG,MAAM;AACnF,UAAG9F,EAAE,UAAU,WAAY,OAAM,IAAI,MAAM;AAAA,IAAgBA,EAAE,MAAM;AACnE,aAAGmB,KAAW,CAAChF,EAAQ,cAAoB2J,EAAG,QACvC,KAAK,kBAAkBA,EAAG,OAAO9F,EAAE,OAAO7D,EAAQ,eAAe,KAAK;AAAA,IAC9E,CAAC,EAAE,QAAQ,MAAM2B,GAAO;AACxB,WAAY,OAAO,OAAO+H,GAAU,EAAC,OAAApH,GAAM;AAAA,EAC5C;AAAA,EAEA,MAAM,iBAAiBjD,IAAgB,KAAK,cAA+B;AAC1E,QAAG,CAAC,KAAK,GAAG,QAAQ,QAAS,OAAM,IAAI,MAAM,wBAAwB;AACrE,IAAIA,EAAM,SAAS,MAAM,MAAGA,KAAS;AACrC,UAAMqF,IAAI6E,EAAK,KAAa,KAAK,GAAG,QAAQ,MAAMlK,CAAK;AACvD,WAAG,MAAMyJ,EAAG,KAAKpE,CAAC,EAAE,KAAK,MAAM,EAAI,EAAE,MAAM,MAAM,EAAK,IAAUA,IAC3D,KAAK,UAAUrF,CAAK,IAAU,KAAK,UAAUA,CAAK,KACvD,KAAK,UAAUA,CAAK,IAAI,MAAM,6DAA6DA,CAAK,EAAE,EAChG,KAAK,CAAAoB,MAAQA,EAAK,aAAa,EAC/B,KAAK,CAAAmJ,MAAO,OAAO,KAAKA,CAAG,CAAC,EAAE,KAAK,OAAMC,OACzC,MAAMf,EAAG,UAAUpE,GAAGmF,CAAM,GAC5B,OAAO,KAAK,UAAUxK,CAAK,GACpBqF,EACP,GACK,KAAK,UAAUrF,CAAK;AAAA,EAC5B;AACD;AC1QO,MAAMyK,GAAO;AAAA,EAEnB,YAAoB3K,GAAQ;AAAR,SAAA,KAAAA;AAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO7B,IAAIsF,GAA+C;AAClD,QAAIsF;AACJ,UAAMrF,IAAI,IAAI,QAAuB,OAAMxE,MAAO;AACjD,MAAA6J,IAAS,MAAMC,EAAa,KAAK,GAAG,QAAQ,OAAO,OAAO,GAAG,EAAC,WAAW,KAAK,GAAG,QAAQ,MAAK;AAC9F,YAAM,EAAC,MAAAtE,EAAA,IAAQ,MAAMqE,EAAO,UAAUtF,CAAI;AAC1C,YAAMsF,EAAO,UAAA,GACb7J,EAAIwF,EAAK,KAAK,KAAA,KAAU,IAAI;AAAA,IAC7B,CAAC;AACD,WAAO,OAAO,OAAOhB,GAAG,EAAC,OAAO,MAAMqF,GAAQ,UAAA,GAAY;AAAA,EAC3D;AACD;ACMO,MAAME,GAAG;AAAA,EAQf,YAA4BjK,GAAoB;AAApB,SAAA,UAAAA,GACvBA,EAAQ,SAAMA,EAAQ,OAAOkK,EAAG,OAAA,IACpC,QAAQ,IAAI,qBAAqBlK,EAAQ,MACzC,KAAK,QAAQ,IAAIwG,GAAM,IAAI,GAC3B,KAAK,WAAW,IAAIpE,EAAI,IAAI,GAC5B,KAAK,SAAS,IAAI0H,GAAO,IAAI;AAAA,EAC9B;AAAA;AAAA,EAZA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AASD;ACpCA,MAAMK,KAAW,MACbD,EAAG,cAAc,UAAgB,QAC7BE,gBAAoB,MAAM,GAAG,EAAE,SAAS,QAmCnCC,KAAkB;AAAA,EAC9B,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM,EAAC,SAAS,EAAC,MAAM,UAAU,aAAa,kBAAkB,UAAU,KAAI;AAAA,EAC9E,IAAI,CAAClI,MAA4BiI,IAAQjI,EAAK,OAAO;AACtD,GAEamI,KAAuB;AAAA,EACnC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM,CAAA;AAAA,EACN,IAAI,aAAY,oBAAI,KAAA,GAAO,YAAA;AAC5B,GAEaC,KAAmB;AAAA,EAC/B,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,IACL,UAAU,EAAC,MAAM,UAAU,aAAa,4BAA4BJ,GAAA,CAAU,KAAK,MAAM,CAAC,OAAO,QAAQ,QAAQ,GAAG,UAAU,GAAA;AAAA,IAC9H,MAAM,EAAC,MAAM,UAAU,aAAa,mBAAmB,UAAU,GAAA;AAAA,EAAI;AAAA,EAEtE,IAAI,OAAOhI,GAAMqI,GAAQrL,MAAO;AAC/B,QAAI;AACH,cAAOgD,EAAK,UAAA;AAAA,QACX,KAAK;AACJ,iBAAO,MAAMkI,GAAQ,GAAG,EAAC,SAASlI,EAAK,KAAA,GAAOqI,GAAQrL,CAAE;AAAA,QACzD,KAAK;AACJ,iBAAO,MAAMsL,GAAO,GAAG,EAAC,MAAMtI,EAAK,KAAA,GAAOqI,GAAQrL,CAAE;AAAA,QACrD,KAAK;AACJ,iBAAO,MAAMuL,GAAW,GAAG,EAAC,MAAMvI,EAAK,KAAA,GAAOqI,GAAQrL,CAAE;AAAA,QACzD;AACC,gBAAM,IAAI,MAAM,yBAAyBgD,EAAK,QAAQ,EAAE;AAAA,MAAA;AAAA,IAE3D,SAAQxB,GAAU;AACjB,aAAO,EAAC,OAAOA,GAAK,WAAWA,EAAI,WAAS;AAAA,IAC7C;AAAA,EACD;AACD,GAEagK,KAAoB;AAAA,EAChC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,IACL,KAAK,EAAC,MAAM,UAAU,aAAa,gBAAgB,UAAU,GAAA;AAAA,IAC7D,QAAQ,EAAC,MAAM,UAAU,aAAa,sBAAsB,MAAM,CAAC,OAAO,QAAQ,OAAO,QAAQ,GAAG,SAAS,MAAA;AAAA,IAC7G,SAAS,EAAC,MAAM,UAAU,aAAa,wBAAwB,SAAS,GAAC;AAAA,IACzE,MAAM,EAAC,MAAM,UAAU,aAAa,oBAAA;AAAA,EAAmB;AAAA,EAExD,IAAI,CAACxI,MAKC,IAAIyI,EAAK,EAAC,KAAKzI,EAAK,KAAK,SAASA,EAAK,SAAQ,EAAE,QAAQ,EAAC,QAAQA,EAAK,UAAU,OAAO,MAAMA,EAAK,KAAA,CAAK;AAC/G,GAEasI,KAAiB;AAAA,EAC7B,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,IACL,MAAM,EAAC,MAAM,UAAU,aAAa,uBAAuB,UAAU,GAAA;AAAA,EAAI;AAAA,EAE1E,IAAI,OAAOtI,MAAyB;AACnC,UAAMvC,IAAIiL,EAAmB,IAAI,GAC3BpK,IAAO,MAAMqK,EAAQ,EAAC,SAASlL,EAAA,GAAIuC,EAAK,MAAM,EAAI,EAAE,MAAM,CAACxB,MAAaf,EAAE,OAAO,MAAM,KAAKe,CAAG,CAAC;AACtG,WAAO,EAAC,GAAGf,EAAE,QAAQ,QAAQa,GAAM,QAAQ,QAAW,QAAQ,OAAA;AAAA,EAC/D;AACD,GAEaiK,KAAqB;AAAA,EACjC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,IACL,MAAM,EAAC,MAAM,UAAU,aAAa,uBAAuB,UAAU,GAAA;AAAA,EAAI;AAAA,EAE1E,IAAI,OAAOvI,OAA0B,EAAC,QAAQiI,eAAmBjI,EAAK,IAAI,IAAA;AAC3E,GAEa4I,KAA0B;AAAA,EACtC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,IACL,KAAK,EAAC,MAAM,UAAU,aAAa,+BAA+B,UAAU,GAAA;AAAA,IAC5E,OAAO,EAAC,MAAM,UAAU,aAAa,kFAAA;AAAA,EAAiF;AAAA,EAEvH,IAAI,OAAO5I,MAAwC;AAClD,UAAM6I,IAAO,MAAM,MAAM7I,EAAK,KAAK,EAAC,SAAS,EAAC,cAAc,4CAAA,GAA6C,EACvG,KAAK,CAAA8I,MAAKA,EAAE,MAAM,EAAE,MAAM,CAAAtK,MAAO;AAAC,YAAM,IAAI,MAAM,oBAAoBA,EAAI,OAAO,EAAE;AAAA,IAAC,CAAC,GAEjFuK,IAAIC,EAAQ,KAAKH,CAAI;AAC3B,IAAAE,EAAE,+HAA+H,EAAE,OAAA;AACnI,UAAME,IAAW;AAAA,MAChB,OAAOF,EAAE,2BAA2B,EAAE,KAAK,SAAS,KAAKA,EAAE,OAAO,EAAE,KAAA,KAAU;AAAA,MAC9E,aAAaA,EAAE,0BAA0B,EAAE,KAAK,SAAS,KAAKA,EAAE,iCAAiC,EAAE,KAAK,SAAS,KAAK;AAAA,IAAA;AAGvH,QAAIG,IAAU;AACd,UAAMC,IAAmB,CAAC,WAAW,QAAQ,iBAAiB,YAAY,SAAS,UAAU,MAAM;AACnG,eAAWC,KAAYD,GAAkB;AACxC,YAAME,IAAKN,EAAEK,CAAQ,EAAE,MAAA;AACvB,UAAIC,EAAG,UAAUA,EAAG,KAAA,EAAO,KAAA,EAAO,SAAS,KAAK;AAC/C,QAAAH,IAAUG,EAAG,KAAA;AACb;AAAA,MACD;AAAA,IACD;AACA,WAAKH,MAASA,IAAUH,EAAE,MAAM,EAAE,KAAA,IAClCG,IAAUA,EAAQ,QAAQ,QAAQ,GAAG,EAAE,OAAO,MAAM,GAAG,GAAI,GAEpD,EAAC,KAAKlJ,EAAK,KAAK,OAAOiJ,EAAS,MAAM,KAAA,GAAQ,aAAaA,EAAS,YAAY,KAAA,GAAQ,SAAAC,GAAS,OAAOlJ,EAAK,MAAA;AAAA,EACrH;AACD,GAEasJ,KAAwB;AAAA,EACpC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,IACL,OAAO,EAAC,MAAM,UAAU,aAAa,iBAAiB,UAAU,GAAA;AAAA,IAChE,QAAQ,EAAC,MAAM,UAAU,aAAa,+BAA+B,SAAS,EAAA;AAAA,EAAC;AAAA,EAEhF,IAAI,OAAOtJ,MAGL;AACL,UAAM6I,IAAO,MAAM,MAAM,uCAAuC,mBAAmB7I,EAAK,KAAK,CAAC,IAAI;AAAA,MACjG,SAAS,EAAC,cAAc,6CAA6C,mBAAmB,iBAAA;AAAA,IAAgB,CACxG,EAAE,KAAK,CAAA1B,MAAQA,EAAK,MAAM;AAC3B,QAAIiL,GAAOC,IAAQ;AACnB,UAAM1K,IAAU,IAAI2K,EAAA;AACpB,YAAOF,IAAQC,EAAM,KAAKX,CAAI,OAAO,QAAM;AAC1C,UAAIa,IAAM,iBAAiB,KAAK,mBAAmBH,EAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAGjE,UAFGG,MAAKA,IAAM,mBAAmBA,CAAG,IACjCA,KAAK5K,EAAQ,IAAI4K,CAAG,GACpB5K,EAAQ,SAASkB,EAAK,UAAU,GAAI;AAAA,IACxC;AACA,WAAOlB;AAAA,EACR;AACD;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ztimson/ai-utils",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
4
4
  "description": "AI Utility library",
5
5
  "author": "Zak Timson",
6
6
  "license": "MIT",