toolnet-memory 0.2.17 → 0.2.18

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/bundle/doctor.js CHANGED
@@ -2,4 +2,4 @@ import"dotenv/config";import{existsSync as ve,readFileSync as Ae}from"node:fs";i
2
2
  `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Pe(){let r=process.env.TOOLNET_GLOBAL_ENV??we(Se(),".config","toolnet-memory",".env");if(!ve(r))return;let e=Ae(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let i=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=_e(o.slice(n+1)))}}Pe();function b(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function E(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function X(){return{memory:{autoCapture:b(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:b(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:b(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:b(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:E(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:E(process.env.MEMORY_RERANK_TOP,10),finalContext:E(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:E(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:b(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:E(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Oe}from"node:crypto";import{existsSync as Y,mkdirSync as Ie,readFileSync as ke,renameSync as je,writeFileSync as xe}from"node:fs";import{basename as Re,dirname as P,join as I,parse as re,resolve as v}from"node:path";var oe=".toolnet",Ce="project.json";function Me(r){return Oe("sha256").update(r).digest("hex").slice(0,16)}function z(r){return I(r,oe,Ce)}function Te(r){return Y(z(r))}function Le(r,e){let t=v(r),o=re(t).root;for(;;){if(Te(t))return t;if(t===o||e&&t===v(e))break;let n=P(t);if(n===t)break;t=n}return null}function De(r){let e=v(r),t=re(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>Y(I(e,i))))return e;if(e===t)break;let n=P(e);if(n===e)break;e=n}return v(r)}function Ke(r){let e;try{e=JSON.parse(ke(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let o=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:P(P(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function ee(r,e){let t=I(r,oe);Ie(t,{recursive:!0});let o=z(r),n=`${o}.tmp-${process.pid}`;xe(n,JSON.stringify(e,null,2)+`
