tarsk 0.2.2 → 0.2.3

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.
@@ -1 +1 @@
1
- import{logWrite,logEnd,logError,logStart}from"../log/log.js";export async function completion(o,t){const e=o.tools.map((o=>JSON.parse(JSON.stringify(o.definition))??[])),r={model:o.model,tools:e,messages:o.messages};let n;logStart({type:"completion",args:""});let l=0,a={};do{if(n=!1,l++,logStart({type:`completion_request_${l}`,args:o}),a=await call(t,r),logEnd(`completion_request_${l}`),a.error){const o=JSON.stringify(a.error.metadata);throw logError({type:"completion_error",message:o,args:{...a.error}}),new Error(a.error.message)}for(const t of a.choices)if(logWrite({type:"inject_choice",args:t}),o.messages.push(cleanedMessage(t.message)),"tool_calls"==t.finish_reason){logStart({type:"tool_calls",args:t.message.tool_calls});const e=await callTools(t.message.tool_calls??[],o);o.messages.push(...e),logEnd("tool_calls"),n=e.length>0}}while(n);return logEnd("completion"),a}function cleanedMessage(o){const t=JSON.parse(JSON.stringify(o));delete t.reasoning,delete t.refusal;for(const o of t.tool_calls??[])delete o.index;return t}export async function callTools(o,t){const e=[];for(const n of o){const o=n.function.name,l=JSON.parse(n.function.arguments);let a,s;for(const e of t.tools)for(const t of e.definition??[])if(t.function.name==o){a=t,s=e.functionMap;break}if(!a)throw new Error(`Tool ${o} not found`);if(!s)throw new Error(`Tool map for ${o} not found`);if(!s[o])throw new Error(`Tool ${o} not found in tool map. Check the function name in the definition matches exactly to the name of the function`);logStart({type:`tool_call_${o}`,args:{toolName:o,toolArgs:l}}),logWrite({type:"tool_call",args:{functionMap:s,toolArgs:l}});try{const t=await s[o](...Object.values(l));e.push({role:"tool",tool_call_id:n.id,name:o,content:JSON.stringify(t)}),logWrite({type:"tool_call_response",args:{toolName:o,toolResponse:t},message:JSON.stringify(t)})}catch(t){var r=new Error;throw logWrite({type:"tool_call_error",args:{toolName:o,error:t},message:r.stack?.toString()}),new Error(`Error calling tool ${o}: ${t}`)}finally{logEnd(`tool_call_${o}`)}}return e}export async function callFunction(o,t){try{return await o(t)}catch(t){new Error;return logWrite({type:"test_call_error",args:{functionName:o.name,error:`${t}`}}),{error:`Error calling ${o.name}: ${t}`}}}async function call(o,t){const e=await fetch(`${o.baseUrl}/chat/completions`,{method:"POST",headers:{Authorization:"Bearer "+o.apiKey,"HTTP-Referer":"https://tarsk.io","X-Title":"Tarsk","Content-Type":"application/json"},body:JSON.stringify(t)}),r=await e.text();return JSON.parse(r)}
1
+ import{logWrite,logEnd,logError,logStart}from"../log/log.js";export async function completion(request,options){const tools=request.tools.map((tool=>JSON.parse(JSON.stringify(tool.definition))??[])),req={model:request.model,tools:tools,messages:request.messages};let repeating;logStart({type:"completion",args:""});let count=0,response={};do{if(repeating=!1,count++,logStart({type:`completion_request_${count}`,args:request}),response=await call(options,req),logEnd(`completion_request_${count}`),response.error){const message=JSON.stringify(response.error.metadata);throw logError({type:"completion_error",message:message,args:{...response.error}}),new Error(response.error.message)}for(const choice of response.choices)if(logWrite({type:"inject_choice",args:choice}),request.messages.push(cleanedMessage(choice.message)),"tool_calls"==choice.finish_reason){logStart({type:"tool_calls",args:choice.message.tool_calls});const newMessages=await callTools(choice.message.tool_calls??[],request);request.messages.push(...newMessages),logEnd("tool_calls"),repeating=newMessages.length>0}}while(repeating);return logEnd("completion"),response}function cleanedMessage(message){const cleaned=JSON.parse(JSON.stringify(message));delete cleaned.reasoning,delete cleaned.refusal;for(const call of cleaned.tool_calls??[])delete call.index;return cleaned}export async function callTools(toolCalls,request){const newMessages=[];for(const toolCall of toolCalls){const toolName=toolCall.function.name,toolArgs=JSON.parse(toolCall.function.arguments);let found,functionMap;for(const tool of request.tools)for(const definition of tool.definition??[])if(definition.function.name==toolName){found=definition,functionMap=tool.functionMap;break}if(!found)throw new Error(`Tool ${toolName} not found`);if(!functionMap)throw new Error(`Tool map for ${toolName} not found`);if(!functionMap[toolName])throw new Error(`Tool ${toolName} not found in tool map. Check the function name in the definition matches exactly to the name of the function`);logStart({type:`tool_call_${toolName}`,args:{toolName:toolName,toolArgs:toolArgs}}),logWrite({type:"tool_call",args:{functionMap:functionMap,toolArgs:toolArgs}});try{const toolResponse=await functionMap[toolName](...Object.values(toolArgs));newMessages.push({role:"tool",tool_call_id:toolCall.id,name:toolName,content:JSON.stringify(toolResponse)}),logWrite({type:"tool_call_response",args:{toolName:toolName,toolResponse:toolResponse},message:JSON.stringify(toolResponse)})}catch(error){var err=new Error;throw logWrite({type:"tool_call_error",args:{toolName:toolName,error:error},message:err.stack?.toString()}),new Error(`Error calling tool ${toolName}: ${error}`)}finally{logEnd(`tool_call_${toolName}`)}}return newMessages}export async function callFunction(_function,args){try{return await _function(args)}catch(error){new Error;return logWrite({type:"test_call_error",args:{functionName:_function.name,error:`${error}`}}),{error:`Error calling ${_function.name}: ${error}`}}}async function call(options,request){const response=await fetch(`${options.baseUrl}/chat/completions`,{method:"POST",headers:{Authorization:"Bearer "+options.apiKey,"HTTP-Referer":"https://tarsk.io","X-Title":"Tarsk","Content-Type":"application/json"},body:JSON.stringify(request)}),text=await response.text();return JSON.parse(text)}
@@ -1 +1 @@
1
- import{createCipheriv,createDecipheriv,randomBytes,scryptSync}from"crypto";import{hostname,machine}from"os";export function encryptString(t){return encrypt(t,`${machineIdSync()}11de20da-f6cf-4b85-b630-555fc6e8b881`)}export function decryptString(t){try{return decrypt(t,`${machineIdSync()}11de20da-f6cf-4b85-b630-555fc6e8b881`)}catch(t){return""}}function machineIdSync(){return machine()+hostname()}const algorithm="aes-256-cbc",ivLength=16;function encrypt(t,e){const r=randomBytes(ivLength),n=scryptSync(e,"salt",32),c=createCipheriv(algorithm,n,r);let a=c.update(t,"utf8","base64");a+=c.final("base64");return`${r.toString("base64")}:${a}`}function decrypt(t,e){const[r,n]=t.split(":");if(!r||!n)throw new Error("Invalid encrypted data format");const c=Buffer.from(r,"base64"),a=scryptSync(e,"salt",32),i=createDecipheriv(algorithm,a,c);let o=i.update(n,"base64","utf8");return o+=i.final("utf8"),o}
1
+ import{createCipheriv,createDecipheriv,randomBytes,scryptSync}from"crypto";import{hostname,machine}from"os";export function encryptString(text){return encrypt(text,`${machineIdSync()}11de20da-f6cf-4b85-b630-555fc6e8b881`)}export function decryptString(text){try{return decrypt(text,`${machineIdSync()}11de20da-f6cf-4b85-b630-555fc6e8b881`)}catch(e){return""}}function machineIdSync(){return machine()+hostname()}const algorithm="aes-256-cbc",ivLength=16;function encrypt(text,passPhrase){const iv=randomBytes(ivLength),key=scryptSync(passPhrase,"salt",32),cipher=createCipheriv(algorithm,key,iv);let encrypted=cipher.update(text,"utf8","base64");encrypted+=cipher.final("base64");return`${iv.toString("base64")}:${encrypted}`}function decrypt(encryptedData,passPhrase){const[ivBase64,encryptedBase64]=encryptedData.split(":");if(!ivBase64||!encryptedBase64)throw new Error("Invalid encrypted data format");const iv=Buffer.from(ivBase64,"base64"),key=scryptSync(passPhrase,"salt",32),decipher=createDecipheriv(algorithm,key,iv);let decrypted=decipher.update(encryptedBase64,"base64","utf8");return decrypted+=decipher.final("utf8"),decrypted}
@@ -1 +1 @@
1
- export async function api_get_models(a){const i=await fetch("https://openrouter.ai/api/v1/models"),e=await i.json(),t=[];for(const a of e.data)hasTools(a.id)&&t.push({id:a.id,description:a.description,name:a.name,type:a.architecture.tokenizer,priceM:totalPrice(a.pricing),price:"0"==a.pricing.prompt&&"0"==a.pricing.completion?"":`($${totalPrice(a.pricing).toFixed(2)}m)`});return a.json(t)}function totalPrice(a){return 1e6*(v(a.prompt)+v(a.completion))}function promptPrice(a){return 1e6*v(a.prompt)}function completionPrice(a){return 1e6*v(a.completion)}function v(a){return a?Number(a):0}function hasTools(a){return["google/gemini-2.5-pro-preview-03-25","google/gemini-2.5-flash-preview","google/gemini-2.5-flash-preview:thinking","openai/o4-mini-high","openai/o3","openai/o4-mini","openai/gpt-4.1","openai/gpt-4.1-mini","openai/gpt-4.1-nano","x-ai/grok-3-beta","meta-llama/llama-4-maverick","meta-llama/llama-4-scout","all-hands/openhands-lm-32b-v0.1","mistral/ministral-8b","google/gemini-2.5-pro-exp-03-25:free","deepseek/deepseek-chat-v3-0324","mistralai/mistral-small-3.1-24b-instruct:free","mistralai/mistral-small-3.1-24b-instruct","ai21/jamba-1.6-large","ai21/jamba-1.6-mini","qwen/qwq-32b","openai/gpt-4.5-preview","google/gemini-2.0-flash-lite-001","anthropic/claude-3.7-sonnet","anthropic/claude-3.7-sonnet:thinking","anthropic/claude-3.7-sonnet:beta","mistralai/mistral-saba","openai/o3-mini-high","google/gemini-2.0-flash-001","qwen/qwen-turbo","qwen/qwen-plus","qwen/qwen-max","openai/o3-mini","mistralai/mistral-small-24b-instruct-2501","deepseek/deepseek-r1-distill-llama-70b","deepseek/deepseek-r1","mistralai/codestral-2501","deepseek/deepseek-chat","openai/o1","x-ai/grok-2-1212","google/gemini-2.0-flash-exp:free","meta-llama/llama-3.3-70b-instruct","amazon/nova-lite-v1","amazon/nova-micro-v1","amazon/nova-pro-v1","openai/gpt-4o-2024-11-20","mistralai/mistral-large-2411","mistralai/mistral-large-2407","mistralai/pixtral-large-2411","anthropic/claude-3.5-haiku:beta","anthropic/claude-3.5-haiku","anthropic/claude-3.5-haiku-20241022:beta","anthropic/claude-3.5-haiku-20241022","anthropic/claude-3.5-sonnet:beta","anthropic/claude-3.5-sonnet","x-ai/grok-beta","mistralai/ministral-8b","mistralai/ministral-3b","nvidia/llama-3.1-nemotron-70b-instruct","google/gemini-flash-1.5-8b","meta-llama/llama-3.2-3b-instruct","qwen/qwen-2.5-72b-instruct","mistralai/pixtral-12b","cohere/command-r-plus-08-2024","cohere/command-r-08-2024","google/gemini-flash-1.5-8b-exp","ai21/jamba-1-5-mini","ai21/jamba-1-5-large","microsoft/phi-3.5-mini-128k-instruct","nousresearch/hermes-3-llama-3.1-70b","openai/gpt-4o-2024-08-06","meta-llama/llama-3.1-8b-instruct","meta-llama/llama-3.1-405b-instruct","meta-llama/llama-3.1-70b-instruct","mistralai/codestral-mamba","mistralai/mistral-nemo","openai/gpt-4o-mini","openai/gpt-4o-mini-2024-07-18","anthropic/claude-3.5-sonnet-20240620:beta","anthropic/claude-3.5-sonnet-20240620","mistralai/mistral-7b-instruct:free","mistralai/mistral-7b-instruct","mistralai/mistral-7b-instruct-v0.3","microsoft/phi-3-mini-128k-instruct","microsoft/phi-3-medium-128k-instruct","google/gemini-flash-1.5","openai/gpt-4o","openai/gpt-4o:extended","openai/gpt-4o-2024-05-13","meta-llama/llama-3-8b-instruct","meta-llama/llama-3-70b-instruct","mistralai/mixtral-8x22b-instruct","google/gemini-pro-1.5","openai/gpt-4-turbo","cohere/command-r-plus","cohere/command-r-plus-04-2024","cohere/command-r","anthropic/claude-3-haiku:beta","anthropic/claude-3-haiku","anthropic/claude-3-opus:beta","anthropic/claude-3-opus","anthropic/claude-3-sonnet:beta","anthropic/claude-3-sonnet","cohere/command-r-03-2024","mistralai/mistral-large","openai/gpt-3.5-turbo-0613","openai/gpt-4-turbo-preview","mistralai/mistral-medium","mistralai/mistral-small","mistralai/mistral-tiny","mistralai/mixtral-8x7b-instruct","openai/gpt-3.5-turbo-1106","openai/gpt-4-1106-preview","mistralai/mistral-7b-instruct-v0.1","openai/gpt-3.5-turbo-16k","openai/gpt-4-32k","openai/gpt-4-32k-0314","openai/gpt-3.5-turbo","openai/gpt-3.5-turbo-0125","openai/gpt-4","openai/gpt-4-0314"].includes(a)}
1
+ export async function api_get_models(c){const res=await fetch("https://openrouter.ai/api/v1/models"),data=await res.json(),models=[];for(const model of data.data)hasTools(model.id)&&models.push({id:model.id,description:model.description,name:model.name,type:model.architecture.tokenizer,priceM:totalPrice(model.pricing),price:"0"==model.pricing.prompt&&"0"==model.pricing.completion?"":`($${totalPrice(model.pricing).toFixed(2)}m)`});return c.json(models)}function totalPrice(price){return 1e6*(v(price.prompt)+v(price.completion))}function promptPrice(price){return 1e6*v(price.prompt)}function completionPrice(price){return 1e6*v(price.completion)}function v(s){return s?Number(s):0}function hasTools(model){return["google/gemini-2.5-pro-preview-03-25","google/gemini-2.5-flash-preview","google/gemini-2.5-flash-preview:thinking","openai/o4-mini-high","openai/o3","openai/o4-mini","openai/gpt-4.1","openai/gpt-4.1-mini","openai/gpt-4.1-nano","x-ai/grok-3-beta","meta-llama/llama-4-maverick","meta-llama/llama-4-scout","all-hands/openhands-lm-32b-v0.1","mistral/ministral-8b","google/gemini-2.5-pro-exp-03-25:free","deepseek/deepseek-chat-v3-0324","mistralai/mistral-small-3.1-24b-instruct:free","mistralai/mistral-small-3.1-24b-instruct","ai21/jamba-1.6-large","ai21/jamba-1.6-mini","qwen/qwq-32b","openai/gpt-4.5-preview","google/gemini-2.0-flash-lite-001","anthropic/claude-3.7-sonnet","anthropic/claude-3.7-sonnet:thinking","anthropic/claude-3.7-sonnet:beta","mistralai/mistral-saba","openai/o3-mini-high","google/gemini-2.0-flash-001","qwen/qwen-turbo","qwen/qwen-plus","qwen/qwen-max","openai/o3-mini","mistralai/mistral-small-24b-instruct-2501","deepseek/deepseek-r1-distill-llama-70b","deepseek/deepseek-r1","mistralai/codestral-2501","deepseek/deepseek-chat","openai/o1","x-ai/grok-2-1212","google/gemini-2.0-flash-exp:free","meta-llama/llama-3.3-70b-instruct","amazon/nova-lite-v1","amazon/nova-micro-v1","amazon/nova-pro-v1","openai/gpt-4o-2024-11-20","mistralai/mistral-large-2411","mistralai/mistral-large-2407","mistralai/pixtral-large-2411","anthropic/claude-3.5-haiku:beta","anthropic/claude-3.5-haiku","anthropic/claude-3.5-haiku-20241022:beta","anthropic/claude-3.5-haiku-20241022","anthropic/claude-3.5-sonnet:beta","anthropic/claude-3.5-sonnet","x-ai/grok-beta","mistralai/ministral-8b","mistralai/ministral-3b","nvidia/llama-3.1-nemotron-70b-instruct","google/gemini-flash-1.5-8b","meta-llama/llama-3.2-3b-instruct","qwen/qwen-2.5-72b-instruct","mistralai/pixtral-12b","cohere/command-r-plus-08-2024","cohere/command-r-08-2024","google/gemini-flash-1.5-8b-exp","ai21/jamba-1-5-mini","ai21/jamba-1-5-large","microsoft/phi-3.5-mini-128k-instruct","nousresearch/hermes-3-llama-3.1-70b","openai/gpt-4o-2024-08-06","meta-llama/llama-3.1-8b-instruct","meta-llama/llama-3.1-405b-instruct","meta-llama/llama-3.1-70b-instruct","mistralai/codestral-mamba","mistralai/mistral-nemo","openai/gpt-4o-mini","openai/gpt-4o-mini-2024-07-18","anthropic/claude-3.5-sonnet-20240620:beta","anthropic/claude-3.5-sonnet-20240620","mistralai/mistral-7b-instruct:free","mistralai/mistral-7b-instruct","mistralai/mistral-7b-instruct-v0.3","microsoft/phi-3-mini-128k-instruct","microsoft/phi-3-medium-128k-instruct","google/gemini-flash-1.5","openai/gpt-4o","openai/gpt-4o:extended","openai/gpt-4o-2024-05-13","meta-llama/llama-3-8b-instruct","meta-llama/llama-3-70b-instruct","mistralai/mixtral-8x22b-instruct","google/gemini-pro-1.5","openai/gpt-4-turbo","cohere/command-r-plus","cohere/command-r-plus-04-2024","cohere/command-r","anthropic/claude-3-haiku:beta","anthropic/claude-3-haiku","anthropic/claude-3-opus:beta","anthropic/claude-3-opus","anthropic/claude-3-sonnet:beta","anthropic/claude-3-sonnet","cohere/command-r-03-2024","mistralai/mistral-large","openai/gpt-3.5-turbo-0613","openai/gpt-4-turbo-preview","mistralai/mistral-medium","mistralai/mistral-small","mistralai/mistral-tiny","mistralai/mixtral-8x7b-instruct","openai/gpt-3.5-turbo-1106","openai/gpt-4-1106-preview","mistralai/mistral-7b-instruct-v0.1","openai/gpt-3.5-turbo-16k","openai/gpt-4-32k","openai/gpt-4-32k-0314","openai/gpt-3.5-turbo","openai/gpt-3.5-turbo-0125","openai/gpt-4","openai/gpt-4-0314"].includes(model)}
@@ -1 +1 @@
1
- import{prompt}from"../prompt.js";import{logWrite}from"../log/log.js";export async function api_prompt(r){const o=await r.req.json();logWrite({type:"prompt",args:o});const t=o.prompt;if(!t)return r.json({error:"Prompt is required"},400);const p=await prompt(t);return r.json({answer:p})}
1
+ import{prompt}from"../prompt.js";import{logWrite}from"../log/log.js";export async function api_prompt(c){const body=await c.req.json();logWrite({type:"prompt",args:body});const question=body.prompt;if(!question)return c.json({error:"Prompt is required"},400);const answer=await prompt(question);return c.json({answer:answer})}
@@ -1 +1 @@
1
- import{}from"../interfaces/settings.js";import{getJSON,setJSON}from"../utils/json-file.js";import{httpValidationErrror as httpValidationError,isEmpty}from"./utils.js";const defaultOpenRouterURL="https://openrouter.ai/api/v1";export const defaultModel="meta-llama/llama-3.3-70b-instruct";export async function api_get_settings(t){return t.json(getSettings())}export async function api_save_settings(t){const e=await t.req.json();return null==e.openRouterApiKey&&httpValidationError("openRouterApiKey is required"),isEmpty(e.openRouterURL)&&(e.openRouterURL=defaultOpenRouterURL),(isEmpty(e.defaultModel)||"Select a Model"==e.defaultModel)&&(e.defaultModel=defaultModel),null==e.openRouterURL&&httpValidationError("openRouterURL is required"),e.openRouterURL.startsWith("https://")||httpValidationError("openRouterURL must start with https://"),e.openRouterURL.endsWith("/")&&(e.openRouterURL=e.openRouterURL.slice(0,-1)),setJSON("settings",e),t.json(getSettings())}export function getSettings(){return getJSON("settings",{openRouterApiKey:"",openRouterURL:defaultOpenRouterURL,defaultModel:defaultModel})}
1
+ import{}from"../interfaces/settings.js";import{getJSON,setJSON}from"../utils/json-file.js";import{httpValidationErrror as httpValidationError,isEmpty}from"./utils.js";const defaultOpenRouterURL="https://openrouter.ai/api/v1";export const defaultModel="meta-llama/llama-3.3-70b-instruct";export async function api_get_settings(c){return c.json(getSettings())}export async function api_save_settings(c){const settings=await c.req.json();return null==settings.openRouterApiKey&&httpValidationError("openRouterApiKey is required"),isEmpty(settings.openRouterURL)&&(settings.openRouterURL=defaultOpenRouterURL),(isEmpty(settings.defaultModel)||"Select a Model"==settings.defaultModel)&&(settings.defaultModel=defaultModel),null==settings.openRouterURL&&httpValidationError("openRouterURL is required"),settings.openRouterURL.startsWith("https://")||httpValidationError("openRouterURL must start with https://"),settings.openRouterURL.endsWith("/")&&(settings.openRouterURL=settings.openRouterURL.slice(0,-1)),setJSON("settings",settings),c.json(getSettings())}export function getSettings(){return getJSON("settings",{openRouterApiKey:"",openRouterURL:defaultOpenRouterURL,defaultModel:defaultModel})}
package/dist/api/test.js CHANGED
@@ -1 +1 @@
1
- import{prompt}from"../prompt.js";import{stripMarkdown}from"../utils/strip-markdown.js";export async function createTest(t,e,o){const n=t.map((t=>t.function.name));let r=`import { ${n.join(",")} } from "./${e}";\n\n`;r+=`export async function test() {\n ${n.map((t=>` // Call ${t} to test it`)).join("\n")}\n return 'place your test results here';\n}`;try{const t=await prompt(`Complete the test function with a test case for the following functions ${n.join(", ")}. The test should be a valid JavaScript code and should return the test results.\n Here is the initial test code:\n\n ${r}\n `,{ignoreTools:!0,firstMessage:{role:"system",content:"You must return the code without any explaination."}});r=stripMarkdown(t)}catch(t){console.error("Error generating test code:",t)}return r}
1
+ import{prompt}from"../prompt.js";import{stripMarkdown}from"../utils/strip-markdown.js";export async function createTest(definition,codeFilename,code){const functions=definition.map((tool=>tool.function.name));let test=`import { ${functions.join(",")} } from "./${codeFilename}";\n\n`;test+=`export async function test() {\n ${functions.map((functionName=>` // Call ${functionName} to test it`)).join("\n")}\n return 'place your test results here';\n}`;try{const updated=await prompt(`Complete the test function with a test case for the following functions ${functions.join(", ")}. The test should be a valid JavaScript code and should return the test results.\n Here is the initial test code:\n\n ${test}\n `,{ignoreTools:!0,firstMessage:{role:"system",content:"You must return the code without any explaination."}});test=stripMarkdown(updated)}catch(e){console.error("Error generating test code:",e)}return test}
package/dist/api/tools.js CHANGED
@@ -1 +1 @@
1
- import{existsSync,mkdirSync,promises,readdirSync,writeFileSync}from"fs";import{extname,join}from"path";import{extensionLess,isEmpty,tarskFolder}from"./utils.js";import{logError,logWrite}from"../log/log.js";import tsBlankSpace from"ts-blank-space";import{loadTools}from"../tools.js";import{callFunction}from"../agent/agent.js";import{readAsJSONIfExists}from"../utils/files.js";import ts,{SyntaxKind}from"typescript";import{createTest}from"./test.js";export async function api_run_tool(t){const e=await t.req.json();if(logWrite({type:"api_run_tool",args:{toolName:e.name}}),!e.code)return t.json({error:"Tool not found"},404);try{const o=await getTool(e.name),s=(await loadTools(toolJavascriptFilenames(!0))).find((t=>t.name==o.name+".test")),n="test";if(!s)throw new Error(`${e.name} not found`);if(!s.functionNames.includes(n))throw new Error(`${e.name} function "${n}" not found (reload?)`);const r=await callFunction(s.functionMap[n]);return t.json({output:r,js:"test();"})}catch(e){return t.json({output:`${e}`,js:""})}}export async function api_save_tool(t){const e=await t.req.json();""==e.name&&(e.name=e.title);const o=e.title,s=e.code;let n=e.test??"";const r=e.name.toLowerCase().replaceAll(" ","_");if(!o||!s||!r)return t.json({error:"Title and code are required"},400);const i={title:o,name:r},a=tsBlankSpace(e.code??"",(t=>{logError({type:"failed_ts_to_js_code",args:t})})),c=tsBlankSpace(e.test??"",(t=>{logError({type:"failed_ts_to_js_test",args:t})})),l=r.replace(/\s+/g,"_").toLowerCase(),m=join(toolsSrcFolder(),`${l}.ts`),p=join(toolsJSFolder(),`${l}.js`),u=join(toolsJSFolder(),`${l}.js.definition.json`),d=join(toolsSrcFolder(),`${l}.test.ts`),f=join(toolsJSFolder(),`${l}.test.js`),y=join(toolsSrcFolder(),`${l}.json`),g=readAsJSONIfExists(y);g&&(i.revision=(g.revision??1)+1);const j={missingParameters:[],missingFunctions:[]},S=await inspectCode(m,j);return logWrite({type:"api_save_tool_check_test",args:{test:n}}),isEmpty(n)&&(n=await createTest(S,`${l}.js`,s)),writeFileSync(m,s,"utf-8"),writeFileSync(y,JSON.stringify(i,null,2),"utf-8"),writeFileSync(u,JSON.stringify(S,null,2),"utf-8"),writeFileSync(d,n,"utf-8"),writeFileSync(p,a,"utf-8"),writeFileSync(f,c,"utf-8"),logWrite({type:"api_save_tool",args:{test:d,code:m,meta:y}}),t.json({message:`Tool saved successfully (${p})`,missingParameters:j.missingParameters,missingFunctions:j.missingFunctions})}export async function api_get_tool(t){const e=t.req.param("tool"),o=await getTool(e);return console.log(`api_get_tool ${e}`),t.json(o)}export async function api_delete_tool(t){const e=t.req.param("tool");return await deleteTool(e),t.json({})}async function deleteTool(t){console.log(`Deleting tool ${t}`);const e=toolsSrcFolder();await promises.rm(join(e,`${t}.ts`)),await promises.rm(join(e,`${t}.test.ts`)),await promises.rm(join(e,`${t}.json`)),await promises.rm(join(toolsJSFolder(),`${t}.js`)),await promises.rm(join(toolsJSFolder(),`${t}.test.js`))}export async function api_get_tools(t){const e=await toolFilenames(),o=[];for(const t of e){const e=await getTool(t);e.code=void 0,o.push(e)}return t.json(o)}async function toolFilenames(){const t=toolsSrcFolder();return(await promises.readdir(t)).filter((t=>".ts"===extname(t)&&!t.endsWith(".test.ts"))).map((t=>extensionLess(t)))}function toolsJSFolder(){const t=join(tarskFolder(),".tools");return existsSync(t)||mkdirSync(t,{recursive:!0}),t}export function toolJavascriptFilenames(t){const e=readdirSync(toolsJSFolder());return t?e.filter((t=>".js"===extname(t))).map((t=>join(tarskFolder(),".tools",t))):e.filter((t=>".js"===extname(t)&&!t.endsWith(".test.js"))).map((t=>join(tarskFolder(),".tools",t)))}export async function getTool(t){const e=toolsSrcFolder(),o=await readOrEmpty(join(e,`${t}.ts`)),s=await readOrEmpty(join(e,`${t}.test.ts`)),n=await readOrEmpty(join(e,`${t}.json`));try{const t=""==n?{tile:"",name:""}:JSON.parse(n);return{code:o,title:t.title,name:t.name,test:s}}catch(e){return console.error(`Failed to parse ${t}.json`,e),{code:o,title:"",name:t,test:s}}}function toolsSrcFolder(){const t=join(tarskFolder(),"tools");return existsSync(t)||mkdirSync(t,{recursive:!0}),t}async function readOrEmpty(t){return existsSync(t)?await promises.readFile(t,"utf-8"):""}export async function inspectCode(t,e){const o=await readOrEmpty(t),s=[];return function t(o){if((ts.isFunctionDeclaration(o)||ts.isFunctionExpression(o)||ts.isArrowFunction(o))&&o.name){const t=parseJSDoc(o);console.log("Parsed function",t);const n={},r=[];o.parameters.forEach((o=>{!!o.questionToken||!!o.initializer||r.push(o.name.getText());let s=typeName(o.type?.getText());o.type?.kind==SyntaxKind.TypeReference&&(s="object"),t.params;const i=Object.keys(t.params).includes(o.name.getText()),a=i?t.params[o.name.getText()]:"";i||e.missingParameters.push(o.name.escapedText),n[o.name.getText()]={type:s,description:a},"array"==s&&(n[o.name.getText()].items={type:arrayType(o.type?.getText())})}));const i=t.description;isEmpty(i)&&e.missingFunctions.push(o.name.getText()),s.push({type:"function",function:{name:o.name?.text??"",description:i,parameters:{type:"object",properties:n,required:r}}})}ts.forEachChild(o,t)}(ts.createSourceFile("temp.ts",o,ts.ScriptTarget.Latest,!0)),s}function parseJSDoc(t){const e=t.name?.getText(),o=ts.getJSDocCommentsAndTags(t),s={functionName:e,description:"",params:{}};let n="";for(const t of o)if(ts.isJSDoc(t)&&(t.comment&&(s.description=t.comment.toString()),t.tags))for(const e of t.tags){if(n+=" "+e.comment,e.kind==SyntaxKind.JSDocTag&&e.comment){let t=e.comment?e.comment.toString():"";const o=t.split(" ")[0];t.startsWith(o)&&(t=t.substring(o.length).trim()),t.startsWith("-")&&(t=t.substring(1).trim()),s.params[o]=t}if(e.kind==SyntaxKind.JSDocFunctionType||e.kind==SyntaxKind.JSDocParameterTag){let t=e.comment?e.comment.toString():"",o=e.name?.escapedText;t.startsWith(o)&&(t=t.substring(o.length).trim()),t.startsWith("-")&&(t=t.substring(1).trim()),s.params[o]=t}}return s}function typeName(t){return t?t.endsWith("[]")?"array":t:"any"}function arrayType(t){return t?t.replace("[]",""):"any"}
1
+ import{existsSync,mkdirSync,promises,readdirSync,writeFileSync}from"fs";import{extname,join}from"path";import{extensionLess,isEmpty,tarskFolder}from"./utils.js";import{logError,logWrite}from"../log/log.js";import tsBlankSpace from"ts-blank-space";import{loadTools}from"../tools.js";import{callFunction}from"../agent/agent.js";import{readAsJSONIfExists}from"../utils/files.js";import ts,{SyntaxKind}from"typescript";import{createTest}from"./test.js";export async function api_run_tool(c){const tool=await c.req.json();if(logWrite({type:"api_run_tool",args:{toolName:tool.name}}),!tool.code)return c.json({error:"Tool not found"},404);try{const toolToRun=await getTool(tool.name),d=(await loadTools(toolJavascriptFilenames(!0))).find((t=>t.name==toolToRun.name+".test")),functionName="test";if(!d)throw new Error(`${tool.name} not found`);if(!d.functionNames.includes(functionName))throw new Error(`${tool.name} function "${functionName}" not found (reload?)`);const output=await callFunction(d.functionMap[functionName]);return c.json({output:output,js:"test();"})}catch(e){return c.json({output:`${e}`,js:""})}}export async function api_save_tool(c){const tool=await c.req.json();""==tool.name&&(tool.name=tool.title);const title=tool.title,code=tool.code;let test=tool.test??"";const name=tool.name.toLowerCase().replaceAll(" ","_");if(!title||!code||!name)return c.json({error:"Title and code are required"},400);const meta={title:title,name:name},jsCode=tsBlankSpace(tool.code??"",(e=>{logError({type:"failed_ts_to_js_code",args:e})})),testCode=tsBlankSpace(tool.test??"",(e=>{logError({type:"failed_ts_to_js_test",args:e})})),filename=name.replace(/\s+/g,"_").toLowerCase(),srcPath=join(toolsSrcFolder(),`${filename}.ts`),jsCodePath=join(toolsJSFolder(),`${filename}.js`),defPath=join(toolsJSFolder(),`${filename}.js.definition.json`),testPath=join(toolsSrcFolder(),`${filename}.test.ts`),jsTestPath=join(toolsJSFolder(),`${filename}.test.js`),metaPath=join(toolsSrcFolder(),`${filename}.json`),currentMeta=readAsJSONIfExists(metaPath);currentMeta&&(meta.revision=(currentMeta.revision??1)+1);const missingData={missingParameters:[],missingFunctions:[]},definition=await inspectCode(srcPath,missingData);return logWrite({type:"api_save_tool_check_test",args:{test:test}}),isEmpty(test)&&(test=await createTest(definition,`${filename}.js`,code)),writeFileSync(srcPath,code,"utf-8"),writeFileSync(metaPath,JSON.stringify(meta,null,2),"utf-8"),writeFileSync(defPath,JSON.stringify(definition,null,2),"utf-8"),writeFileSync(testPath,test,"utf-8"),writeFileSync(jsCodePath,jsCode,"utf-8"),writeFileSync(jsTestPath,testCode,"utf-8"),logWrite({type:"api_save_tool",args:{test:testPath,code:srcPath,meta:metaPath}}),c.json({message:`Tool saved successfully (${jsCodePath})`,missingParameters:missingData.missingParameters,missingFunctions:missingData.missingFunctions})}export async function api_get_tool(c){const toolName=c.req.param("tool"),tool=await getTool(toolName);return console.log(`api_get_tool ${toolName}`),c.json(tool)}export async function api_delete_tool(c){const toolName=c.req.param("tool");return await deleteTool(toolName),c.json({})}async function deleteTool(name){console.log(`Deleting tool ${name}`);const toolsFolder=toolsSrcFolder();await promises.rm(join(toolsFolder,`${name}.ts`)),await promises.rm(join(toolsFolder,`${name}.test.ts`)),await promises.rm(join(toolsFolder,`${name}.json`)),await promises.rm(join(toolsJSFolder(),`${name}.js`)),await promises.rm(join(toolsJSFolder(),`${name}.test.js`))}export async function api_get_tools(c){const fileList=await toolFilenames(),result=[];for(const file of fileList){const tool=await getTool(file);tool.code=void 0,result.push(tool)}return c.json(result)}async function toolFilenames(){const toolsFolder=toolsSrcFolder();return(await promises.readdir(toolsFolder)).filter((f=>".ts"===extname(f)&&!f.endsWith(".test.ts"))).map((f=>extensionLess(f)))}function toolsJSFolder(){const folderPath=join(tarskFolder(),".tools");return existsSync(folderPath)||mkdirSync(folderPath,{recursive:!0}),folderPath}export function toolJavascriptFilenames(includeTests){const files=readdirSync(toolsJSFolder());return includeTests?files.filter((f=>".js"===extname(f))).map((f=>join(tarskFolder(),".tools",f))):files.filter((f=>".js"===extname(f)&&!f.endsWith(".test.js"))).map((f=>join(tarskFolder(),".tools",f)))}export async function getTool(name){const toolsFolder=toolsSrcFolder(),code=await readOrEmpty(join(toolsFolder,`${name}.ts`)),test=await readOrEmpty(join(toolsFolder,`${name}.test.ts`)),meta=await readOrEmpty(join(toolsFolder,`${name}.json`));try{const json=""==meta?{tile:"",name:""}:JSON.parse(meta);return{code:code,title:json.title,name:json.name,test:test}}catch(e){return console.error(`Failed to parse ${name}.json`,e),{code:code,title:"",name:name,test:test}}}function toolsSrcFolder(){const folderPath=join(tarskFolder(),"tools");return existsSync(folderPath)||mkdirSync(folderPath,{recursive:!0}),folderPath}async function readOrEmpty(filename){return existsSync(filename)?await promises.readFile(filename,"utf-8"):""}export async function inspectCode(filename,missingData){const code=await readOrEmpty(filename),tools=[];return function visit(node){if((ts.isFunctionDeclaration(node)||ts.isFunctionExpression(node)||ts.isArrowFunction(node))&&node.name){const parsed=parseJSDoc(node);console.log("Parsed function",parsed);const properties={},required=[];node.parameters.forEach((param=>{!!param.questionToken||!!param.initializer||required.push(param.name.getText());let type=typeName(param.type?.getText());param.type?.kind==SyntaxKind.TypeReference&&(type="object"),parsed.params;const hasDescription=Object.keys(parsed.params).includes(param.name.getText()),description=hasDescription?parsed.params[param.name.getText()]:"";hasDescription||missingData.missingParameters.push(param.name.escapedText),properties[param.name.getText()]={type:type,description:description},"array"==type&&(properties[param.name.getText()].items={type:arrayType(param.type?.getText())})}));const functionDescription=parsed.description;isEmpty(functionDescription)&&missingData.missingFunctions.push(node.name.getText()),tools.push({type:"function",function:{name:node.name?.text??"",description:functionDescription,parameters:{type:"object",properties:properties,required:required}}})}ts.forEachChild(node,visit)}(ts.createSourceFile("temp.ts",code,ts.ScriptTarget.Latest,!0)),tools}function parseJSDoc(node){const functionName=node.name?.getText(),jsDoc=ts.getJSDocCommentsAndTags(node),parsed={functionName:functionName,description:"",params:{}};let info="";for(const doc of jsDoc)if(ts.isJSDoc(doc)&&(doc.comment&&(parsed.description=doc.comment.toString()),doc.tags))for(const tag of doc.tags){if(info+=" "+tag.comment,tag.kind==SyntaxKind.JSDocTag&&tag.comment){let txt=tag.comment?tag.comment.toString():"";const paramName=txt.split(" ")[0];txt.startsWith(paramName)&&(txt=txt.substring(paramName.length).trim()),txt.startsWith("-")&&(txt=txt.substring(1).trim()),parsed.params[paramName]=txt}if(tag.kind==SyntaxKind.JSDocFunctionType||tag.kind==SyntaxKind.JSDocParameterTag){let txt=tag.comment?tag.comment.toString():"",paramName=tag.name?.escapedText;txt.startsWith(paramName)&&(txt=txt.substring(paramName.length).trim()),txt.startsWith("-")&&(txt=txt.substring(1).trim()),parsed.params[paramName]=txt}}return parsed}function typeName(name){return name?name.endsWith("[]")?"array":name:"any"}function arrayType(name){return name?name.replace("[]",""):"any"}
package/dist/api/utils.js CHANGED
@@ -1 +1 @@
1
- import{HTTPException}from"hono/http-exception";import{homedir}from"os";import{extname,join}from"path";export function extensionLess(t){return t.substring(0,t.length-extname(t).length)}export function tarskFolder(){return join(homedir(),".tarsk")}export function httpValidationErrror(t){throw new HTTPException(406,{message:t})}export function isEmpty(t){return null==t||null==t||""==t||""==t.trim()}
1
+ import{HTTPException}from"hono/http-exception";import{homedir}from"os";import{extname,join}from"path";export function extensionLess(filename){return filename.substring(0,filename.length-extname(filename).length)}export function tarskFolder(){return join(homedir(),".tarsk")}export function httpValidationErrror(message){throw new HTTPException(406,{message:message})}export function isEmpty(v){return null==v||null==v||""==v||""==v.trim()}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{serve}from"@hono/node-server";import{Hono}from"hono";import{cors}from"hono/cors";import open from"open";import{api_prompt}from"./api/prompt.js";import{api_delete_tool,api_get_tool,api_get_tools,api_run_tool,api_save_tool}from"./api/tools.js";import{api_get_settings,api_save_settings}from"./api/settings.js";import{api_get_models}from"./api/models.js";const app=new Hono;app.use("/*",cors({origin:(t,o)=>t.startsWith("http://localhost")||t.startsWith("https://tarsk.io")?t:"x"})),app.get("/",(t=>t.text("Tarsk Started."))),app.post("/prompt",(async t=>await api_prompt(t))),app.post("/tools",(async t=>await api_save_tool(t))),app.get("/tools",(async t=>await api_get_tools(t))),app.post("/run/tool",(async t=>await api_run_tool(t))),app.get("/tools/:tool",(async t=>await api_get_tool(t))),app.delete("/tools/:tool",(async t=>await api_delete_tool(t))),app.get("/settings",(async t=>await api_get_settings(t))),app.post("/settings",(async t=>await api_save_settings(t))),app.get("/models",(async t=>await api_get_models(t))),serve({fetch:app.fetch,port:4021},(t=>{process.env._&&process.env._.endsWith("tsx")?console.log(`Tarsk is running in dev mode on http://localhost:${t.port}`):(console.log("Tarsk is running. Visit https://tarsk.io"),open("https://tarsk.io"))}));
2
+ import{serve}from"@hono/node-server";import{Hono}from"hono";import{cors}from"hono/cors";import open from"open";import{api_prompt}from"./api/prompt.js";import{api_delete_tool,api_get_tool,api_get_tools,api_run_tool,api_save_tool}from"./api/tools.js";import{api_get_settings,api_save_settings}from"./api/settings.js";import{api_get_models}from"./api/models.js";const app=new Hono;app.use("/*",cors({origin:(origin,c)=>origin.startsWith("http://localhost")||origin.startsWith("https://tarsk.io")?origin:"x"})),app.get("/",(c=>c.text("Tarsk Started."))),app.post("/prompt",(async c=>await api_prompt(c))),app.post("/tools",(async c=>await api_save_tool(c))),app.get("/tools",(async c=>await api_get_tools(c))),app.post("/run/tool",(async c=>await api_run_tool(c))),app.get("/tools/:tool",(async c=>await api_get_tool(c))),app.delete("/tools/:tool",(async c=>await api_delete_tool(c))),app.get("/settings",(async c=>await api_get_settings(c))),app.post("/settings",(async c=>await api_save_settings(c))),app.get("/models",(async c=>await api_get_models(c))),serve({fetch:app.fetch,port:4021},(info=>{process.env._&&process.env._.endsWith("tsx")?console.log(`Tarsk is running in dev mode on http://localhost:${info.port}`):(console.log("Tarsk is running. Visit https://tarsk.io"),open("https://tarsk.io"))}));
package/dist/log/log.js CHANGED
@@ -1 +1 @@
1
- let logLevel="debug";export function logWrite(e,o){if("none"==logLevel)return;let n=e.type;e.message&&(n+=`: ${e.message}`),e.args&&(n+=` ${JSON.stringify(e.args)}`),e.id=id(),console.log(n)}export function logStart(e,o){"none"!==logLevel&&(console.time(e.type),logWrite(e,o))}export function logEnd(e){"none"!==logLevel&&console.timeEnd(e)}export function logError(e){"none"!==logLevel&&console.error(e)}function id(){return Math.random().toString().replace(".","")}
1
+ let logLevel="debug";export function logWrite(l,additionalMessage){if("none"==logLevel)return;let msg=l.type;l.message&&(msg+=`: ${l.message}`),l.args&&(msg+=` ${JSON.stringify(l.args)}`),l.id=id(),console.log(msg)}export function logStart(l,additionalMessage){"none"!==logLevel&&(console.time(l.type),logWrite(l,additionalMessage))}export function logEnd(label){"none"!==logLevel&&console.timeEnd(label)}export function logError(l){"none"!==logLevel&&console.error(l)}function id(){return Math.random().toString().replace(".","")}
package/dist/prompt.js CHANGED
@@ -1 +1 @@
1
- import{completion}from"./agent/agent.js";import{loadTools}from"./tools.js";import{defaultModel,getSettings}from"./api/settings.js";import{toolJavascriptFilenames}from"./api/tools.js";import{isEmpty}from"./api/utils.js";import{logWrite,logEnd,logStart}from"./log/log.js";export async function prompt(e,o){const t=await getSettings();if(""==t.openRouterApiKey)return"You need to set the OpenRouter API key in the settings.";const s={baseUrl:t.openRouterURL,apiKey:t.openRouterApiKey},r=[];o?.firstMessage&&r.push(o.firstMessage),r.push({role:"user",content:e});const l=isEmpty(t.defaultModel)?defaultModel:t.defaultModel;logWrite({type:"prompt",args:e},`The model is ${l}`);const a=toolJavascriptFilenames(!1);let i=[];o?.ignoreTools||(logStart({type:"load_tools",args:a}),i=await loadTools(a),logEnd("load_tools"));const n={model:l,tools:i,messages:r};try{const e=await completion(n,s);return logWrite({type:"completion_response",args:e}),logWrite({type:"message",args:e?.choices[0].message}),e?.choices[0].message.content}catch(e){return friendlyError(`${e}`,t)}}function friendlyError(e,o){return e.startsWith("Error: No endpoints found that support tool use")?`The model "${o.defaultModel}" does not support tool use. Please select a different model (A good default is ${defaultModel}).`:e.startsWith("Error: No auth credentials found")?"The OpenRouter API key is invalid. Please check your account at https://openrouter.ai and get a new key.":e}
1
+ import{completion}from"./agent/agent.js";import{loadTools}from"./tools.js";import{defaultModel,getSettings}from"./api/settings.js";import{toolJavascriptFilenames}from"./api/tools.js";import{isEmpty}from"./api/utils.js";import{logWrite,logEnd,logStart}from"./log/log.js";export async function prompt(content,promptOptions){const settings=await getSettings();if(""==settings.openRouterApiKey)return"You need to set the OpenRouter API key in the settings.";const options={baseUrl:settings.openRouterURL,apiKey:settings.openRouterApiKey},messages=[];promptOptions?.firstMessage&&messages.push(promptOptions.firstMessage),messages.push({role:"user",content:content});const model=isEmpty(settings.defaultModel)?defaultModel:settings.defaultModel;logWrite({type:"prompt",args:content},`The model is ${model}`);const filenames=toolJavascriptFilenames(!1);let tools=[];promptOptions?.ignoreTools||(logStart({type:"load_tools",args:filenames}),tools=await loadTools(filenames),logEnd("load_tools"));const request={model:model,tools:tools,messages:messages};try{const response=await completion(request,options);return logWrite({type:"completion_response",args:response}),logWrite({type:"message",args:response?.choices[0].message}),response?.choices[0].message.content}catch(e){return friendlyError(`${e}`,settings)}}function friendlyError(e,settings){return e.startsWith("Error: No endpoints found that support tool use")?`The model "${settings.defaultModel}" does not support tool use. Please select a different model (A good default is ${defaultModel}).`:e.startsWith("Error: No auth credentials found")?"The OpenRouter API key is invalid. Please check your account at https://openrouter.ai and get a new key.":e}
@@ -1 +1 @@
1
- export async function searchGutenbergBooks(e){const t=e.join(" "),o=await fetch(`https://gutendex.com/books?search=${t}`);return(await o.json()).results.map((e=>({id:e.id,title:e.title,authors:e.authors})))}export default function tools(){return booksTools}const booksTools=[{type:"function",function:{name:"searchGutenbergBooks",description:"Search for books in the Project Gutenberg library based on specified search terms",parameters:{type:"object",properties:{searchTerms:{type:"array",items:{type:"string"},description:"List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)"}},required:["searchTerms"]}}}];
1
+ export async function searchGutenbergBooks(searchTerms){const searchQuery=searchTerms.join(" "),response=await fetch(`https://gutendex.com/books?search=${searchQuery}`);return(await response.json()).results.map((book=>({id:book.id,title:book.title,authors:book.authors})))}export default function tools(){return booksTools}const booksTools=[{type:"function",function:{name:"searchGutenbergBooks",description:"Search for books in the Project Gutenberg library based on specified search terms",parameters:{type:"object",properties:{searchTerms:{type:"array",items:{type:"string"},description:"List of search terms to find books in the Gutenberg library (e.g. ['dickens', 'great'] to search for books by Dickens with 'great' in the title)"}},required:["searchTerms"]}}}];
package/dist/tools.js CHANGED
@@ -1 +1 @@
1
- import{logWrite,logEnd,logError,logStart}from"./log/log.js";import{getPathWithoutExtension,readAsJSONIfExists}from"./utils/files.js";export async function loadTools(o){const t=[];logWrite({type:"load_tools",args:o},`modulePaths is "${o.join(", ")}"`);for(const n of o)if(logWrite({type:"getTool",args:n}),""!=n){const o=await inspectTool(n);t.push(o)}else logError({type:"getTool",args:"Empty modulePath"});return t}function findMetaData(o){let t=(getPathWithoutExtension(o)+".json").replace(".tools","tools");const n=readAsJSONIfExists(t);if(n)return n;t=t.replace(".test","");const r=readAsJSONIfExists(t);return r&&(r.name=r.name+".test"),r||void 0}async function inspectTool(o){const t={functionNames:[],functionMap:void 0,definition:void 0,name:void 0,path:o,revision:void 0};logStart({type:"load_tool",args:{modulePath:o}},`The modulePath is "${o}"`);try{const n=findMetaData(o);t.revision=n?.revision,t.name=n?.name;const r=o.endsWith(".test.js"),e=r?`?${Math.random()}`:`?${t.revision}`,i=await import(o+e);try{t.functionNames=Object.keys(i),t.functionMap={};for(const o of t.functionNames)logWrite({type:"load_tool_function",args:{foundFunction:o}}),t.functionMap[o]=i[o]}catch(t){throw new Error(`Error loading Map from ${o}: ${t}`)}try{r||(t.definition=getDefinition(o))}catch(t){throw new Error(`Error loading the agent map from ${o}: ${t}`)}return t}catch(t){throw logError({type:"load_tool_error",args:t}),new Error(`load_tool_error ${o}: ${t}`)}finally{logEnd("load_tool"),logWrite({type:"load_tool",args:{result:t}})}}function getDefinition(o){return readAsJSONIfExists(o+".definition.json")}
1
+ import{logWrite,logEnd,logError,logStart}from"./log/log.js";import{getPathWithoutExtension,readAsJSONIfExists}from"./utils/files.js";export async function loadTools(modulePaths){const tools=[];logWrite({type:"load_tools",args:modulePaths},`modulePaths is "${modulePaths.join(", ")}"`);for(const modulePath of modulePaths)if(logWrite({type:"getTool",args:modulePath}),""!=modulePath){const tool=await inspectTool(modulePath);tools.push(tool)}else logError({type:"getTool",args:"Empty modulePath"});return tools}function findMetaData(modulePath){let metaPath=(getPathWithoutExtension(modulePath)+".json").replace(".tools","tools");const meta=readAsJSONIfExists(metaPath);if(meta)return meta;metaPath=metaPath.replace(".test","");const meta2=readAsJSONIfExists(metaPath);return meta2&&(meta2.name=meta2.name+".test"),meta2||void 0}async function inspectTool(modulePath){const result={functionNames:[],functionMap:void 0,definition:void 0,name:void 0,path:modulePath,revision:void 0};logStart({type:"load_tool",args:{modulePath:modulePath}},`The modulePath is "${modulePath}"`);try{const meta=findMetaData(modulePath);result.revision=meta?.revision,result.name=meta?.name;const isTest=modulePath.endsWith(".test.js"),query=isTest?`?${Math.random()}`:`?${result.revision}`,myModule=await import(modulePath+query);try{result.functionNames=Object.keys(myModule),result.functionMap={};for(const func of result.functionNames)logWrite({type:"load_tool_function",args:{foundFunction:func}}),result.functionMap[func]=myModule[func]}catch(e){throw new Error(`Error loading Map from ${modulePath}: ${e}`)}try{isTest||(result.definition=getDefinition(modulePath))}catch(e){throw new Error(`Error loading the agent map from ${modulePath}: ${e}`)}return result}catch(e){throw logError({type:"load_tool_error",args:e}),new Error(`load_tool_error ${modulePath}: ${e}`)}finally{logEnd("load_tool"),logWrite({type:"load_tool",args:{result:result}})}}function getDefinition(modulePath){return readAsJSONIfExists(modulePath+".definition.json")}
@@ -1 +1 @@
1
- import{existsSync,readFileSync}from"fs";export function getPathWithoutExtension(t){const e=t.lastIndexOf(".");return-1===e?t:t.slice(0,e)}export function readAsJSONIfExists(t){if(existsSync(t)){const e=readFileSync(t,"utf-8");return JSON.parse(e)}}
1
+ import{existsSync,readFileSync}from"fs";export function getPathWithoutExtension(path){const lastDotIndex=path.lastIndexOf(".");return-1===lastDotIndex?path:path.slice(0,lastDotIndex)}export function readAsJSONIfExists(path){if(existsSync(path)){const data=readFileSync(path,"utf-8");return JSON.parse(data)}}
@@ -1 +1 @@
1
- import{join}from"path";import{tarskFolder}from"../api/utils.js";import{existsSync,mkdir,mkdirSync,readFileSync,writeFileSync}from"fs";import{decryptString,encryptString}from"../api/encryption.js";export function getJSON(r,t){const e=join(tarskFolder(),r+".json");if(!existsSync(e))return existsSync(tarskFolder())||mkdirSync(tarskFolder(),{recursive:!0}),setJSON(r,t),t;try{const r=readFileSync(e,"utf-8");return JSON.parse(decryptString(r))}catch(e){return setJSON(r,t),t}}export function setJSON(r,t){const e=join(tarskFolder(),r+".json");writeFileSync(e,encryptString(JSON.stringify(t)))}
1
+ import{join}from"path";import{tarskFolder}from"../api/utils.js";import{existsSync,mkdir,mkdirSync,readFileSync,writeFileSync}from"fs";import{decryptString,encryptString}from"../api/encryption.js";export function getJSON(name,defaultValue){const filename=join(tarskFolder(),name+".json");if(!existsSync(filename))return existsSync(tarskFolder())||mkdirSync(tarskFolder(),{recursive:!0}),setJSON(name,defaultValue),defaultValue;try{const data=readFileSync(filename,"utf-8");return JSON.parse(decryptString(data))}catch(e){return setJSON(name,defaultValue),defaultValue}}export function setJSON(name,value){const filename=join(tarskFolder(),name+".json");writeFileSync(filename,encryptString(JSON.stringify(value)))}
@@ -1 +1 @@
1
- export function stripMarkdown(t){return t.split("\n").filter((t=>!t.startsWith("```"))).join("\n").trim()}
1
+ export function stripMarkdown(markdown){return markdown.split("\n").filter((line=>!line.startsWith("```"))).join("\n").trim()}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tarsk",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "author": "WebNative LLC",
5
5
  "description": "Tarsk is a AI tool available at https://tarsk.io",
6
6
  "license": "MIT",