3
3
  `,{encoding:"utf8",mode:384}),je(n,o)}function te(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var O=class{detect(e=process.cwd()){let t=v(e),o=De(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>Y(I(o,p))),a=Le(t,i?o:void 0);if(a){let p=z(a),u=Ke(p);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),ee(a,u)),te(u,a)}let c=new Date().toISOString(),d=Re(o),m={version:1,id:Me(o),name:d,remote:d,rootPath:o,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return ee(o,m),te(m,o)}};import{homedir as it}from"node:os";import{join as at}from"node:path";import{DeleteObjectCommand as Ne,GetObjectCommand as Ue,HeadObjectCommand as $e,ListObjectsV2Command as Be,PutObjectCommand as Fe,S3Client as Ge}from"@aws-sdk/client-s3";import{getSignedUrl as Ve}from"@aws-sdk/s3-request-presigner";var k=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ge({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Fe({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Ve(this.client,new Ue({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new $e({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Ne({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Be({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as ne,mkdir as He,readFile as Ye,readdir as ze,rm as Je,stat as se,writeFile as qe}from"node:fs/promises";import{dirname as We,join as Ze,relative as ie,resolve as Qe}from"node:path";var A=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Qe(this.root,t)}async put(e,t){let o=this.path(e);await He(We(o),{recursive:!0}),await qe(o,t)}async get(e){try{return await Ye(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await ne(this.path(e)),!0}catch{return!1}}async delete(e){await Je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ne(t)}catch{return o}let n=async a=>{let c=await ze(a,{withFileTypes:!0});for(let d of c){let m=Ze(a,d.name);if(d.isDirectory()){await n(m);continue}let p=await se(m);o.push({key:ie(this.root,m),size:p.size,updatedAt:p.mtime.toISOString()})}},i=await se(t);return i.isDirectory()?await n(t):o.push({key:ie(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as Xe,GetObjectCommand as et,HeadObjectCommand as tt,ListObjectsV2Command as rt,PutObjectCommand as ot,S3Client as nt}from"@aws-sdk/client-s3";import{getSignedUrl as st}from"@aws-sdk/s3-request-presigner";var S=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new nt({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ot({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await st(this.client,new et({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`${this.name} download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new tt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Xe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new rt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};function J(r,e){return console.warn(e),new A(r)}function ae(r){let e=r.localRoot??at(it(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new S({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new S({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new k({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new A(e)}var j=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};var x=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let o=JSON.parse(t);if(o.version!==1||o.projectId!==e||!Array.isArray(o.records))throw new Error("Invalid vector snapshot");return o}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var R=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var C=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var M=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function ct(r){return new Promise(e=>setTimeout(e,r))}async function ce(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let d=Math.min(n,o*2**(a-1)),m=Math.floor(Math.random()*Math.max(1,d*.2));await ct(d+m)}throw i}var dt=new Set(["put","get","getText","delete","list"]);function de(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:dt.has(o)?(...i)=>ce(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}var le=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function f(r){let e=le.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function T(r){return le.some(e=>e.id===r)}function s(r){return process.env[r]?.trim()||void 0}function l(...r){return r.find(e=>!!e?.trim())}function pe(){if(s("GROQ_API_KEY"))return"groq";if(s("DEEPSEEK_API_KEY"))return"deepseek";if(s("NVIDIA_API_KEY")||s("NVIDIA_NIM_API_KEY"))return"nvidia";if(s("OPENROUTER_API_KEY"))return"openrouter";if(s("ALIBABA_API_KEY")||s("DASHSCOPE_API_KEY"))return"alibaba";if(s("GEMINI_API_KEY")||s("GOOGLE_API_KEY"))return"gemini";if(s("CLOUDFLARE_API_TOKEN")&&s("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(s("HF_TOKEN"))return"huggingface";if(s("OLLAMA_MODEL")||s("OLLAMA_BASE_URL"))return"ollama"}function me(){let r=s("TOOLNET_LLM_PROVIDER");return r&&T(r)?r:pe()??"openai-compatible"}function L(r){let e=f(r);switch(r){case"alibaba":return{provider:r,apiKey:l(s("ALIBABA_API_KEY"),s("DASHSCOPE_API_KEY")),baseUrl:l(s("ALIBABA_BASE_URL"),s("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:l(s("ALIBABA_MODEL"),s("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:s("OPENROUTER_API_KEY"),baseUrl:l(s("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:s("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:s("GROQ_API_KEY"),baseUrl:l(s("GROQ_BASE_URL"),e.defaultBaseUrl),model:s("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:s("DEEPSEEK_API_KEY"),baseUrl:l(s("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:l(s("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:l(s("NVIDIA_API_KEY"),s("NVIDIA_NIM_API_KEY")),baseUrl:l(s("NVIDIA_BASE_URL"),s("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:l(s("NVIDIA_MODEL"),s("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:l(s("GEMINI_API_KEY"),s("GOOGLE_API_KEY")),baseUrl:l(s("GEMINI_BASE_URL"),e.defaultBaseUrl),model:s("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:s("HF_TOKEN"),baseUrl:l(s("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:l(s("HF_LLM_MODEL"),s("HF_MODEL"))};case"ollama":return{provider:r,apiKey:s("OLLAMA_API_KEY"),baseUrl:l(s("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:s("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:s("CLOUDFLARE_ACCOUNT_ID"),apiKey:s("CLOUDFLARE_API_TOKEN"),baseUrl:s("CLOUDFLARE_AI_BASE_URL"),model:s("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:s("CUSTOM_AI_API_KEY"),baseUrl:s("CUSTOM_AI_BASE_URL"),model:s("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:l(s("OPENAI_API_KEY"),s("MODEL_API_KEY")),baseUrl:l(s("OPENAI_BASE_URL"),s("MODEL_BASE_URL")),model:l(s("OPENAI_MODEL"),s("MODEL_NAME"))}}}function lt(){let r=s("TOOLNET_LLM_PROVIDER"),e=r&&T(r)?r:me(),t=f(e),o=L(e);return{provider:e,apiKey:l(s("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:l(s("TOOLNET_LLM_BASE_URL"),o.baseUrl,t.defaultBaseUrl),model:l(s("TOOLNET_LLM_MODEL"),o.model,t.defaultModel),accountId:l(s("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function pt(){let r=s("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&T(r)?r:s("HF_TOKEN")||s("HF_EMBEDDING_MODEL")?"huggingface":"local"}function mt(){let r=pt();if(r==="local")return{provider:"local",model:l(s("TOOLNET_EMBEDDING_MODEL"),s("LOCAL_EMBEDDING_MODEL"))};let e=f(r),t,o,n,i;switch(r){case"huggingface":t=s("HF_TOKEN"),o=s("HF_INFERENCE_BASE_URL"),n=s("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=s("OPENAI_API_KEY"),o=s("OPENAI_BASE_URL"),n=s("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=s("CLOUDFLARE_API_TOKEN"),o=s("CLOUDFLARE_AI_BASE_URL"),n=s("CLOUDFLARE_EMBEDDING_MODEL"),i=s("CLOUDFLARE_ACCOUNT_ID");break;default:t=L(r).apiKey,o=L(r).baseUrl,n=s(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=l(s("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),c=l(s("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),d=r==="cloudflare"&&!c&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:c;return{provider:r,apiKey:l(s("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:d,model:l(s("TOOLNET_EMBEDDING_MODEL"),n),accountId:a}}function w(){let r=lt(),e=mt();return{llm:r,embedding:e,legacy:{llm:!s("TOOLNET_LLM_PROVIDER")&&!!pe(),embedding:!s("TOOLNET_EMBEDDING_PROVIDER")&&!!(s("HF_TOKEN")||s("HF_EMBEDDING_MODEL"))}}}function ue(r=me()){let e=w().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=L(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}var D=class{constructor(e){this.options=e}options;name="gemini";async embed(e){let t=this.options.model.replace(/^models\//,""),n=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(t)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,i=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${t}`,content:{parts:[{text:e}]}})});if(!i.ok)throw new Error(`Gemini embedding failed: ${i.status} ${await i.text()}`);let c=(await i.json()).embedding?.values;if(!Array.isArray(c)||c.length===0)throw new Error("Gemini embedding returned invalid response");return c}async embedMany(e){let t=[];for(let o of e)t.push(await this.embed(o));return t}};import{createHash as ut}from"node:crypto";var K=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),o=e.toLowerCase().split(/\s+/).filter(Boolean);for(let n of o){let a=ut("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[a]+=1}return gt(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function gt(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var N=class{constructor(e){this.options=e;this.dimensions=e.dimensions}options;name="openai-compatible";dimensions;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=this.options.baseUrl.replace(/\/+$/,""),o=await fetch(`${t}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:e})});if(!o.ok)throw new Error(`Embedding failed: ${o.status} ${await o.text()}`);let i=(await o.json()).data?.sort((a,c)=>(a.index??0)-(c.index??0)).map(a=>a.embedding);if(!i||i.length!==e.length||i.some(a=>!Array.isArray(a)))throw new Error("Embedding provider returned invalid response");return i}};var U=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,o=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!o.ok)throw new Error(`HF embedding failed: ${o.status} ${await o.text()}`);let n=await o.json();if(!Array.isArray(n))throw new Error("HF embedding returned invalid response");return n.map(i=>ft(i))}};function ft(r){if(!Array.isArray(r))throw new Error("Invalid embedding");if(r.length>0&&typeof r[0]=="number")return r;if(r.length>0&&Array.isArray(r[0])){let e=r;if(e.length===0)return[];let t=e[0].length,o=new Array(t).fill(0);for(let n of e)for(let i=0;i<t;i++)o[i]+=n[i]??0;for(let n=0;n<t;n++)o[n]/=e.length;return o}throw new Error("Unsupported embedding shape")}var q=class{constructor(e,t=new K){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function yt(r){return`https://api.cloudflare.com/client/v4/accounts/${r}/ai/v1`}function ht(){let r=w().embedding;if(r.provider==="local")return null;if(r.provider==="huggingface")return!r.apiKey||!r.model?null:new U({token:r.apiKey,model:r.model});if(r.provider==="gemini")return!r.apiKey||!r.model?null:new D({apiKey:r.apiKey,model:r.model,baseUrl:r.baseUrl});let e=r.baseUrl;return r.provider==="cloudflare"&&!e&&r.accountId&&(e=yt(r.accountId)),e&&r.model?new N({apiKey:r.apiKey,baseUrl:e,model:r.model}):null}function ge(){return new q(ht())}var W=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(r,e,t=3e4){let o=new AbortController,n=setTimeout(()=>o.abort(),t);n.unref?.();try{let i=await fetch(r,{...e,signal:o.signal}),a=await i.text();if(!i.ok){let c=a;try{let d=JSON.parse(a);c=d.error?.message??d.message??a}catch{}throw new W(c||`HTTP ${i.status}`,i.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(n)}}function $(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var B=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),o=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!o)throw new Error("cloudflare: API TOKEN is not configured");let n=this.model(),a=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${n}`,c=await y(a,{method:"POST",headers:{authorization:`Bearer ${o}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),d=c.result?.response?.trim();if(!d)throw new Error(c.errors?.[0]?.message??"cloudflare: empty model response");return{text:d,provider:"cloudflare",model:n}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var F=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let o=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",n=this.model(),i=e.messages.filter(p=>p.role==="system"),a=e.messages.filter(p=>p.role!=="system").map(p=>({role:p.role==="assistant"?"model":"user",parts:[{text:p.content}]})),c=`${$(o,`models/${encodeURIComponent(n)}:generateContent`)}?key=${encodeURIComponent(t)}`,d=await y(c,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(p=>p.content).join(`
4
4
 
5
- `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),m=d.candidates?.[0]?.content?.parts?.map(p=>p.text??"").join("").trim();if(!m)throw new Error("gemini: empty model response");return{text:m,provider:"gemini",model:n,usage:d.usageMetadata?{inputTokens:d.usageMetadata.promptTokenCount,outputTokens:d.usageMetadata.candidatesTokenCount,totalTokens:d.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var G=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),o=await y($(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),n=o.choices?.[0]?.message?.content?.trim();if(!n)throw new Error(`${this.id}: empty model response`);return{text:n,provider:this.id,model:t,usage:o.usage?{inputTokens:o.usage.prompt_tokens,outputTokens:o.usage.completion_tokens,totalTokens:o.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function fe(r=ue()){switch(f(r.id).transport){case"gemini":return new F(r);case"cloudflare":return new B(r);default:return new G(r)}}var bt=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],V=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),i=n.replace(/[:.]/g,"-"),a=this.projectPrefix(e),c=this.snapshotPrefix(e,i),d=[];for(let p of bt){let u=`${a}/${p}`,_=await this.storage.get(u);_&&(await this.storage.put(`${c}/${p}`,_,"application/json"),d.push(p))}if(d.length===0)return null;let m={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:d,metadata:o};return await this.storage.put(`${c}/snapshot.json`,JSON.stringify(m,null,2),"application/json"),m}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(a=>a.key.endsWith("/snapshot.json")),i=[];for(let a of n){let c=await this.storage.getText(a.key);if(c)try{i.push(JSON.parse(c))}catch{}}return i.sort((a,c)=>c.createdAt.localeCompare(a.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let i=JSON.parse(n);if(i.projectId!==e)throw new Error("Snapshot project mismatch");let a=this.projectPrefix(e),c=[];for(let d of i.objects){let m=await this.storage.get(`${o}/${d}`);m&&(await this.storage.put(`${a}/${d}`,m,"application/json"),c.push(d))}return{restored:c}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let i of n)await this.storage.delete(i.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),i=0;for(let a of n)await this.remove(e,a.id),i++;return i}};function Z(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function ye(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?Z(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?Z(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?Z(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback"),process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Et}from"node:crypto";var H=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${Et()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let n=null;if(this.embeddings)try{let i=await this.embeddings.embed("ToolNet Memory production health check");n={ok:i.length>0,dimensions:i.length,mode:i.length===384?"huggingface":"fallback-or-custom"}}catch{n={ok:!1,dimensions:0,mode:"failed"}}return{ok:o&&(n===null||n.ok),storage:{ok:o,provider:this.storage.name},embedding:n}}};function be(){return process.argv.includes("--json")}function vt(r){if(console.log(""),console.log("ToolNet Memory Doctor"),console.log("====================="),console.log(""),r.project&&(console.log(`Project: ${r.project}`),console.log("")),r.storage)if(r.storage.ok){let n=typeof r.storage.provider=="string"?` (${r.storage.provider})`:"";console.log(`\u2713 Storage${n}`)}else console.log("\u2717 Storage");if(r.llm)if(r.llm.ok){let n=[];r.llm.provider&&n.push(r.llm.provider),r.llm.model&&n.push(r.llm.model),typeof r.llm.latencyMs=="number"&&n.push(`${r.llm.latencyMs} ms`),console.log(`\u2713 LLM${n.length?` (${n.join(", ")})`:""}`)}else console.log(`\u2717 LLM${r.llm.error?` (${r.llm.error})`:""}`);if(r.embedding)if(r.embedding.ok){let n=[];typeof r.embedding.mode=="string"&&n.push(r.embedding.mode),typeof r.embedding.dimensions=="number"&&n.push(`${r.embedding.dimensions} dimensions`),console.log(`\u2713 Embedding${n.length?` (${n.join(", ")})`:""}`)}else console.log("\u2717 Embedding");(r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(""),console.log("Project data:"),r.memory!==void 0&&console.log(` Memories ${r.memory}`),r.graphSymbols!==void 0&&console.log(` Graph symbols ${r.graphSymbols}`),r.graphEdges!==void 0&&console.log(` Graph edges ${r.graphEdges}`),r.memoryVectors!==void 0&&console.log(` Memory vectors ${r.memoryVectors}`),r.codeChunks!==void 0&&console.log(` Code chunks ${r.codeChunks}`),r.codeVectors!==void 0&&console.log(` Code vectors ${r.codeVectors}`),r.snapshots!==void 0&&console.log(` Snapshots ${r.snapshots}`));let e=r.config?.errors??[];if(e.length>0){console.log(""),console.log("Configuration required:");for(let n of e)console.log(` - ${n}`)}let t=[...r.config?.warnings??[],...r.warnings??[]],o=[...new Set(t)];if(o.length>0){console.log(""),console.log("Warnings:");for(let n of o)console.log(` - ${n}`)}console.log(""),r.ok?console.log("\u2713 ToolNet Memory is ready"):(console.log("\u2717 ToolNet Memory requires attention"),e.length>0&&(console.log(""),console.log("Run:"),console.log(" toolnet-memory setup"))),console.log("")}function he(r){be()?console.log(JSON.stringify(r,null,2)):vt(r)}async function At(){let r=ye();if(!r.ok){let g={ok:!1,config:r,warnings:r.warnings};he(g),process.exitCode=1;return}let e=X(),t=new O().detect(),o=de(ae({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=ge(),i=w(),a;try{let h=await fe({id:i.llm.provider,apiKey:i.llm.apiKey,baseUrl:i.llm.baseUrl,model:i.llm.model,accountId:i.llm.accountId}).healthCheck();a={ok:h.ok,provider:i.llm.provider,model:h.model??i.llm.model,latencyMs:h.latencyMs,error:h.ok?void 0:h.message}}catch(g){a={ok:!1,provider:i.llm.provider,model:i.llm.model,error:g instanceof Error?g.message:String(g)}}let c=await new H(o,n).run(),d=await new j(o).load(t.id),m=await new R(o).load(t.id),p=await new x(o).load(t.id),u=await new C(o).load(t.id),_=await new M(o).load(t.id),Ee=await new V(o).list(t.id),Q={ok:c.ok&&!!a?.ok,project:t.name,storage:c.storage,llm:a,embedding:c.embedding,memory:d.length,graphSymbols:m?.symbols.length??0,graphEdges:m?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:u?.chunks.length??0,codeVectors:_?.records.length??0,snapshots:Ee.length,warnings:r.warnings};he(Q),process.exitCode=Q.ok?0:1}At().catch(r=>{let e=r instanceof Error?r.message:String(r);be()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
5
+ `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),m=d.candidates?.[0]?.content?.parts?.map(p=>p.text??"").join("").trim();if(!m)throw new Error("gemini: empty model response");return{text:m,provider:"gemini",model:n,usage:d.usageMetadata?{inputTokens:d.usageMetadata.promptTokenCount,outputTokens:d.usageMetadata.candidatesTokenCount,totalTokens:d.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var G=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),o=await y($(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),n=o.choices?.[0]?.message?.content?.trim();if(!n)throw new Error(`${this.id}: empty model response`);return{text:n,provider:this.id,model:t,usage:o.usage?{inputTokens:o.usage.prompt_tokens,outputTokens:o.usage.completion_tokens,totalTokens:o.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function fe(r=ue()){switch(f(r.id).transport){case"gemini":return new F(r);case"cloudflare":return new B(r);default:return new G(r)}}var bt=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],V=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),i=n.replace(/[:.]/g,"-"),a=this.projectPrefix(e),c=this.snapshotPrefix(e,i),d=[];for(let p of bt){let u=`${a}/${p}`,_=await this.storage.get(u);_&&(await this.storage.put(`${c}/${p}`,_,"application/json"),d.push(p))}if(d.length===0)return null;let m={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:d,metadata:o};return await this.storage.put(`${c}/snapshot.json`,JSON.stringify(m,null,2),"application/json"),m}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(a=>a.key.endsWith("/snapshot.json")),i=[];for(let a of n){let c=await this.storage.getText(a.key);if(c)try{i.push(JSON.parse(c))}catch{}}return i.sort((a,c)=>c.createdAt.localeCompare(a.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let i=JSON.parse(n);if(i.projectId!==e)throw new Error("Snapshot project mismatch");let a=this.projectPrefix(e),c=[];for(let d of i.objects){let m=await this.storage.get(`${o}/${d}`);m&&(await this.storage.put(`${a}/${d}`,m,"application/json"),c.push(d))}return{restored:c}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let i of n)await this.storage.delete(i.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),i=0;for(let a of n)await this.remove(e,a.id),i++;return i}};function Z(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function ye(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?Z(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?Z(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?Z(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback"),process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Et}from"node:crypto";var H=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${Et()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let n=null;if(this.embeddings)try{let i=await this.embeddings.embed("ToolNet Memory production health check");n={ok:i.length>0,dimensions:i.length,mode:i.length===384?"huggingface":"fallback-or-custom"}}catch{n={ok:!1,dimensions:0,mode:"failed"}}return{ok:o&&(n===null||n.ok),storage:{ok:o,provider:this.storage.name},embedding:n}}};function be(){return process.argv.includes("--json")}function vt(r){if(console.log(""),console.log("ToolNet Memory Doctor"),console.log("====================="),console.log(""),r.project&&(console.log(`Project: ${r.project}`),console.log("")),r.storage)if(r.storage.ok){let n=typeof r.storage.provider=="string"?` (${r.storage.provider})`:"";console.log(`\u2713 Storage${n}`)}else console.log("\u2717 Storage");if(r.llm)if(r.llm.ok){let n=[];r.llm.provider&&n.push(r.llm.provider),r.llm.model&&n.push(r.llm.model),typeof r.llm.latencyMs=="number"&&n.push(`${r.llm.latencyMs} ms`),console.log(`\u2713 LLM${n.length?` (${n.join(", ")})`:""}`)}else console.log(`\u2717 LLM${r.llm.error?` (${r.llm.error})`:""}`);if(r.embedding)if(r.embedding.ok){let n=[];typeof r.embedding.mode=="string"&&n.push(r.embedding.mode),typeof r.embedding.dimensions=="number"&&n.push(`${r.embedding.dimensions} dimensions`),console.log(`\u2713 Embedding${n.length?` (${n.join(", ")})`:""}`)}else console.log("\u2717 Embedding");(r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(""),console.log("Project data:"),r.memory!==void 0&&console.log(` Memories ${r.memory}`),r.graphSymbols!==void 0&&console.log(` Graph symbols ${r.graphSymbols}`),r.graphEdges!==void 0&&console.log(` Graph edges ${r.graphEdges}`),r.memoryVectors!==void 0&&console.log(` Memory vectors ${r.memoryVectors}`),r.codeChunks!==void 0&&console.log(` Code chunks ${r.codeChunks}`),r.codeVectors!==void 0&&console.log(` Code vectors ${r.codeVectors}`),r.snapshots!==void 0&&console.log(` Snapshots ${r.snapshots}`));let e=r.config?.errors??[];if(e.length>0){console.log(""),console.log("Configuration required:");for(let n of e)console.log(` - ${n}`)}let t=[...r.config?.warnings??[],...r.warnings??[]],o=[...new Set(t)];if(o.length>0){console.log(""),console.log("Warnings:");for(let n of o)console.log(` - ${n}`)}console.log(""),r.ok?console.log("\u2713 ToolNet Memory is ready"):(console.log("\u2717 ToolNet Memory requires attention"),e.length>0&&(console.log(""),console.log("Run:"),console.log(" toolnet-memory setup"))),console.log("")}function he(r){be()?console.log(JSON.stringify(r,null,2)):vt(r)}async function At(){let r=ye();if(!r.ok){let g={ok:!1,config:r,warnings:r.warnings};he(g),process.exitCode=1;return}let e=X(),t=new O().detect(),o=de(ae({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=ge(),i=w(),a;try{let h=await fe({id:i.llm.provider,apiKey:i.llm.apiKey,baseUrl:i.llm.baseUrl,model:i.llm.model,accountId:i.llm.accountId}).healthCheck();a={ok:h.ok,provider:i.llm.provider,model:h.model??i.llm.model,latencyMs:h.latencyMs,error:h.ok?void 0:h.message}}catch(g){a={ok:!1,provider:i.llm.provider,model:i.llm.model,error:g instanceof Error?g.message:String(g)}}let c=await new H(o,n).run(),d=await new j(o).load(t.id),m=await new R(o).load(t.id),p=await new x(o).load(t.id),u=await new C(o).load(t.id),_=await new M(o).load(t.id),Ee=await new V(o).list(t.id),Q={ok:c.ok&&!!a?.ok,project:t.name,storage:c.storage,llm:a,embedding:c.embedding,memory:d.length,graphSymbols:m?.symbols.length??0,graphEdges:m?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:u?.chunks.length??0,codeVectors:_?.records.length??0,snapshots:Ee.length,warnings:r.warnings};he(Q),process.exitCode=Q.ok?0:1}At().catch(r=>{let e=r instanceof Error?r.message:String(r);be()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
package/bundle/mcp.js CHANGED
@@ -9,7 +9,7 @@ import"dotenv/config";import{existsSync as Gr,readFileSync as Ur}from"node:fs";i
9
9
  ${On(s,8)}`,source:"work-state"};break}case"status":{if(n){let s=[`Progress: ${n.progress.tasksCompleted}/${n.progress.tasksTotal} task ho\xE0n th\xE0nh.`];return n.currentTask&&s.push(`\u0110ang l\xE0m: ${n.currentTask.title}.`),n.progress.blocked>0&&s.push(`Blocked: ${n.progress.blocked}.`),{intent:t,answer:s.join(" "),source:"work-state"}}break}case"summary":{if(o||n){let s=[];o&&s.push(`Agent tr\u01B0\u1EDBc: ${o.agent}.`);let a=o?.currentTask??n?.currentTask?.title;a&&s.push(`Task hi\u1EC7n t\u1EA1i: ${a}.`);let c=o?.lastTouchedFile??n?.filesTouched?.at(-1);c&&s.push(`File g\u1EA7n nh\u1EA5t: ${c}.`);let d=o?.latestNextAction??n?.nextActions?.[0];d&&s.push(`Ti\u1EBFp theo: ${d}.`);let l=o?.latestBlocker??n?.blockers?.at(-1);l&&s.push(`Blocker: ${l}.`);let u=o?.latestDecision??n?.decisions?.at(-1);return u&&s.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${u}.`),{intent:t,answer:s.join(" "),source:o?"session-origin":"work-state"}}break}}let i=Nn(r);if(i){let s=i.length>900?`${i.slice(0,900)}
10
10
  [truncated]`:i;return{intent:t,answer:s,source:"handoff"}}return{intent:t,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}var ee=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function $(r,e,t=3e4){let o=new AbortController,n=setTimeout(()=>o.abort(),t);n.unref?.();try{let i=await fetch(r,{...e,signal:o.signal}),s=await i.text();if(!i.ok){let a=s;try{let c=JSON.parse(s);a=c.error?.message??c.message??s}catch{}throw new ee(a||`HTTP ${i.status}`,i.status)}return s.trim()?JSON.parse(s):{}}finally{clearTimeout(n)}}function Oe(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var De=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),o=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!o)throw new Error("cloudflare: API TOKEN is not configured");let n=this.model(),s=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${n}`,a=await $(s,{method:"POST",headers:{authorization:`Bearer ${o}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),c=a.result?.response?.trim();if(!c)throw new Error(a.errors?.[0]?.message??"cloudflare: empty model response");return{text:c,provider:"cloudflare",model:n}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var $e=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let o=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",n=this.model(),i=e.messages.filter(l=>l.role==="system"),s=e.messages.filter(l=>l.role!=="system").map(l=>({role:l.role==="assistant"?"model":"user",parts:[{text:l.content}]})),a=`${Oe(o,`models/${encodeURIComponent(n)}:generateContent`)}?key=${encodeURIComponent(t)}`,c=await $(a,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(l=>l.content).join(`
11
11
 
12
- `)}]}}:{},contents:s,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),d=c.candidates?.[0]?.content?.parts?.map(l=>l.text??"").join("").trim();if(!d)throw new Error("gemini: empty model response");return{text:d,provider:"gemini",model:n,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var Fe=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),o=await $(Oe(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),n=o.choices?.[0]?.message?.content?.trim();if(!n)throw new Error(`${this.id}: empty model response`);return{text:n,provider:this.id,model:t,usage:o.usage?{inputTokens:o.usage.prompt_tokens,outputTokens:o.usage.completion_tokens,totalTokens:o.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function Mr(r=vt()){switch(I(r.id).transport){case"gemini":return new $e(r);case"cloudflare":return new De(r);default:return new Fe(r)}}function Dn(r){return new Promise(e=>{setTimeout(e,r)})}function $n(r){if(r instanceof ee){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var Ke=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],o={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=o.cooldownMs??6e4,this.maxRetries=Math.max(0,o.maxRetries??1),this.providers=[e,...t].map(n=>({provider:Mr(n.config),label:n.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),o=this.states.get(t);return o||(o={failures:0,cooldownUntil:0},this.states.set(t,o)),o}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let o=this.state(e);o.failures+=1,o.lastError=t instanceof Error?t.message:String(t),o.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let o=0;o<this.providers.length;o+=1){if(!this.available(o)){t.push(`${this.providers[o].label}: cooldown`);continue}let n=this.providers[o];for(let i=0;i<=this.maxRetries;i+=1)try{let s=await n.provider.generate(e);return this.success(o),s}catch(s){let a=s instanceof Error?s.message:String(s),c=$n(s);if(t.push(`${n.label}: ${a}`),!c)throw s;if(i<this.maxRetries){await Dn(Math.min(250*2**i,2e3));continue}this.fail(o,s)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:t.provider,model:t.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,t)=>{let o=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:o.cooldownUntil>Date.now(),cooldownUntil:o.cooldownUntil||void 0,failures:o.failures,lastError:o.lastError}})}};function Rr(){let r=q(),e=xt();return new Ke({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),wt())}var rt=class{constructor(e=Rr()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function jr(){return new rt(Rr())}function Fn(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
12
+ `)}]}}:{},contents:s,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),d=c.candidates?.[0]?.content?.parts?.map(l=>l.text??"").join("").trim();if(!d)throw new Error("gemini: empty model response");return{text:d,provider:"gemini",model:n,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var Fe=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),o=await $(Oe(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),n=o.choices?.[0]?.message?.content?.trim();if(!n)throw new Error(`${this.id}: empty model response`);return{text:n,provider:this.id,model:t,usage:o.usage?{inputTokens:o.usage.prompt_tokens,outputTokens:o.usage.completion_tokens,totalTokens:o.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function Mr(r=vt()){switch(I(r.id).transport){case"gemini":return new $e(r);case"cloudflare":return new De(r);default:return new Fe(r)}}function Dn(r){return new Promise(e=>{setTimeout(e,r)})}function $n(r){if(r instanceof ee){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var Ke=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],o={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=o.cooldownMs??6e4,this.maxRetries=Math.max(0,o.maxRetries??1),this.providers=[e,...t].map(n=>({provider:Mr(n.config),label:n.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),o=this.states.get(t);return o||(o={failures:0,cooldownUntil:0},this.states.set(t,o)),o}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let o=this.state(e);o.failures+=1,o.lastError=t instanceof Error?t.message:String(t),o.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let o=0;o<this.providers.length;o+=1){if(!this.available(o)){t.push(`${this.providers[o].label}: cooldown`);continue}let n=this.providers[o];for(let i=0;i<=this.maxRetries;i+=1)try{let s=await n.provider.generate(e);return this.success(o),s}catch(s){let a=s instanceof Error?s.message:String(s),c=$n(s);if(t.push(`${n.label}: ${a}`),!c)throw s;if(i<this.maxRetries){await Dn(Math.min(250*2**i,2e3));continue}this.fail(o,s)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:t.provider,model:t.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,t)=>{let o=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:o.cooldownUntil>Date.now(),cooldownUntil:o.cooldownUntil||void 0,failures:o.failures,lastError:o.lastError}})}};function Rr(){let r=q(),e=xt();return new Ke({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),wt())}var rt=class{constructor(e=Rr()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function jr(){return new rt(Rr())}function Fn(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
13
13
  [truncated]`}function Kn(r,e){let t=X(r,e),o=Ne(r),n=_e(r),i={project:{id:r.id,name:r.name},directAnswer:t.answer,previousSession:o,workState:n?{goal:n.goal,plan:n.plan,currentPhase:n.currentPhase,currentTask:n.currentTask,tasks:n.tasks,blockers:n.blockers,decisions:n.decisions,nextActions:n.nextActions,filesTouched:n.filesTouched,tests:n.tests,progress:n.progress,lastSession:n.lastSession}:null};return Fn(i,7e3)}async function Ir(r,e){let t=X(r,e),o=Kn(r,e),n=jr();try{let i=await n.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
14
14
  You are ToolNet Memory Agent.
15
15
 
@@ -1,6 +1,6 @@
1
- import*as h from"fs";import*as f from"path";function j(r){let e=f.resolve(r),t=f.parse(e).root;for(;e!==t;){let n=f.join(e,".toolnet");if(h.existsSync(n)&&h.statSync(n).isDirectory())return e;e=f.dirname(e)}return null}var K=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function g(r){let e=K.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function A(r){return K.some(e=>e.id===r)}function o(r){return process.env[r]?.trim()||void 0}function c(...r){return r.find(e=>!!e?.trim())}function F(){if(o("GROQ_API_KEY"))return"groq";if(o("DEEPSEEK_API_KEY"))return"deepseek";if(o("NVIDIA_API_KEY")||o("NVIDIA_NIM_API_KEY"))return"nvidia";if(o("OPENROUTER_API_KEY"))return"openrouter";if(o("ALIBABA_API_KEY")||o("DASHSCOPE_API_KEY"))return"alibaba";if(o("GEMINI_API_KEY")||o("GOOGLE_API_KEY"))return"gemini";if(o("CLOUDFLARE_API_TOKEN")&&o("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(o("HF_TOKEN"))return"huggingface";if(o("OLLAMA_MODEL")||o("OLLAMA_BASE_URL"))return"ollama"}function B(){let r=o("TOOLNET_LLM_PROVIDER");return r&&A(r)?r:F()??"openai-compatible"}function b(r){let e=g(r);switch(r){case"alibaba":return{provider:r,apiKey:c(o("ALIBABA_API_KEY"),o("DASHSCOPE_API_KEY")),baseUrl:c(o("ALIBABA_BASE_URL"),o("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(o("ALIBABA_MODEL"),o("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:o("OPENROUTER_API_KEY"),baseUrl:c(o("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:o("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:o("GROQ_API_KEY"),baseUrl:c(o("GROQ_BASE_URL"),e.defaultBaseUrl),model:o("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:o("DEEPSEEK_API_KEY"),baseUrl:c(o("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(o("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:c(o("NVIDIA_API_KEY"),o("NVIDIA_NIM_API_KEY")),baseUrl:c(o("NVIDIA_BASE_URL"),o("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(o("NVIDIA_MODEL"),o("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:c(o("GEMINI_API_KEY"),o("GOOGLE_API_KEY")),baseUrl:c(o("GEMINI_BASE_URL"),e.defaultBaseUrl),model:o("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:o("HF_TOKEN"),baseUrl:c(o("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(o("HF_LLM_MODEL"),o("HF_MODEL"))};case"ollama":return{provider:r,apiKey:o("OLLAMA_API_KEY"),baseUrl:c(o("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:o("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:o("CLOUDFLARE_ACCOUNT_ID"),apiKey:o("CLOUDFLARE_API_TOKEN"),baseUrl:o("CLOUDFLARE_AI_BASE_URL"),model:o("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:o("CUSTOM_AI_API_KEY"),baseUrl:o("CUSTOM_AI_BASE_URL"),model:o("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(o("OPENAI_API_KEY"),o("MODEL_API_KEY")),baseUrl:c(o("OPENAI_BASE_URL"),o("MODEL_BASE_URL")),model:c(o("OPENAI_MODEL"),o("MODEL_NAME"))}}}function X(){let r=o("TOOLNET_LLM_PROVIDER"),e=r&&A(r)?r:B(),t=g(e),n=b(e);return{provider:e,apiKey:c(o("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:c(o("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:c(o("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:c(o("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function ee(){let r=o("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&A(r)?r:o("HF_TOKEN")||o("HF_EMBEDDING_MODEL")?"huggingface":"local"}function te(){let r=ee();if(r==="local")return{provider:"local",model:c(o("TOOLNET_EMBEDDING_MODEL"),o("LOCAL_EMBEDDING_MODEL"))};let e=g(r),t,n,s,a;switch(r){case"huggingface":t=o("HF_TOKEN"),n=o("HF_INFERENCE_BASE_URL"),s=o("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=o("OPENAI_API_KEY"),n=o("OPENAI_BASE_URL"),s=o("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=o("CLOUDFLARE_API_TOKEN"),n=o("CLOUDFLARE_AI_BASE_URL"),s=o("CLOUDFLARE_EMBEDDING_MODEL"),a=o("CLOUDFLARE_ACCOUNT_ID");break;default:t=b(r).apiKey,n=b(r).baseUrl,s=o(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let i=c(o("TOOLNET_EMBEDDING_ACCOUNT_ID"),a),l=c(o("TOOLNET_EMBEDDING_BASE_URL"),n,e.defaultBaseUrl),u=r==="cloudflare"&&!l&&i?`https://api.cloudflare.com/client/v4/accounts/${i}/ai/v1`:l;return{provider:r,apiKey:c(o("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:u,model:c(o("TOOLNET_EMBEDDING_MODEL"),s),accountId:i}}function C(){let r=X(),e=te();return{llm:r,embedding:e,legacy:{llm:!o("TOOLNET_LLM_PROVIDER")&&!!F(),embedding:!o("TOOLNET_EMBEDDING_PROVIDER")&&!!(o("HF_TOKEN")||o("HF_EMBEDDING_MODEL"))}}}function $(r=B()){let e=C().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=b(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function k(r,e){return o(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function G(){let r=[];for(let e of[1,2]){let t=k(e,"PROVIDER");if(!t||!A(t))continue;let n=g(t);r.push({slot:e,config:{provider:t,apiKey:k(e,"API_KEY"),baseUrl:c(k(e,"BASE_URL"),n.defaultBaseUrl),model:c(k(e,"MODEL"),n.defaultModel),accountId:k(e,"ACCOUNT_ID")}})}return r}function Y(){let r=o("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=o("TOOLNET_LLM_MAX_RETRIES"),t=Number(r??6e4),n=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(n)&&n>=0?Math.floor(n):1}}var E=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(r,e,t=3e4){let n=new AbortController,s=setTimeout(()=>n.abort(),t);s.unref?.();try{let a=await fetch(r,{...e,signal:n.signal}),i=await a.text();if(!a.ok){let l=i;try{let u=JSON.parse(i);l=u.error?.message??u.message??i}catch{}throw new E(l||`HTTP ${a.status}`,a.status)}return i.trim()?JSON.parse(i):{}}finally{clearTimeout(s)}}function _(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var O=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),n=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!n)throw new Error("cloudflare: API TOKEN is not configured");let s=this.model(),i=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${s}`,l=await y(i,{method:"POST",headers:{authorization:`Bearer ${n}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),u=l.result?.response?.trim();if(!u)throw new Error(l.errors?.[0]?.message??"cloudflare: empty model response");return{text:u,provider:"cloudflare",model:s}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var w=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let n=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",s=this.model(),a=e.messages.filter(d=>d.role==="system"),i=e.messages.filter(d=>d.role!=="system").map(d=>({role:d.role==="assistant"?"model":"user",parts:[{text:d.content}]})),l=`${_(n,`models/${encodeURIComponent(s)}:generateContent`)}?key=${encodeURIComponent(t)}`,u=await y(l,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...a.length?{systemInstruction:{parts:[{text:a.map(d=>d.content).join(`
1
+ import*as h from"fs";import*as f from"path";function j(r){let e=f.resolve(r),t=f.parse(e).root;for(;e!==t;){let n=f.join(e,".toolnet");if(h.existsSync(n)&&h.statSync(n).isDirectory())return e;e=f.dirname(e)}return null}var K=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function g(r){let e=K.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function A(r){return K.some(e=>e.id===r)}function o(r){return process.env[r]?.trim()||void 0}function c(...r){return r.find(e=>!!e?.trim())}function F(){if(o("GROQ_API_KEY"))return"groq";if(o("DEEPSEEK_API_KEY"))return"deepseek";if(o("NVIDIA_API_KEY")||o("NVIDIA_NIM_API_KEY"))return"nvidia";if(o("OPENROUTER_API_KEY"))return"openrouter";if(o("ALIBABA_API_KEY")||o("DASHSCOPE_API_KEY"))return"alibaba";if(o("GEMINI_API_KEY")||o("GOOGLE_API_KEY"))return"gemini";if(o("CLOUDFLARE_API_TOKEN")&&o("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(o("HF_TOKEN"))return"huggingface";if(o("OLLAMA_MODEL")||o("OLLAMA_BASE_URL"))return"ollama"}function B(){let r=o("TOOLNET_LLM_PROVIDER");return r&&A(r)?r:F()??"openai-compatible"}function v(r){let e=g(r);switch(r){case"alibaba":return{provider:r,apiKey:c(o("ALIBABA_API_KEY"),o("DASHSCOPE_API_KEY")),baseUrl:c(o("ALIBABA_BASE_URL"),o("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(o("ALIBABA_MODEL"),o("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:o("OPENROUTER_API_KEY"),baseUrl:c(o("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:o("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:o("GROQ_API_KEY"),baseUrl:c(o("GROQ_BASE_URL"),e.defaultBaseUrl),model:o("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:o("DEEPSEEK_API_KEY"),baseUrl:c(o("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(o("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:c(o("NVIDIA_API_KEY"),o("NVIDIA_NIM_API_KEY")),baseUrl:c(o("NVIDIA_BASE_URL"),o("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(o("NVIDIA_MODEL"),o("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:c(o("GEMINI_API_KEY"),o("GOOGLE_API_KEY")),baseUrl:c(o("GEMINI_BASE_URL"),e.defaultBaseUrl),model:o("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:o("HF_TOKEN"),baseUrl:c(o("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(o("HF_LLM_MODEL"),o("HF_MODEL"))};case"ollama":return{provider:r,apiKey:o("OLLAMA_API_KEY"),baseUrl:c(o("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:o("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:o("CLOUDFLARE_ACCOUNT_ID"),apiKey:o("CLOUDFLARE_API_TOKEN"),baseUrl:o("CLOUDFLARE_AI_BASE_URL"),model:o("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:o("CUSTOM_AI_API_KEY"),baseUrl:o("CUSTOM_AI_BASE_URL"),model:o("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(o("OPENAI_API_KEY"),o("MODEL_API_KEY")),baseUrl:c(o("OPENAI_BASE_URL"),o("MODEL_BASE_URL")),model:c(o("OPENAI_MODEL"),o("MODEL_NAME"))}}}function X(){let r=o("TOOLNET_LLM_PROVIDER"),e=r&&A(r)?r:B(),t=g(e),n=v(e);return{provider:e,apiKey:c(o("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:c(o("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:c(o("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:c(o("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function ee(){let r=o("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&A(r)?r:o("HF_TOKEN")||o("HF_EMBEDDING_MODEL")?"huggingface":"local"}function te(){let r=ee();if(r==="local")return{provider:"local",model:c(o("TOOLNET_EMBEDDING_MODEL"),o("LOCAL_EMBEDDING_MODEL"))};let e=g(r),t,n,s,a;switch(r){case"huggingface":t=o("HF_TOKEN"),n=o("HF_INFERENCE_BASE_URL"),s=o("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=o("OPENAI_API_KEY"),n=o("OPENAI_BASE_URL"),s=o("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=o("CLOUDFLARE_API_TOKEN"),n=o("CLOUDFLARE_AI_BASE_URL"),s=o("CLOUDFLARE_EMBEDDING_MODEL"),a=o("CLOUDFLARE_ACCOUNT_ID");break;default:t=v(r).apiKey,n=v(r).baseUrl,s=o(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let i=c(o("TOOLNET_EMBEDDING_ACCOUNT_ID"),a),l=c(o("TOOLNET_EMBEDDING_BASE_URL"),n,e.defaultBaseUrl),u=r==="cloudflare"&&!l&&i?`https://api.cloudflare.com/client/v4/accounts/${i}/ai/v1`:l;return{provider:r,apiKey:c(o("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:u,model:c(o("TOOLNET_EMBEDDING_MODEL"),s),accountId:i}}function C(){let r=X(),e=te();return{llm:r,embedding:e,legacy:{llm:!o("TOOLNET_LLM_PROVIDER")&&!!F(),embedding:!o("TOOLNET_EMBEDDING_PROVIDER")&&!!(o("HF_TOKEN")||o("HF_EMBEDDING_MODEL"))}}}function $(r=B()){let e=C().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=v(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function k(r,e){return o(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function G(){let r=[];for(let e of[1,2]){let t=k(e,"PROVIDER");if(!t||!A(t))continue;let n=g(t);r.push({slot:e,config:{provider:t,apiKey:k(e,"API_KEY"),baseUrl:c(k(e,"BASE_URL"),n.defaultBaseUrl),model:c(k(e,"MODEL"),n.defaultModel),accountId:k(e,"ACCOUNT_ID")}})}return r}function Y(){let r=o("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=o("TOOLNET_LLM_MAX_RETRIES"),t=Number(r??6e4),n=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(n)&&n>=0?Math.floor(n):1}}var E=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(r,e,t=3e4){let n=new AbortController,s=setTimeout(()=>n.abort(),t);s.unref?.();try{let a=await fetch(r,{...e,signal:n.signal}),i=await a.text();if(!a.ok){let l=i;try{let u=JSON.parse(i);l=u.error?.message??u.message??i}catch{}throw new E(l||`HTTP ${a.status}`,a.status)}return i.trim()?JSON.parse(i):{}}finally{clearTimeout(s)}}function _(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var O=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),n=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!n)throw new Error("cloudflare: API TOKEN is not configured");let s=this.model(),i=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${s}`,l=await y(i,{method:"POST",headers:{authorization:`Bearer ${n}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),u=l.result?.response?.trim();if(!u)throw new Error(l.errors?.[0]?.message??"cloudflare: empty model response");return{text:u,provider:"cloudflare",model:s}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var w=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let n=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",s=this.model(),a=e.messages.filter(d=>d.role==="system"),i=e.messages.filter(d=>d.role!=="system").map(d=>({role:d.role==="assistant"?"model":"user",parts:[{text:d.content}]})),l=`${_(n,`models/${encodeURIComponent(s)}:generateContent`)}?key=${encodeURIComponent(t)}`,u=await y(l,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...a.length?{systemInstruction:{parts:[{text:a.map(d=>d.content).join(`
2
2
 
3
- `)}]}}:{},contents:i,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),p=u.candidates?.[0]?.content?.parts?.map(d=>d.text??"").join("").trim();if(!p)throw new Error("gemini: empty model response");return{text:p,provider:"gemini",model:s,usage:u.usageMetadata?{inputTokens:u.usageMetadata.promptTokenCount,outputTokens:u.usageMetadata.candidatesTokenCount,totalTokens:u.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var T=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),n=await y(_(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),s=n.choices?.[0]?.message?.content?.trim();if(!s)throw new Error(`${this.id}: empty model response`);return{text:s,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function H(r=$()){switch(g(r.id).transport){case"gemini":return new w(r);case"cloudflare":return new O(r);default:return new T(r)}}function re(r){return new Promise(e=>{setTimeout(e,r)})}function ne(r){if(r instanceof E){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var S=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],n={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=n.cooldownMs??6e4,this.maxRetries=Math.max(0,n.maxRetries??1),this.providers=[e,...t].map(s=>({provider:H(s.config),label:s.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),n=this.states.get(t);return n||(n={failures:0,cooldownUntil:0},this.states.set(t,n)),n}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let n=this.state(e);n.failures+=1,n.lastError=t instanceof Error?t.message:String(t),n.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let n=0;n<this.providers.length;n+=1){if(!this.available(n)){t.push(`${this.providers[n].label}: cooldown`);continue}let s=this.providers[n];for(let a=0;a<=this.maxRetries;a+=1)try{let i=await s.provider.generate(e);return this.success(n),i}catch(i){let l=i instanceof Error?i.message:String(i),u=ne(i);if(t.push(`${s.label}: ${l}`),!u)throw i;if(a<this.maxRetries){await re(Math.min(250*2**a,2e3));continue}this.fail(n,i)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:t.provider,model:t.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,t)=>{let n=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:n.cooldownUntil>Date.now(),cooldownUntil:n.cooldownUntil||void 0,failures:n.failures,lastError:n.lastError}})}};function W(){let r=C(),e=G();return new S({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),Y())}var L=class{constructor(e=W()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function V(){return new L(W())}import{existsSync as pe,readFileSync as me}from"node:fs";import{join as fe}from"node:path";import{existsSync as oe,mkdirSync as _t,readFileSync as se,renameSync as Ot,writeFileSync as wt}from"node:fs";import{dirname as St,join as ie}from"node:path";function ae(r){return ie(r.rootPath,".toolnet","work","current.json")}function I(r){let e=ae(r);if(!oe(e))return null;try{let t=JSON.parse(se(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as ce,mkdirSync as Mt,readFileSync as le,renameSync as Pt,writeFileSync as Rt}from"node:fs";import{dirname as Lt,join as ue}from"node:path";function de(r){return ue(r.rootPath,".toolnet","context","session-origin.json")}function x(r){let e=de(r);if(!ce(e))return null;try{let t=JSON.parse(le(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ge(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function he(r){let e=ge(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),n=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return t&&n?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}function ye(r){let e=fe(r.rootPath,".toolnet","context","handoff.md");if(!pe(e))return null;try{let t=me(e,"utf8").trim();return t||null}catch{return null}}function Ae(r,e=5){return r.slice(0,e).map(t=>`- ${t}`).join(`
3
+ `)}]}}:{},contents:i,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),p=u.candidates?.[0]?.content?.parts?.map(d=>d.text??"").join("").trim();if(!p)throw new Error("gemini: empty model response");return{text:p,provider:"gemini",model:s,usage:u.usageMetadata?{inputTokens:u.usageMetadata.promptTokenCount,outputTokens:u.usageMetadata.candidatesTokenCount,totalTokens:u.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var T=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),n=await y(_(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),s=n.choices?.[0]?.message?.content?.trim();if(!s)throw new Error(`${this.id}: empty model response`);return{text:s,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function H(r=$()){switch(g(r.id).transport){case"gemini":return new w(r);case"cloudflare":return new O(r);default:return new T(r)}}function re(r){return new Promise(e=>{setTimeout(e,r)})}function ne(r){if(r instanceof E){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var S=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],n={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=n.cooldownMs??6e4,this.maxRetries=Math.max(0,n.maxRetries??1),this.providers=[e,...t].map(s=>({provider:H(s.config),label:s.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),n=this.states.get(t);return n||(n={failures:0,cooldownUntil:0},this.states.set(t,n)),n}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let n=this.state(e);n.failures+=1,n.lastError=t instanceof Error?t.message:String(t),n.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let n=0;n<this.providers.length;n+=1){if(!this.available(n)){t.push(`${this.providers[n].label}: cooldown`);continue}let s=this.providers[n];for(let a=0;a<=this.maxRetries;a+=1)try{let i=await s.provider.generate(e);return this.success(n),i}catch(i){let l=i instanceof Error?i.message:String(i),u=ne(i);if(t.push(`${s.label}: ${l}`),!u)throw i;if(a<this.maxRetries){await re(Math.min(250*2**a,2e3));continue}this.fail(n,i)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:t.provider,model:t.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,t)=>{let n=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:n.cooldownUntil>Date.now(),cooldownUntil:n.cooldownUntil||void 0,failures:n.failures,lastError:n.lastError}})}};function W(){let r=C(),e=G();return new S({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),Y())}var L=class{constructor(e=W()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function V(){return new L(W())}import{existsSync as pe,readFileSync as me}from"node:fs";import{join as fe}from"node:path";import{existsSync as oe,mkdirSync as _t,readFileSync as se,renameSync as Ot,writeFileSync as wt}from"node:fs";import{dirname as St,join as ie}from"node:path";function ae(r){return ie(r.rootPath,".toolnet","work","current.json")}function I(r){let e=ae(r);if(!oe(e))return null;try{let t=JSON.parse(se(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as ce,mkdirSync as Mt,readFileSync as le,renameSync as Pt,writeFileSync as Rt}from"node:fs";import{dirname as Lt,join as ue}from"node:path";function de(r){return ue(r.rootPath,".toolnet","context","session-origin.json")}function x(r){let e=de(r);if(!ce(e))return null;try{let t=JSON.parse(le(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ge(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function he(r){let e=ge(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),n=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return t&&n?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}function ye(r){let e=fe(r.rootPath,".toolnet","context","handoff.md");if(!pe(e))return null;try{let t=me(e,"utf8").trim();return t||null}catch{return null}}function Ae(r,e=5){return r.slice(0,e).map(t=>`- ${t}`).join(`
4
4
  `)}function N(r,e){let t=he(e),n=x(r),s=I(r);switch(t){case"previous_agent":{if(n)return{intent:t,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${n.agent}. Session: ${n.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(n?.currentTask){let i=[`Task hi\u1EC7n t\u1EA1i: ${n.currentTask}.`];return n.lastTouchedFile&&i.push(`File g\u1EA7n nh\u1EA5t: ${n.lastTouchedFile}.`),n.latestNextAction&&i.push(`Ti\u1EBFp theo: ${n.latestNextAction}.`),{intent:t,answer:i.join(" "),source:"session-origin"}}if(s?.currentTask)return{intent:t,answer:`Task hi\u1EC7n t\u1EA1i: ${s.currentTask.title} (${s.currentTask.status}).`,source:"work-state"};break}case"next_action":{let i=n?.latestNextAction??s?.nextActions?.[0];if(i)return{intent:t,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${i}.`,source:n?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let i=n?.lastTouchedFile??s?.filesTouched?.at(-1);if(i)return{intent:t,answer:`File g\u1EA7n nh\u1EA5t \u0111\u01B0\u1EE3c nh\u1EAFc ho\u1EB7c s\u1EEDa: ${i}.`,source:n?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let i=n?.latestBlocker??s?.blockers?.at(-1);return i?{intent:t,answer:`Blocker hi\u1EC7n t\u1EA1i: ${i}.`,source:n?.latestBlocker?"session-origin":"work-state"}:{intent:t,answer:"Hi\u1EC7n ToolNet ch\u01B0a ghi nh\u1EADn blocker n\xE0o.",source:s?"work-state":"none"}}case"decision":{let i=n?.latestDecision??s?.decisions?.at(-1);if(i)return{intent:t,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${i}.`,source:n?.latestDecision?"session-origin":"work-state"};break}case"completed":{let i=s?.tasks?.filter(l=>l.status==="completed").map(l=>l.title)??[];if(i.length)return{intent:t,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
5
5
  ${Ae(i,8)}`,source:"work-state"};break}case"status":{if(s){let i=[`Progress: ${s.progress.tasksCompleted}/${s.progress.tasksTotal} task ho\xE0n th\xE0nh.`];return s.currentTask&&i.push(`\u0110ang l\xE0m: ${s.currentTask.title}.`),s.progress.blocked>0&&i.push(`Blocked: ${s.progress.blocked}.`),{intent:t,answer:i.join(" "),source:"work-state"}}break}case"summary":{if(n||s){let i=[];n&&i.push(`Agent tr\u01B0\u1EDBc: ${n.agent}.`);let l=n?.currentTask??s?.currentTask?.title;l&&i.push(`Task hi\u1EC7n t\u1EA1i: ${l}.`);let u=n?.lastTouchedFile??s?.filesTouched?.at(-1);u&&i.push(`File g\u1EA7n nh\u1EA5t: ${u}.`);let p=n?.latestNextAction??s?.nextActions?.[0];p&&i.push(`Ti\u1EBFp theo: ${p}.`);let d=n?.latestBlocker??s?.blockers?.at(-1);d&&i.push(`Blocker: ${d}.`);let m=n?.latestDecision??s?.decisions?.at(-1);return m&&i.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${m}.`),{intent:t,answer:i.join(" "),source:n?"session-origin":"work-state"}}break}}let a=ye(r);if(a){let i=a.length>900?`${a.slice(0,900)}
6
6
  [truncated]`:a;return{intent:t,answer:i,source:"handoff"}}return{intent:t,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}function ke(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
@@ -41,9 +41,9 @@ ToolNet selected memory:
41
41
  ${n}
42
42
 
43
43
  Answer the coding agent directly.
44
- `.trim()}]}),i=a.text.trim();return i?{answer:i,provider:a.provider,model:a.model,usedAi:!0}:{answer:t.answer,usedAi:!1}}catch{return{answer:t.answer,usedAi:!1}}}import{existsSync as ve,readFileSync as be}from"node:fs";import{homedir as _e}from"node:os";import{join as Oe}from"node:path";function we(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
45
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Te(){let r=process.env.TOOLNET_GLOBAL_ENV??Oe(_e(),".config","toolnet-memory",".env");if(!ve(r))return;let e=be(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let a=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=we(n.slice(s+1)))}}Te();import{createHash as Se}from"node:crypto";import{existsSync as D,mkdirSync as Ie,readFileSync as xe,renameSync as Me,writeFileSync as Pe}from"node:fs";import{basename as Re,dirname as M,join as R,parse as Q,resolve as v}from"node:path";var Z=".toolnet",Ce="project.json";function Le(r){return Se("sha256").update(r).digest("hex").slice(0,16)}function U(r){return R(r,Z,Ce)}function Ne(r){return D(U(r))}function De(r,e){let t=v(r),n=Q(t).root;for(;;){if(Ne(t))return t;if(t===n||e&&t===v(e))break;let s=M(t);if(s===t)break;t=s}return null}function Ue(r){let e=v(r),t=Q(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(a=>D(R(e,a))))return e;if(e===t)break;let s=M(e);if(s===e)break;e=s}return v(r)}function je(r){let e;try{e=JSON.parse(xe(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:M(M(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function J(r,e){let t=R(r,Z);Ie(t,{recursive:!0});let n=U(r),s=`${n}.tmp-${process.pid}`;Pe(s,JSON.stringify(e,null,2)+`
46
- `,{encoding:"utf8",mode:384}),Me(s,n)}function q(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var P=class{detect(e=process.cwd()){let t=v(e),n=Ue(t),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>D(R(n,d))),i=De(t,a?n:void 0);if(i){let d=U(i),m=je(d);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),J(i,m)),q(m,i)}let l=new Date().toISOString(),u=Re(n),p={version:1,id:Le(n),name:u,remote:u,rootPath:n,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return J(n,p),q(p,n)}};async function Ke(){let r=process.argv.slice(2).join(" ").trim();if(!r){console.error('Usage: toolnet-memory ask-ai "<question>"'),process.exitCode=1;return}let e=j(process.cwd());if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new P().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=await z(t,r);process.stdout.write(`${n.answer}
44
+ `.trim()}]}),i=a.text.trim();return i?{answer:i,provider:a.provider,model:a.model,usedAi:!0}:{answer:t.answer,usedAi:!1}}catch{return{answer:t.answer,usedAi:!1}}}import{existsSync as be,readFileSync as ve}from"node:fs";import{homedir as _e}from"node:os";import{join as Oe}from"node:path";function we(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
45
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Te(){let r=process.env.TOOLNET_GLOBAL_ENV??Oe(_e(),".config","toolnet-memory",".env");if(!be(r))return;let e=ve(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let a=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=we(n.slice(s+1)))}}Te();import{createHash as Se}from"node:crypto";import{existsSync as D,mkdirSync as Ie,readFileSync as xe,renameSync as Me,writeFileSync as Pe}from"node:fs";import{basename as Re,dirname as M,join as R,parse as Q,resolve as b}from"node:path";var Z=".toolnet",Ce="project.json";function Le(r){return Se("sha256").update(r).digest("hex").slice(0,16)}function U(r){return R(r,Z,Ce)}function Ne(r){return D(U(r))}function De(r,e){let t=b(r),n=Q(t).root;for(;;){if(Ne(t))return t;if(t===n||e&&t===b(e))break;let s=M(t);if(s===t)break;t=s}return null}function Ue(r){let e=b(r),t=Q(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(a=>D(R(e,a))))return e;if(e===t)break;let s=M(e);if(s===e)break;e=s}return b(r)}function je(r){let e;try{e=JSON.parse(xe(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:M(M(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function J(r,e){let t=R(r,Z);Ie(t,{recursive:!0});let n=U(r),s=`${n}.tmp-${process.pid}`;Pe(s,JSON.stringify(e,null,2)+`
46
+ `,{encoding:"utf8",mode:384}),Me(s,n)}function q(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var P=class{detect(e=process.cwd()){let t=b(e),n=Ue(t),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>D(R(n,d))),i=De(t,a?n:void 0);if(i){let d=U(i),m=je(d);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),J(i,m)),q(m,i)}let l=new Date().toISOString(),u=Re(n),p={version:1,id:Le(n),name:u,remote:u,rootPath:n,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return J(n,p),q(p,n)}};async function Ke(){let r=process.argv.slice(2).join(" ").trim();if(!r){console.error('Usage: toolnet-memory ask-ai "<question>"'),process.exitCode=1;return}let e=j(process.cwd());if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new P().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=await z(t,r);process.stdout.write(`${n.answer}
47
47
  `),process.env.TOOLNET_MEMORY_AGENT_DEBUG==="1"&&process.stderr.write(["",`[ToolNet Memory Agent] AI: ${n.usedAi?"yes":"fallback"}`,n.provider?`Provider: ${n.provider}`:"",n.model?`Model: ${n.model}`:""].filter(Boolean).join(`
48
48
  `)+`
49
49
  `)}Ke().catch(r=>{console.error(r instanceof Error?r.message:String(r)),process.exitCode=1});
@@ -1,3 +1,3 @@
1
1
  import"dotenv/config";var f=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function u(e){let o=f.find(r=>r.id===e);if(!o)throw new Error(`Unsupported AI provider: ${e}`);return o}function E(e){return f.some(o=>o.id===e)}function n(e){return process.env[e]?.trim()||void 0}function a(...e){return e.find(o=>!!o?.trim())}function M(){if(n("GROQ_API_KEY"))return"groq";if(n("DEEPSEEK_API_KEY"))return"deepseek";if(n("NVIDIA_API_KEY")||n("NVIDIA_NIM_API_KEY"))return"nvidia";if(n("OPENROUTER_API_KEY"))return"openrouter";if(n("ALIBABA_API_KEY")||n("DASHSCOPE_API_KEY"))return"alibaba";if(n("GEMINI_API_KEY")||n("GOOGLE_API_KEY"))return"gemini";if(n("CLOUDFLARE_API_TOKEN")&&n("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(n("HF_TOKEN"))return"huggingface";if(n("OLLAMA_MODEL")||n("OLLAMA_BASE_URL"))return"ollama"}function w(){let e=n("TOOLNET_LLM_PROVIDER");return e&&E(e)?e:M()??"openai-compatible"}function b(e){let o=u(e);switch(e){case"alibaba":return{provider:e,apiKey:a(n("ALIBABA_API_KEY"),n("DASHSCOPE_API_KEY")),baseUrl:a(n("ALIBABA_BASE_URL"),n("DASHSCOPE_BASE_URL"),o.defaultBaseUrl),model:a(n("ALIBABA_MODEL"),n("DASHSCOPE_MODEL"))};case"openrouter":return{provider:e,apiKey:n("OPENROUTER_API_KEY"),baseUrl:a(n("OPENROUTER_BASE_URL"),o.defaultBaseUrl),model:n("OPENROUTER_MODEL")};case"groq":return{provider:e,apiKey:n("GROQ_API_KEY"),baseUrl:a(n("GROQ_BASE_URL"),o.defaultBaseUrl),model:n("GROQ_MODEL")};case"deepseek":return{provider:e,apiKey:n("DEEPSEEK_API_KEY"),baseUrl:a(n("DEEPSEEK_BASE_URL"),o.defaultBaseUrl),model:a(n("DEEPSEEK_MODEL"),o.defaultModel)};case"nvidia":return{provider:e,apiKey:a(n("NVIDIA_API_KEY"),n("NVIDIA_NIM_API_KEY")),baseUrl:a(n("NVIDIA_BASE_URL"),n("NVIDIA_NIM_BASE_URL"),o.defaultBaseUrl),model:a(n("NVIDIA_MODEL"),n("NVIDIA_NIM_MODEL"),o.defaultModel)};case"gemini":return{provider:e,apiKey:a(n("GEMINI_API_KEY"),n("GOOGLE_API_KEY")),baseUrl:a(n("GEMINI_BASE_URL"),o.defaultBaseUrl),model:n("GEMINI_MODEL")};case"huggingface":return{provider:e,apiKey:n("HF_TOKEN"),baseUrl:a(n("HF_INFERENCE_BASE_URL"),o.defaultBaseUrl),model:a(n("HF_LLM_MODEL"),n("HF_MODEL"))};case"ollama":return{provider:e,apiKey:n("OLLAMA_API_KEY"),baseUrl:a(n("OLLAMA_BASE_URL"),o.defaultBaseUrl),model:n("OLLAMA_MODEL")};case"cloudflare":return{provider:e,accountId:n("CLOUDFLARE_ACCOUNT_ID"),apiKey:n("CLOUDFLARE_API_TOKEN"),baseUrl:n("CLOUDFLARE_AI_BASE_URL"),model:n("CLOUDFLARE_MODEL")};case"custom":return{provider:e,apiKey:n("CUSTOM_AI_API_KEY"),baseUrl:n("CUSTOM_AI_BASE_URL"),model:n("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:a(n("OPENAI_API_KEY"),n("MODEL_API_KEY")),baseUrl:a(n("OPENAI_BASE_URL"),n("MODEL_BASE_URL")),model:a(n("OPENAI_MODEL"),n("MODEL_NAME"))}}}function k(){let e=n("TOOLNET_LLM_PROVIDER"),o=e&&E(e)?e:w(),r=u(o),t=b(o);return{provider:o,apiKey:a(n("TOOLNET_LLM_API_KEY"),t.apiKey),baseUrl:a(n("TOOLNET_LLM_BASE_URL"),t.baseUrl,r.defaultBaseUrl),model:a(n("TOOLNET_LLM_MODEL"),t.model,r.defaultModel),accountId:a(n("TOOLNET_LLM_ACCOUNT_ID"),t.accountId)}}function $(){let e=n("TOOLNET_EMBEDDING_PROVIDER");return e==="local"?"local":e&&E(e)?e:n("HF_TOKEN")||n("HF_EMBEDDING_MODEL")?"huggingface":"local"}function S(){let e=$();if(e==="local")return{provider:"local",model:a(n("TOOLNET_EMBEDDING_MODEL"),n("LOCAL_EMBEDDING_MODEL"))};let o=u(e),r,t,i,s;switch(e){case"huggingface":r=n("HF_TOKEN"),t=n("HF_INFERENCE_BASE_URL"),i=n("HF_EMBEDDING_MODEL");break;case"openai-compatible":r=n("OPENAI_API_KEY"),t=n("OPENAI_BASE_URL"),i=n("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":r=n("CLOUDFLARE_API_TOKEN"),t=n("CLOUDFLARE_AI_BASE_URL"),i=n("CLOUDFLARE_EMBEDDING_MODEL"),s=n("CLOUDFLARE_ACCOUNT_ID");break;default:r=b(e).apiKey,t=b(e).baseUrl,i=n(`${e.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let l=a(n("TOOLNET_EMBEDDING_ACCOUNT_ID"),s),d=a(n("TOOLNET_EMBEDDING_BASE_URL"),t,o.defaultBaseUrl),c=e==="cloudflare"&&!d&&l?`https://api.cloudflare.com/client/v4/accounts/${l}/ai/v1`:d;return{provider:e,apiKey:a(n("TOOLNET_EMBEDDING_API_KEY"),r),baseUrl:c,model:a(n("TOOLNET_EMBEDDING_MODEL"),i),accountId:l}}function p(){let e=k(),o=S();return{llm:e,embedding:o,legacy:{llm:!n("TOOLNET_LLM_PROVIDER")&&!!M(),embedding:!n("TOOLNET_EMBEDDING_PROVIDER")&&!!(n("HF_TOKEN")||n("HF_EMBEDDING_MODEL"))}}}function R(e=w()){let o=p().llm;if(e===o.provider)return{id:e,apiKey:o.apiKey,baseUrl:o.baseUrl,model:o.model,accountId:o.accountId};let r=b(e);return{id:e,apiKey:r.apiKey,baseUrl:r.baseUrl,model:r.model,accountId:r.accountId}}var P=class extends Error{status;constructor(o,r){super(o),this.name="AiHttpError",this.status=r}};async function g(e,o,r=3e4){let t=new AbortController,i=setTimeout(()=>t.abort(),r);i.unref?.();try{let s=await fetch(e,{...o,signal:t.signal}),l=await s.text();if(!s.ok){let d=l;try{let c=JSON.parse(l);d=c.error?.message??c.message??l}catch{}throw new P(d||`HTTP ${s.status}`,s.status)}return l.trim()?JSON.parse(l):{}}finally{clearTimeout(i)}}function A(e,o){return`${e.replace(/\/+$/,"")}/${o.replace(/^\/+/,"")}`}var y=class{constructor(o){this.config=o}config;id="cloudflare";model(){let o=this.config.model?.trim();if(!o)throw new Error("cloudflare: MODEL is not configured");return o}async generate(o){let r=this.config.accountId?.trim(),t=this.config.apiKey?.trim();if(!r)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!t)throw new Error("cloudflare: API TOKEN is not configured");let i=this.model(),l=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${r}/ai/run`).replace(/\/+$/,"")}/${i}`,d=await g(l,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens})}),c=d.result?.response?.trim();if(!c)throw new Error(d.errors?.[0]?.message??"cloudflare: empty model response");return{text:c,provider:"cloudflare",model:i}}async healthCheck(){let o=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(r){return{ok:!1,provider:"cloudflare",model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};var _=class{constructor(o){this.config=o}config;id="gemini";model(){let o=this.config.model?.trim();if(!o)throw new Error("gemini: MODEL is not configured");return o.replace(/^models\//,"")}async generate(o){let r=this.config.apiKey?.trim();if(!r)throw new Error("gemini: API KEY is not configured");let t=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",i=this.model(),s=o.messages.filter(m=>m.role==="system"),l=o.messages.filter(m=>m.role!=="system").map(m=>({role:m.role==="assistant"?"model":"user",parts:[{text:m.content}]})),d=`${A(t,`models/${encodeURIComponent(i)}:generateContent`)}?key=${encodeURIComponent(r)}`,c=await g(d,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...s.length?{systemInstruction:{parts:[{text:s.map(m=>m.content).join(`
2
2
 
3
- `)}]}}:{},contents:l,generationConfig:{temperature:o.temperature,maxOutputTokens:o.maxTokens}})}),D=c.candidates?.[0]?.content?.parts?.map(m=>m.text??"").join("").trim();if(!D)throw new Error("gemini: empty model response");return{text:D,provider:"gemini",model:i,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let o=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(r){return{ok:!1,provider:"gemini",model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};var h=class{constructor(o){this.config=o;this.id=o.id}config;id;baseUrl(){let o=this.config.baseUrl?.trim();if(!o)throw new Error(`${this.id}: BASE URL is not configured`);return o}model(){let o=this.config.model?.trim();if(!o)throw new Error(`${this.id}: MODEL is not configured`);return o}headers(){let o={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(o.authorization=`Bearer ${this.config.apiKey}`),o}async generate(o){let r=this.model(),t=await g(A(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:r,messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens})}),i=t.choices?.[0]?.message?.content?.trim();if(!i)throw new Error(`${this.id}: empty model response`);return{text:i,provider:this.id,model:r,usage:t.usage?{inputTokens:t.usage.prompt_tokens,outputTokens:t.usage.completion_tokens,totalTokens:t.usage.total_tokens}:void 0}}async healthCheck(){let o=Date.now();try{let r=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:r.model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(r){return{ok:!1,provider:this.id,model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};function N(e=R()){switch(u(e.id).transport){case"gemini":return new _(e);case"cloudflare":return new y(e);default:return new h(e)}}var v=class{constructor(o){this.options=o}options;name="gemini";async embed(o){let r=this.options.model.replace(/^models\//,""),i=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(r)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,s=await fetch(i,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${r}`,content:{parts:[{text:o}]}})});if(!s.ok)throw new Error(`Gemini embedding failed: ${s.status} ${await s.text()}`);let d=(await s.json()).embedding?.values;if(!Array.isArray(d)||d.length===0)throw new Error("Gemini embedding returned invalid response");return d}async embedMany(o){let r=[];for(let t of o)r.push(await this.embed(t));return r}};import{createHash as x}from"node:crypto";var O=class{name="hash-fallback";dimensions=128;async embed(o){let r=new Array(this.dimensions).fill(0),t=o.toLowerCase().split(/\s+/).filter(Boolean);for(let i of t){let l=x("sha256").update(i).digest().readUInt32BE(0)%this.dimensions;r[l]+=1}return G(r)}async embedMany(o){return Promise.all(o.map(r=>this.embed(r)))}};function G(e){let o=Math.sqrt(e.reduce((r,t)=>r+t*t,0));return o===0?e:e.map(r=>r/o)}var I=class{constructor(o){this.options=o;this.dimensions=o.dimensions}options;name="openai-compatible";dimensions;async embed(o){let[r]=await this.embedMany([o]);return r}async embedMany(o){if(o.length===0)return[];let r=this.options.baseUrl.replace(/\/+$/,""),t=await fetch(`${r}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:o})});if(!t.ok)throw new Error(`Embedding failed: ${t.status} ${await t.text()}`);let s=(await t.json()).data?.sort((l,d)=>(l.index??0)-(d.index??0)).map(l=>l.embedding);if(!s||s.length!==o.length||s.some(l=>!Array.isArray(l)))throw new Error("Embedding provider returned invalid response");return s}};var L=class{constructor(o){this.options=o}options;name="huggingface";dimensions=384;async embed(o){let[r]=await this.embedMany([o]);return r}async embedMany(o){if(o.length===0)return[];let r=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,t=await fetch(r,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:o,options:{wait_for_model:!0}})});if(!t.ok)throw new Error(`HF embedding failed: ${t.status} ${await t.text()}`);let i=await t.json();if(!Array.isArray(i))throw new Error("HF embedding returned invalid response");return i.map(s=>F(s))}};function F(e){if(!Array.isArray(e))throw new Error("Invalid embedding");if(e.length>0&&typeof e[0]=="number")return e;if(e.length>0&&Array.isArray(e[0])){let o=e;if(o.length===0)return[];let r=o[0].length,t=new Array(r).fill(0);for(let i of o)for(let s=0;s<r;s++)t[s]+=i[s]??0;for(let i=0;i<r;i++)t[i]/=o.length;return t}throw new Error("Unsupported embedding shape")}var U=class{constructor(o,r=new O){this.primary=o;this.fallback=r}primary;fallback;name="resilient";async embed(o){if(this.primary)try{return await this.primary.embed(o)}catch(r){console.warn("[embedding] primary failed, fallback enabled:",r instanceof Error?r.message:r)}return this.fallback.embed(o)}async embedMany(o){if(this.primary)try{return await this.primary.embedMany(o)}catch(r){console.warn("[embedding] primary failed, fallback enabled:",r instanceof Error?r.message:r)}return this.fallback.embedMany(o)}};function H(e){return`https://api.cloudflare.com/client/v4/accounts/${e}/ai/v1`}function Y(){let e=p().embedding;if(e.provider==="local")return null;if(e.provider==="huggingface")return!e.apiKey||!e.model?null:new L({token:e.apiKey,model:e.model});if(e.provider==="gemini")return!e.apiKey||!e.model?null:new v({apiKey:e.apiKey,model:e.model,baseUrl:e.baseUrl});let o=e.baseUrl;return e.provider==="cloudflare"&&!o&&e.accountId&&(o=H(e.accountId)),o&&e.model?new I({apiKey:e.apiKey,baseUrl:o,model:e.model}):null}function T(){return new U(Y())}function K(e){return e?e.length<=8?"********":`${e.slice(0,4)}...${e.slice(-4)}`:"not configured"}function j(){console.log(""),console.log("ToolNet AI Providers"),console.log("===================="),console.log("");for(let e of f)console.log(`- ${e.label}`),console.log(` id : ${e.id}`),console.log(` protocol : ${e.transport}`),e.defaultBaseUrl&&console.log(` base URL : ${e.defaultBaseUrl}`),e.defaultModel&&console.log(` model : ${e.defaultModel}`),console.log("");console.log("- Local / Hash embedding"),console.log(" id : local"),console.log(" protocol : local"),console.log("")}function q(){let e=p();console.log(""),console.log("ToolNet Provider Status"),console.log("======================="),console.log(""),console.log("LLM"),console.log(` Provider : ${e.llm.provider}`),console.log(` Model : ${e.llm.model??"not configured"}`),console.log(` Base URL : ${e.llm.baseUrl??"default/provider native"}`),console.log(` API Key : ${K(e.llm.apiKey)}`),e.llm.accountId&&console.log(` Account : ${e.llm.accountId}`),console.log(` Legacy : ${e.legacy.llm?"yes":"no"}`),console.log(""),console.log("Embedding"),console.log(` Provider : ${e.embedding.provider}`),console.log(` Model : ${e.embedding.model??(e.embedding.provider==="local"?"local hash":"not configured")}`),console.log(` Base URL : ${e.embedding.baseUrl??(e.embedding.provider==="local"?"local":"default/provider native")}`),console.log(` API Key : ${e.embedding.provider==="local"?"not required":K(e.embedding.apiKey)}`),e.embedding.accountId&&console.log(` Account : ${e.embedding.accountId}`),console.log(` Legacy : ${e.legacy.embedding?"yes":"no"}`),console.log("")}async function C(){let e=p().llm;console.log(""),console.log("Testing LLM"),console.log("-----------"),console.log(`Provider : ${e.provider}`),console.log(`Model : ${e.model??"not configured"}`);try{let r=await N({id:e.provider,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId}).healthCheck();return r.ok?(console.log("\u2713 Provider reachable"),r.latencyMs!==void 0&&console.log(`\u2713 Latency: ${r.latencyMs} ms`),console.log(""),!0):(console.log(`\u2717 ${r.message}`),!1)}catch(o){return console.log(`\u2717 ${o instanceof Error?o.message:String(o)}`),console.log(""),!1}}async function B(){let e=p().embedding;console.log(""),console.log("Testing Embedding"),console.log("-----------------"),console.log(`Provider : ${e.provider}`),console.log(`Model : ${e.model??(e.provider==="local"?"local hash":"not configured")}`);try{let r=await T().embed("ToolNet Memory provider health check");if(!Array.isArray(r)||r.length===0)throw new Error("Empty embedding vector");return console.log("\u2713 Embedding ready"),console.log(`\u2713 Dimensions: ${r.length}`),console.log(""),!0}catch(o){return console.log(`\u2717 ${o instanceof Error?o.message:String(o)}`),console.log(""),!1}}async function V(){let e=await C(),o=await B();return console.log(""),console.log("Provider Test Summary"),console.log("====================="),console.log(`LLM : ${e?"READY":"FAILED"}`),console.log(`Embedding : ${o?"READY":"FAILED"}`),console.log(""),e&&o}async function J(){let e=process.argv[2]??"status";if(e==="list"){j();return}if(e==="status"){q();return}if(e==="test"){let o=process.argv[3]??"all",r=!1;o==="llm"?r=await C():o==="embedding"?r=await B():r=await V(),process.exitCode=r?0:1;return}console.error(`Unknown provider command: ${e}`),console.error(""),console.error("Usage:"),console.error(" toolnet-memory provider:list"),console.error(" toolnet-memory provider:status"),console.error(" toolnet-memory provider:test"),console.error(" toolnet-memory provider:test llm"),console.error(" toolnet-memory provider:test embedding"),process.exitCode=1}J().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});
3
+ `)}]}}:{},contents:l,generationConfig:{temperature:o.temperature,maxOutputTokens:o.maxTokens}})}),D=c.candidates?.[0]?.content?.parts?.map(m=>m.text??"").join("").trim();if(!D)throw new Error("gemini: empty model response");return{text:D,provider:"gemini",model:i,usage:c.usageMetadata?{inputTokens:c.usageMetadata.promptTokenCount,outputTokens:c.usageMetadata.candidatesTokenCount,totalTokens:c.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let o=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(r){return{ok:!1,provider:"gemini",model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};var h=class{constructor(o){this.config=o;this.id=o.id}config;id;baseUrl(){let o=this.config.baseUrl?.trim();if(!o)throw new Error(`${this.id}: BASE URL is not configured`);return o}model(){let o=this.config.model?.trim();if(!o)throw new Error(`${this.id}: MODEL is not configured`);return o}headers(){let o={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(o.authorization=`Bearer ${this.config.apiKey}`),o}async generate(o){let r=this.model(),t=await g(A(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:r,messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),i=t.choices?.[0]?.message?.content?.trim();if(!i)throw new Error(`${this.id}: empty model response`);return{text:i,provider:this.id,model:r,usage:t.usage?{inputTokens:t.usage.prompt_tokens,outputTokens:t.usage.completion_tokens,totalTokens:t.usage.total_tokens}:void 0}}async healthCheck(){let o=Date.now();try{let r=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:r.model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(r){return{ok:!1,provider:this.id,model:this.config.model,message:r instanceof Error?r.message:String(r),latencyMs:Date.now()-o}}}};function N(e=R()){switch(u(e.id).transport){case"gemini":return new _(e);case"cloudflare":return new y(e);default:return new h(e)}}var v=class{constructor(o){this.options=o}options;name="gemini";async embed(o){let r=this.options.model.replace(/^models\//,""),i=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(r)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,s=await fetch(i,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${r}`,content:{parts:[{text:o}]}})});if(!s.ok)throw new Error(`Gemini embedding failed: ${s.status} ${await s.text()}`);let d=(await s.json()).embedding?.values;if(!Array.isArray(d)||d.length===0)throw new Error("Gemini embedding returned invalid response");return d}async embedMany(o){let r=[];for(let t of o)r.push(await this.embed(t));return r}};import{createHash as x}from"node:crypto";var O=class{name="hash-fallback";dimensions=128;async embed(o){let r=new Array(this.dimensions).fill(0),t=o.toLowerCase().split(/\s+/).filter(Boolean);for(let i of t){let l=x("sha256").update(i).digest().readUInt32BE(0)%this.dimensions;r[l]+=1}return G(r)}async embedMany(o){return Promise.all(o.map(r=>this.embed(r)))}};function G(e){let o=Math.sqrt(e.reduce((r,t)=>r+t*t,0));return o===0?e:e.map(r=>r/o)}var I=class{constructor(o){this.options=o;this.dimensions=o.dimensions}options;name="openai-compatible";dimensions;async embed(o){let[r]=await this.embedMany([o]);return r}async embedMany(o){if(o.length===0)return[];let r=this.options.baseUrl.replace(/\/+$/,""),t=await fetch(`${r}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:o})});if(!t.ok)throw new Error(`Embedding failed: ${t.status} ${await t.text()}`);let s=(await t.json()).data?.sort((l,d)=>(l.index??0)-(d.index??0)).map(l=>l.embedding);if(!s||s.length!==o.length||s.some(l=>!Array.isArray(l)))throw new Error("Embedding provider returned invalid response");return s}};var L=class{constructor(o){this.options=o}options;name="huggingface";dimensions=384;async embed(o){let[r]=await this.embedMany([o]);return r}async embedMany(o){if(o.length===0)return[];let r=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,t=await fetch(r,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:o,options:{wait_for_model:!0}})});if(!t.ok)throw new Error(`HF embedding failed: ${t.status} ${await t.text()}`);let i=await t.json();if(!Array.isArray(i))throw new Error("HF embedding returned invalid response");return i.map(s=>F(s))}};function F(e){if(!Array.isArray(e))throw new Error("Invalid embedding");if(e.length>0&&typeof e[0]=="number")return e;if(e.length>0&&Array.isArray(e[0])){let o=e;if(o.length===0)return[];let r=o[0].length,t=new Array(r).fill(0);for(let i of o)for(let s=0;s<r;s++)t[s]+=i[s]??0;for(let i=0;i<r;i++)t[i]/=o.length;return t}throw new Error("Unsupported embedding shape")}var U=class{constructor(o,r=new O){this.primary=o;this.fallback=r}primary;fallback;name="resilient";async embed(o){if(this.primary)try{return await this.primary.embed(o)}catch(r){console.warn("[embedding] primary failed, fallback enabled:",r instanceof Error?r.message:r)}return this.fallback.embed(o)}async embedMany(o){if(this.primary)try{return await this.primary.embedMany(o)}catch(r){console.warn("[embedding] primary failed, fallback enabled:",r instanceof Error?r.message:r)}return this.fallback.embedMany(o)}};function H(e){return`https://api.cloudflare.com/client/v4/accounts/${e}/ai/v1`}function Y(){let e=p().embedding;if(e.provider==="local")return null;if(e.provider==="huggingface")return!e.apiKey||!e.model?null:new L({token:e.apiKey,model:e.model});if(e.provider==="gemini")return!e.apiKey||!e.model?null:new v({apiKey:e.apiKey,model:e.model,baseUrl:e.baseUrl});let o=e.baseUrl;return e.provider==="cloudflare"&&!o&&e.accountId&&(o=H(e.accountId)),o&&e.model?new I({apiKey:e.apiKey,baseUrl:o,model:e.model}):null}function T(){return new U(Y())}function K(e){return e?e.length<=8?"********":`${e.slice(0,4)}...${e.slice(-4)}`:"not configured"}function j(){console.log(""),console.log("ToolNet AI Providers"),console.log("===================="),console.log("");for(let e of f)console.log(`- ${e.label}`),console.log(` id : ${e.id}`),console.log(` protocol : ${e.transport}`),e.defaultBaseUrl&&console.log(` base URL : ${e.defaultBaseUrl}`),e.defaultModel&&console.log(` model : ${e.defaultModel}`),console.log("");console.log("- Local / Hash embedding"),console.log(" id : local"),console.log(" protocol : local"),console.log("")}function q(){let e=p();console.log(""),console.log("ToolNet Provider Status"),console.log("======================="),console.log(""),console.log("LLM"),console.log(` Provider : ${e.llm.provider}`),console.log(` Model : ${e.llm.model??"not configured"}`),console.log(` Base URL : ${e.llm.baseUrl??"default/provider native"}`),console.log(` API Key : ${K(e.llm.apiKey)}`),e.llm.accountId&&console.log(` Account : ${e.llm.accountId}`),console.log(` Legacy : ${e.legacy.llm?"yes":"no"}`),console.log(""),console.log("Embedding"),console.log(` Provider : ${e.embedding.provider}`),console.log(` Model : ${e.embedding.model??(e.embedding.provider==="local"?"local hash":"not configured")}`),console.log(` Base URL : ${e.embedding.baseUrl??(e.embedding.provider==="local"?"local":"default/provider native")}`),console.log(` API Key : ${e.embedding.provider==="local"?"not required":K(e.embedding.apiKey)}`),e.embedding.accountId&&console.log(` Account : ${e.embedding.accountId}`),console.log(` Legacy : ${e.legacy.embedding?"yes":"no"}`),console.log("")}async function C(){let e=p().llm;console.log(""),console.log("Testing LLM"),console.log("-----------"),console.log(`Provider : ${e.provider}`),console.log(`Model : ${e.model??"not configured"}`);try{let r=await N({id:e.provider,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId}).healthCheck();return r.ok?(console.log("\u2713 Provider reachable"),r.latencyMs!==void 0&&console.log(`\u2713 Latency: ${r.latencyMs} ms`),console.log(""),!0):(console.log(`\u2717 ${r.message}`),!1)}catch(o){return console.log(`\u2717 ${o instanceof Error?o.message:String(o)}`),console.log(""),!1}}async function B(){let e=p().embedding;console.log(""),console.log("Testing Embedding"),console.log("-----------------"),console.log(`Provider : ${e.provider}`),console.log(`Model : ${e.model??(e.provider==="local"?"local hash":"not configured")}`);try{let r=await T().embed("ToolNet Memory provider health check");if(!Array.isArray(r)||r.length===0)throw new Error("Empty embedding vector");return console.log("\u2713 Embedding ready"),console.log(`\u2713 Dimensions: ${r.length}`),console.log(""),!0}catch(o){return console.log(`\u2717 ${o instanceof Error?o.message:String(o)}`),console.log(""),!1}}async function V(){let e=await C(),o=await B();return console.log(""),console.log("Provider Test Summary"),console.log("====================="),console.log(`LLM : ${e?"READY":"FAILED"}`),console.log(`Embedding : ${o?"READY":"FAILED"}`),console.log(""),e&&o}async function J(){let e=process.argv[2]??"status";if(e==="list"){j();return}if(e==="status"){q();return}if(e==="test"){let o=process.argv[3]??"all",r=!1;o==="llm"?r=await C():o==="embedding"?r=await B():r=await V(),process.exitCode=r?0:1;return}console.error(`Unknown provider command: ${e}`),console.error(""),console.error("Usage:"),console.error(" toolnet-memory provider:list"),console.error(" toolnet-memory provider:status"),console.error(" toolnet-memory provider:test"),console.error(" toolnet-memory provider:test llm"),console.error(" toolnet-memory provider:test embedding"),process.exitCode=1}J().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});
package/bundle/setup.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import A from"node:fs";import ne from"node:os";import P from"node:path";import vo from"node:readline/promises";import{stdin as T,stdout as b}from"node:process";import{HeadBucketCommand as Vo,S3Client as Jo}from"@aws-sdk/client-s3";var le=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function S(e){let o=le.find(t=>t.id===e);if(!o)throw new Error(`Unsupported AI provider: ${e}`);return o}function U(e){return le.some(o=>o.id===e)}function c(e){return process.env[e]?.trim()||void 0}function f(...e){return e.find(o=>!!o?.trim())}function ge(){if(c("GROQ_API_KEY"))return"groq";if(c("DEEPSEEK_API_KEY"))return"deepseek";if(c("NVIDIA_API_KEY")||c("NVIDIA_NIM_API_KEY"))return"nvidia";if(c("OPENROUTER_API_KEY"))return"openrouter";if(c("ALIBABA_API_KEY")||c("DASHSCOPE_API_KEY"))return"alibaba";if(c("GEMINI_API_KEY")||c("GOOGLE_API_KEY"))return"gemini";if(c("CLOUDFLARE_API_TOKEN")&&c("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(c("HF_TOKEN"))return"huggingface";if(c("OLLAMA_MODEL")||c("OLLAMA_BASE_URL"))return"ollama"}function de(){let e=c("TOOLNET_LLM_PROVIDER");return e&&U(e)?e:ge()??"openai-compatible"}function B(e){let o=S(e);switch(e){case"alibaba":return{provider:e,apiKey:f(c("ALIBABA_API_KEY"),c("DASHSCOPE_API_KEY")),baseUrl:f(c("ALIBABA_BASE_URL"),c("DASHSCOPE_BASE_URL"),o.defaultBaseUrl),model:f(c("ALIBABA_MODEL"),c("DASHSCOPE_MODEL"))};case"openrouter":return{provider:e,apiKey:c("OPENROUTER_API_KEY"),baseUrl:f(c("OPENROUTER_BASE_URL"),o.defaultBaseUrl),model:c("OPENROUTER_MODEL")};case"groq":return{provider:e,apiKey:c("GROQ_API_KEY"),baseUrl:f(c("GROQ_BASE_URL"),o.defaultBaseUrl),model:c("GROQ_MODEL")};case"deepseek":return{provider:e,apiKey:c("DEEPSEEK_API_KEY"),baseUrl:f(c("DEEPSEEK_BASE_URL"),o.defaultBaseUrl),model:f(c("DEEPSEEK_MODEL"),o.defaultModel)};case"nvidia":return{provider:e,apiKey:f(c("NVIDIA_API_KEY"),c("NVIDIA_NIM_API_KEY")),baseUrl:f(c("NVIDIA_BASE_URL"),c("NVIDIA_NIM_BASE_URL"),o.defaultBaseUrl),model:f(c("NVIDIA_MODEL"),c("NVIDIA_NIM_MODEL"),o.defaultModel)};case"gemini":return{provider:e,apiKey:f(c("GEMINI_API_KEY"),c("GOOGLE_API_KEY")),baseUrl:f(c("GEMINI_BASE_URL"),o.defaultBaseUrl),model:c("GEMINI_MODEL")};case"huggingface":return{provider:e,apiKey:c("HF_TOKEN"),baseUrl:f(c("HF_INFERENCE_BASE_URL"),o.defaultBaseUrl),model:f(c("HF_LLM_MODEL"),c("HF_MODEL"))};case"ollama":return{provider:e,apiKey:c("OLLAMA_API_KEY"),baseUrl:f(c("OLLAMA_BASE_URL"),o.defaultBaseUrl),model:c("OLLAMA_MODEL")};case"cloudflare":return{provider:e,accountId:c("CLOUDFLARE_ACCOUNT_ID"),apiKey:c("CLOUDFLARE_API_TOKEN"),baseUrl:c("CLOUDFLARE_AI_BASE_URL"),model:c("CLOUDFLARE_MODEL")};case"custom":return{provider:e,apiKey:c("CUSTOM_AI_API_KEY"),baseUrl:c("CUSTOM_AI_BASE_URL"),model:c("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:f(c("OPENAI_API_KEY"),c("MODEL_API_KEY")),baseUrl:f(c("OPENAI_BASE_URL"),c("MODEL_BASE_URL")),model:f(c("OPENAI_MODEL"),c("MODEL_NAME"))}}}function Je(){let e=c("TOOLNET_LLM_PROVIDER"),o=e&&U(e)?e:de(),t=S(o),n=B(o);return{provider:o,apiKey:f(c("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:f(c("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:f(c("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:f(c("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function We(){let e=c("TOOLNET_EMBEDDING_PROVIDER");return e==="local"?"local":e&&U(e)?e:c("HF_TOKEN")||c("HF_EMBEDDING_MODEL")?"huggingface":"local"}function Xe(){let e=We();if(e==="local")return{provider:"local",model:f(c("TOOLNET_EMBEDDING_MODEL"),c("LOCAL_EMBEDDING_MODEL"))};let o=S(e),t,n,r,i;switch(e){case"huggingface":t=c("HF_TOKEN"),n=c("HF_INFERENCE_BASE_URL"),r=c("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=c("OPENAI_API_KEY"),n=c("OPENAI_BASE_URL"),r=c("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=c("CLOUDFLARE_API_TOKEN"),n=c("CLOUDFLARE_AI_BASE_URL"),r=c("CLOUDFLARE_EMBEDDING_MODEL"),i=c("CLOUDFLARE_ACCOUNT_ID");break;default:t=B(e).apiKey,n=B(e).baseUrl,r=c(`${e.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let s=f(c("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),a=f(c("TOOLNET_EMBEDDING_BASE_URL"),n,o.defaultBaseUrl),l=e==="cloudflare"&&!a&&s?`https://api.cloudflare.com/client/v4/accounts/${s}/ai/v1`:a;return{provider:e,apiKey:f(c("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:l,model:f(c("TOOLNET_EMBEDDING_MODEL"),r),accountId:s}}function ze(){let e=Je(),o=Xe();return{llm:e,embedding:o,legacy:{llm:!c("TOOLNET_LLM_PROVIDER")&&!!ge(),embedding:!c("TOOLNET_EMBEDDING_PROVIDER")&&!!(c("HF_TOKEN")||c("HF_EMBEDDING_MODEL"))}}}function Ee(e=de()){let o=ze().llm;if(e===o.provider)return{id:e,apiKey:o.apiKey,baseUrl:o.baseUrl,model:o.model,accountId:o.accountId};let t=B(e);return{id:e,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}var v=class extends Error{status;constructor(o,t){super(o),this.name="AiHttpError",this.status=t}};async function R(e,o,t=3e4){let n=new AbortController,r=setTimeout(()=>n.abort(),t);r.unref?.();try{let i=await fetch(e,{...o,signal:n.signal}),s=await i.text();if(!i.ok){let a=s;try{let l=JSON.parse(s);a=l.error?.message??l.message??s}catch{}throw new v(a||`HTTP ${i.status}`,i.status)}return s.trim()?JSON.parse(s):{}}finally{clearTimeout(r)}}function w(e,o){return`${e.replace(/\/+$/,"")}/${o.replace(/^\/+/,"")}`}var k=class{constructor(o){this.config=o}config;id="cloudflare";model(){let o=this.config.model?.trim();if(!o)throw new Error("cloudflare: MODEL is not configured");return o}async generate(o){let t=this.config.accountId?.trim(),n=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!n)throw new Error("cloudflare: API TOKEN is not configured");let r=this.model(),s=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${r}`,a=await R(s,{method:"POST",headers:{authorization:`Bearer ${n}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens})}),l=a.result?.response?.trim();if(!l)throw new Error(a.errors?.[0]?.message??"cloudflare: empty model response");return{text:l,provider:"cloudflare",model:r}}async healthCheck(){let o=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-o}}}};var Y=class{constructor(o){this.config=o}config;id="gemini";model(){let o=this.config.model?.trim();if(!o)throw new Error("gemini: MODEL is not configured");return o.replace(/^models\//,"")}async generate(o){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let n=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",r=this.model(),i=o.messages.filter(E=>E.role==="system"),s=o.messages.filter(E=>E.role!=="system").map(E=>({role:E.role==="assistant"?"model":"user",parts:[{text:E.content}]})),a=`${w(n,`models/${encodeURIComponent(r)}:generateContent`)}?key=${encodeURIComponent(t)}`,l=await R(a,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(E=>E.content).join(`
2
2
 
3
- `)}]}}:{},contents:s,generationConfig:{temperature:o.temperature,maxOutputTokens:o.maxTokens}})}),g=l.candidates?.[0]?.content?.parts?.map(E=>E.text??"").join("").trim();if(!g)throw new Error("gemini: empty model response");return{text:g,provider:"gemini",model:r,usage:l.usageMetadata?{inputTokens:l.usageMetadata.promptTokenCount,outputTokens:l.usageMetadata.candidatesTokenCount,totalTokens:l.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let o=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-o}}}};var $=class{constructor(o){this.config=o;this.id=o.id}config;id;baseUrl(){let o=this.config.baseUrl?.trim();if(!o)throw new Error(`${this.id}: BASE URL is not configured`);return o}model(){let o=this.config.model?.trim();if(!o)throw new Error(`${this.id}: MODEL is not configured`);return o}headers(){let o={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(o.authorization=`Bearer ${this.config.apiKey}`),o}async generate(o){let t=this.model(),n=await R(w(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens})}),r=n.choices?.[0]?.message?.content?.trim();if(!r)throw new Error(`${this.id}: empty model response`);return{text:r,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.usage.total_tokens}:void 0}}async healthCheck(){let o=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-o}}}};function _e(e=Ee()){switch(S(e.id).transport){case"gemini":return new Y(e);case"cloudflare":return new k(e);default:return new $(e)}}import{existsSync as z}from"node:fs";import{homedir as Q}from"node:os";import{join as Z}from"node:path";import{spawnSync as $o}from"node:child_process";import{existsSync as Qe,mkdirSync as Ze,readFileSync as eo,writeFileSync as oo}from"node:fs";import{homedir as to}from"node:os";import{dirname as no,join as ro}from"node:path";function io(e){return`'${e.replace(/'/g,"'\\''")}'`}function Oe(e={}){let o=e.hooksFile??ro(to(),".gemini","config","hooks.json");Ze(no(o),{recursive:!0});let t={};if(Qe(o))try{t=JSON.parse(eo(o,"utf8"))}catch(i){throw new Error(`Invalid existing Agy hooks.json: ${i instanceof Error?i.message:String(i)}`)}let n=e.binary??"toolnet-memory",r=`${io(n)} session:agy-hook`;return t["toolnet-memory"]={enabled:!0,PreInvocation:[{type:"command",command:`${r} pre`,timeout:15}],PostInvocation:[{type:"command",command:`${r} post`,timeout:15}],Stop:[{type:"command",command:`${r} stop`,timeout:30}]},oo(o,JSON.stringify(t,null,2)+`
3
+ `)}]}}:{},contents:s,generationConfig:{temperature:o.temperature,maxOutputTokens:o.maxTokens}})}),g=l.candidates?.[0]?.content?.parts?.map(E=>E.text??"").join("").trim();if(!g)throw new Error("gemini: empty model response");return{text:g,provider:"gemini",model:r,usage:l.usageMetadata?{inputTokens:l.usageMetadata.promptTokenCount,outputTokens:l.usageMetadata.candidatesTokenCount,totalTokens:l.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let o=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-o}}}};var $=class{constructor(o){this.config=o;this.id=o.id}config;id;baseUrl(){let o=this.config.baseUrl?.trim();if(!o)throw new Error(`${this.id}: BASE URL is not configured`);return o}model(){let o=this.config.model?.trim();if(!o)throw new Error(`${this.id}: MODEL is not configured`);return o}headers(){let o={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(o.authorization=`Bearer ${this.config.apiKey}`),o}async generate(o){let t=this.model(),n=await R(w(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:o.messages,temperature:o.temperature,max_tokens:o.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),r=n.choices?.[0]?.message?.content?.trim();if(!r)throw new Error(`${this.id}: empty model response`);return{text:r,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.usage.total_tokens}:void 0}}async healthCheck(){let o=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-o}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-o}}}};function _e(e=Ee()){switch(S(e.id).transport){case"gemini":return new Y(e);case"cloudflare":return new k(e);default:return new $(e)}}import{existsSync as z}from"node:fs";import{homedir as Q}from"node:os";import{join as Z}from"node:path";import{spawnSync as $o}from"node:child_process";import{existsSync as Qe,mkdirSync as Ze,readFileSync as eo,writeFileSync as oo}from"node:fs";import{homedir as to}from"node:os";import{dirname as no,join as ro}from"node:path";function io(e){return`'${e.replace(/'/g,"'\\''")}'`}function Oe(e={}){let o=e.hooksFile??ro(to(),".gemini","config","hooks.json");Ze(no(o),{recursive:!0});let t={};if(Qe(o))try{t=JSON.parse(eo(o,"utf8"))}catch(i){throw new Error(`Invalid existing Agy hooks.json: ${i instanceof Error?i.message:String(i)}`)}let n=e.binary??"toolnet-memory",r=`${io(n)} session:agy-hook`;return t["toolnet-memory"]={enabled:!0,PreInvocation:[{type:"command",command:`${r} pre`,timeout:15}],PostInvocation:[{type:"command",command:`${r} post`,timeout:15}],Stop:[{type:"command",command:`${r} stop`,timeout:30}]},oo(o,JSON.stringify(t,null,2)+`
4
4
  `,{encoding:"utf8",mode:384}),o}import{existsSync as so,mkdirSync as co,readFileSync as ao,renameSync as lo,writeFileSync as go}from"node:fs";import{homedir as Eo}from"node:os";import{dirname as _o,join as Oo}from"node:path";function D(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function fo(e,o){co(_o(e),{recursive:!0});let t=`${e}.tmp-${process.pid}-${Date.now()}`;go(t,`${JSON.stringify(o,null,2)}
5
5
  `,{encoding:"utf8",mode:384}),lo(t,e)}function fe(e){if(!so(e))return{};let o=ao(e,"utf8").trim();if(!o)return{};let t;try{t=JSON.parse(o)}catch(n){throw new Error(`Invalid existing Agy MCP config: ${n instanceof Error?n.message:String(n)}`)}if(!D(t))throw new Error("Invalid existing Agy MCP config: root must be a JSON object.");return t}function me(e,o){return D(e)?e.command===o&&Array.isArray(e.args)&&e.args.length===1&&e.args[0]==="mcp":!1}function ue(e={}){let o=e.configFile??Oo(Eo(),".gemini","config","mcp_config.json"),t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",n=e.serverName??"toolnet-memory",r=fe(o),i=r.mcpServers;if(i!==void 0&&!D(i))throw new Error("Invalid existing Agy MCP config: mcpServers must be an object.");let s=D(i)?{...i}:{},a=s[n];if(me(a,t))return{installed:!0,changed:!1,configFile:o,serverName:n,command:t,args:["mcp"]};s[n]={command:t,args:["mcp"]};let l={...r,mcpServers:s};fo(o,l);let E=fe(o).mcpServers;if(!D(E)||!me(E[n],t))throw new Error("Agy MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:o,serverName:n,command:t,args:["mcp"]}}import{existsSync as uo,mkdirSync as Te,readFileSync as Lo,writeFileSync as Ae}from"node:fs";import{homedir as J}from"node:os";import{join as F}from"node:path";var mo="memory_agent_ask";function Le(){return`
6
6
  [TOOLNET MEMORY AGENT]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolnet-memory",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "description": "Persistent project memory, work continuity, and code intelligence for AI coding agents.",
5
5
  "type": "module",
6
6
  "license": "MIT",